vue项目,开发环境和生产环境不一致的问题的解决思路

399 阅读2分钟

📌 核心问题

现象:开发环境正常运行,生产环境出现组件渲染失败、样式丢失等问题

🔍 根本原因

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 中生产环境就会渲染不出来。