乐于分享
好东西不私藏

在 Vue 渲染模板时,如何保留模板中的 HTML 注释?

在 Vue 渲染模板时,如何保留模板中的 HTML 注释?

页面上明明写了这段:

<!-- cms:block=user-card -->

本地跑 dev 能看到,打完生产包就没了。

这种问题我一般不先怀疑浏览器,也不先怀疑 Nginx。HTML 注释这种东西,八成是在模板编译阶段被处理掉了。Vue 官方这个配置就叫 compilerOptions.comments,默认是 false,生产环境会移除模板里的 HTML 注释;打开后才会强制保留,开发环境本来就会保留。

这个坑不大,但很烦。

因为大部分人写注释,是给自己看的:

<!-- 这里后面要改 -->

这种丢了没事。

但有些注释不是“注释”,它是协议。比如 CMS 靠它切块,老系统靠它做 SSI,邮件模板靠它塞条件标记,甚至有些埋点工具会扫 DOM 里的 comment node。

这时候生产包把它干掉,页面不一定报错,接口也不一定报错,就是某块内容不渲染了。你看控制台干干净净,才恶心。

在 Vue 3 里,如果你用的是浏览器里运行时编译,也就是那种 full build,配置大概是这样:

const app = Vue.createApp(App)
app.config.compilerOptions.comments = true
app.mount('#app')

但现在项目基本都是 Vite + .vue 单文件组件。这时候别把配置写在 main.ts 里就完事了。

这里我踩过一次。

app.config.compilerOptions 影响的是浏览器里的运行时模板编译。Vue 官方文档也说得很清楚:如果你用的是 runtime-only 加构建工具,编译选项要通过构建工具传给 @vue/compiler-dom,Vite 要走 @vitejs/plugin-vue 的配置。([Vue.js][1])

Vite 里要放在这里:

import vue from'@vitejs/plugin-vue'

exportdefault {
plugins: [
    vue({
template: {
compilerOptions: {
commentstrue
        }
      }
    })
  ]
}

@vitejs/plugin-vue 的配置里,template.compilerOptions 会传给 Vue SFC 模板编译器,这个位置才对。

我通常还会补一个构建后检查。

不是不信配置,是不信后面没人手欠改配置。尤其模板注释这种东西,不在页面上显示,测试同学也不一定能看出来。

项目里可以丢一个 Go 小脚本,专门扫 dist 目录,确认关键注释还在。

package main

import (
"fmt"
"os"
"path/filepath"
"strings"
)

var mustKeep = []string{
"cms:block=user-card",
"cms:block=article-body",
}

funcmain() {
 root := "dist"
 found := make(map[string]bool)

 err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error)error {
if err != nil {
return err
  }
if d.IsDir() {
returnnil
  }

if !strings.HasSuffix(path, ".html") &&
   !strings.HasSuffix(path, ".js") {
returnnil
  }

  b, err := os.ReadFile(path)
if err != nil {
return err
  }

  text := string(b)
for _, mark := range mustKeep {
if strings.Contains(text, "<!--") && strings.Contains(text, mark) {
    found[mark] = true
   }
  }

returnnil
 })

if err != nil {
  fmt.Println("scan dist failed:", err)
  os.Exit(2)
 }

 missing := false
for _, mark := range mustKeep {
if !found[mark] {
   fmt.Println("missing html comment:", mark)
   missing = true
  }
 }

if missing {
  os.Exit(1)
 }

 fmt.Println("html comments checked")
}

然后在构建流水线里加一步:

npm run build
go run ./tools/check_vue_comments.go

这里有个细节,别只扫 index.html

Vue 的注释节点如果在组件模板里,最终可能进 JS 渲染函数,也可能被 SSR 输出到 HTML。你项目是哪种形态,就扫哪种产物。我一般偷懒,.html 和 .js 都扫。

还有一种写法是不用 Vue 模板承载这个注释,直接用运行时插入 comment node:

package main

import (
"fmt"
"html"
)

funcmain() {
 block := "cms:block=user-card"
 fmt.Printf("<!-- %s -->\n", html.EscapeString(block))
}

这个 Go 例子只是说明一个判断:如果这段注释是后端协议、CMS 协议,不一定非要塞进 Vue 模板。前端能少碰就少碰,尤其是那种上线后由别的系统二次解析的东西。

不过如果需求就是“Vue 模板里必须保留”,那就别绕。

Vue 3 + Vite:配 vite.config 里的 template.compilerOptions.comments = true

浏览器运行时编译:配 app.config.compilerOptions.comments = true

然后构建后扫一遍产物。

这个问题最容易误判的地方,是本地开发环境能看到注释。开发环境能看到,不代表生产包还在。要看 dist,要看最终发到服务器上的那份。生产包里还在,才算真的保住了。