📌 核心问题
现象:开发环境正常运行,生产环境出现组件渲染失败、样式丢失等问题
🔍 根本原因
graph LR
A[环境差异] --> B[Vue构建文件不同]
B --> E[完整编译包template含动态编译]
B --> F[无动态编译]
🛠️ 解决方案:替换编译器
如果项目中或者引用包使用了动态编译,即这种写法
new Vue({
template: '<div>...</div>'
})
如果该生产vue版本没有动态模板编译器,需要进行替换。
查看vue使用的编译工具
可以在node_modules文件夹下找到vue,记住是没有@的vue,之后查看dist
index.js可以看到默认的vue指向,在vue2中也是类似
vue.cjs.js //开发默认使用
vue.cjs.prod.js //生产默认使用
//非运行时构建包括模板编译器
vue.esm-browser.js //esm
vue.esm-browser.prod.js //esm
vue.esm-bundler.js //esm
vue.global.js //umd
vue.global.prod.js //umd
//运行时构建不包括模板编译器
vue.runtime.esm-browser.js
vue.runtime.esm-browser.prod.js
vue.runtime.esm-bundler.js
vue.runtime.global.js
vue.runtime.global.prod.js
替换编译工具
在vite.config.js中通过别名,强制指定使用包含模板编译器的vue。
// vite.config.js
export default {
resolve: {
alias: [{
find: "vue",
replacement: "dist/vue.esm-browser.prod.js"
}]
}
}
不用担心别名会影响到代码,因为别名不是全局替换,它不会修改你的源代码(不会把代码里的 import Vue from 'vue' 改成 import Vue from 'vue/dist/vue.esm-browser.prod.js')。
而是在构建过程中,当工具解析到 vue 时,才会替换 。
而且只有通过 import 或 require 引用 'vue' 的地方会受影响。
弊端
- 问题:浏览器需要实时编译模板字符串为渲染函数,增加主线程负担
- 影响:组件首次渲染时间增加 20%-50%(尤其在低端移动设备更明显
🛠️ (非第三方包)解决方案:使用render函数替换
vue进行预编译的时候会把template 直接编译成render函数,所以在不更换编译器的情况下,使用直接使用render来替代template。
虽然使用render函数可以完美支持,但是没有特殊要求,建议使用单文件组件的写法。
// 改造前(依赖编译器)
new Vue({
template: '<div><child-comp :msg="message"/></div>',
components: { ChildComp },
data: { message: 'Hello' }
})
// 改造后(手动render函数)
new Vue({
render(h) {
return h('div', [
h(ChildComp, { props: { msg: this.message } })
])
},
components: { ChildComp },
data: { message: 'Hello' }
})
❓ 常见问题
Q: 如何检查项目使用的vue构建版本?
A: 在node_modules/vue/package.json中查看module/main字段指向
Q: 为什么ElementUI会受影响?
A: 旧版本ElementUI组件可能包含template选项而非渲染函数,在早期的vue2中,默认入口是完整构建包括模板编译器,但是在vue2.7开始默认入口明确不包含模板编译器。所以elementui 的table组件在 vue2.7 中生产环境就会渲染不出来。