页面上明明写了这段:
<!-- 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: {
comments: true
}
}
})
]
}
@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,要看最终发到服务器上的那份。生产包里还在,才算真的保住了。
夜雨聆风