Skip to content

Vue / Nuxt 源码里的注释能删吗

Vue / Nuxt 在服务端渲染(SSR)时插入的 <!--[--><!--]--> 注释是 hydration(水合)所需的锚点标记,删除会导致应用崩溃;它们对性能几乎无影响,无需清除。

打开一个 Vue 或 Nuxt 应用的页面源码,常能看到成对出现、内部只有一个方括号的 HTML 注释:

html
<!--[-->
  ...一些元素...
<!--]-->

一个页面里这样的成对注释可能有几百上千个。有时仅落地页就能搜到近 150<!--[-->,闭合标记数量也几乎相同(149 个)。

于是很自然会产生疑问:更多的元素意味着更多的字节(KB / bytes),这些注释是不是可以删掉来优化性能?是 Vue / Nuxt 加进去的,还是某个组件写得不好留下的?

结论:这些注释是必需的,它们来自基于 SSR 的渲染机制,删掉会让应用可能直接崩溃。下面拆解原因与所谓的「替代方案」。

SSR 与 Fragment 组件

这些方括号注释出现的典型场景之一,是多根组件(multi-root component,也叫 fragment component)

即组件模板不再只有一个根元素,而是有多个并列根节点。

vue
<!-- FragmentComponent.vue:多根组件 -->
<template>
  <button>Click</button>
  <p>Some text</p>
</template>

多根组件是 Vue 3 引入的能力。在 Vue 2 中,组件必须有单一根元素,多根需要借助插件才能实现;Vue 3 将其内置到核心中。

在 SSR 输出里循环渲染这类组件(比如渲染 100 个),每个组件实例外层就会包裹一对方括号注释。

Vue 单文件组件 Playground(play.vuejs.org)提供的 SSR 预览可以直接观察到这一现象。

这对注释本质上是一个 定界符(delimiter):它告诉 Vue「从这里开始、到这里结束的元素属于同一个组件(或片段)」。

这样做的价值在于让 hydration(水合,即客户端接管服务端已渲染 DOM 的过程) 更简单、更可靠:

  • Vue 无需在整个 DOM 里做多余的搜索,就能知道一个组件的边界在哪;
  • 避免在多根结构下把节点归属判断错误,减少潜在 bug。

除了多根组件,v-for 循环、slot 插槽等场景同样以 fragment 模式(fragment mode) 渲染,因此也会带上这对起止标记。

也就是说,凡是「一段没有单一包裹元素的节点集合」,Vue 都需要注释来划定范围。

html
<!-- v-for 渲染的列表同样带定界注释 -->
<!--[-->
  <div>item 1</div>
  <div>item 2</div>
<!--]-->

包一层 div 反而更差

一个直觉性的「优化」想法是:既然多根组件才产生注释,那把 fragment 组件改成单根组件不就行了?例如外层套一个 div

vue
<!-- 把多根改成单根,注释消失了 -->
<template>
  <div>
    <button>Click</button>
    <p>Some text</p>
  </div>
</template>

注释确实没了,但这并不是更好的方案

方案代价
保留多根组件(带注释)多两个注释节点(几乎无成本)
包一层 div(去掉注释)多一个真实 DOM 元素

div 是一个真实的 DOM 元素。当组件被渲染几百上千次时,就意味着页面上多出几百上千个不必要的真实元素

比注释的负担更重。更糟的是,它可能破坏依赖结构层级的样式:原本 p 是父级的直接子元素,套上 div 后就变成了「孙级」,CSS 选择器可能因此失效。

因此反而鼓励使用 fragment 组件,以避免这些多余的 div 或其他包裹型 DOM 元素。

性能影响几乎可以忽略

关于「注释增加文件体积」的担忧,答案是「是,也不是」:

  • 看原始文件大小(raw size):注释确实占字节;但 div 元素同样占字节,甚至更多,所以这个对比并不成立。
  • 看实际传输:现代 Web 普遍启用 gzip / Brotli 压缩。大量重复的相同注释会被压缩算法合并为极小的表示,最终增量微不足道

换言之,这些注释不会真正拖累站点性能,反而是让应用正确工作所必需的。

实操清单

  1. 看到 <!--[--> / <!--]--> 不要惊慌,它们是 Vue SSR 的正常产物,不是 bug。
  2. 绝对不要写脚本去删除 HTML 里的「多余注释」 很可能之前就已经悄悄搞坏了你的应用。
  3. 关闭 CI/构建流程中会「美化 / 压缩 / 格式化」HTML 的自动步骤(尤其针对 Nuxt 应用),这类 auto-minify、prettify 可能误删定界注释。
  4. 优先使用多根(fragment)组件,而不是为了消除注释去套一层 div
  5. 依赖 gzip / Brotli 压缩处理传输体积,无需为注释数量做手动优化。
  6. 理解注释出现的场景:多根组件、v-forslot 等 fragment 模式都会产生。

注意事项

场景说明与建议
手动删注释「优化性能」会破坏 hydration 的定界逻辑,导致客户端接管失败、应用崩溃。
HTML 自动 minify / prettify部分工具会移除注释节点,对 SSR 应用是隐患,建议关闭。
div 换掉 fragment 组件引入真实 DOM 元素,数量放大后拖累渲染,还可能打乱 CSS 层级。
纠结原始文件大小应以压缩后传输体积为准,注释在 gzip/Brotli 下增量极小。
误以为是自己组件的问题这是 Vue 核心 SSR 机制,与你的组件写法无关。

核心结论:带方括号的 HTML 注释是 Vue(以及基于它的 Nuxt)在 SSR 场景下用于标记组件 / 片段边界、辅助 hydration 的必要机制。它们既不伤性能,也删不得。下次再看到它们,你甚至可以把它当作调试线索。