目标和环境
最近,迫于原本的vue-cli构建速度越来越慢,每次修改代码要等很久才能看到效果,已经严重了影响了开发效率,遂决定优化项目的构建机制,也体验一把不到1s的飞速快感。
项目采用vue2 + antdv1 + vue-cli的B端项目,目标是改造成dev环境下同时支持vite和webpack,生产环境下支持webpack,这里就需要修改代码和配置时做到既能用webpack也能用vite,并且要尽量减少对src目录下的代码修改,保证生产环境不出问题。
改造前后对比:
构建工具 | dev启动耗时 | 热更新 HMR |
---|---|---|
webpack | 51s | 5s |
vite | 17s(无预构建) 600ms(已有预构建) |
500ms |
在dev环境下,vite的效率提升非常明显,生产环境下,两者差距不大,这里不做对比。
改造步骤
在项目根目录下安装vite相关的模块,包括后面会用到的插件,如下所示:
1 | "vite": "^2.8.4", |
创建vite需要的vite.config.js
文件和index.html
文件,并添加对应的配置。
具体配置和踩坑点
require is not defined
Vite开发模式下,完全安装ESM进行构建,无法识别原本在webpack中使用的require语法,针对此问题,有以下方案:
采用import替换
1
2
3
4
5
6
7<img :src="require('./a.png')" />
// 替换为
const a = import('./a.png')
<img :src="a" />采用
@originjs/vite-plugin-commonjs
插件
1 | import { viteCommonjs, esbuildCommonjs } from '@originjs/vite-plugin-commonjs'; |
注意,vite在生产环境下通过commonjsOptions
会默认转换require,此插件只会在dev下生效,建议统一改为import xxx
方案,这种方案在vue cli的webpack中也可兼容。
Unknown theme type: undefined, name: undefined(and-design-vue)
报错如下图:
此问题由于and-design-vue版本过低,部分代码不支持原生ESM,有以下解决方案。
- 升级到ant-design-vue-1.7.8稳定版。
- 配置alias
1
2
3
4
5
6
7resolve: {
// 配置路径别名
alias: [
{find: /ant-design-vue$/,replacement: 'ant-design-vue/dist/antd.min'},
],
},
建议采用第一种,并且全量引入and-design-vue,这种方案在vue cli的webpack中也可兼容。
无法识别.vue文件以及含有jsx语法的.vue文件
报错如下图:
添加如下配置即可解决:1
2
3
4
5
6
7
8
9
10
11
12import { createVuePlugin } from 'vite-plugin-vue2'
...
plugins: [
createVuePlugin({
jsx: true
}),
]
...
resolve: {
extensions: ['.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
},
在对应使用jsx语法的vue文件中,修改:1
2
3
4
5<script>
// 替换为
<script lang="jsx">
注意,为了在vue cli的webpack中也可兼容,需要安装了@vue/babel-preset-jsx
和@vue/babel-helper-vue-jsx-merge-props
‘isMoment’ is not exported by ‘node_modules..
此问题出现在使用ant-design-vue 的1
import * as moment from "moment";
解决方法是使用 vite 的插件 vite-plugin-antdv1-momentjs-resolver,配置如下:1
2
3
4
5import AntdMomentResolver from "vite-plugin-antdv1-momentjs-resolver";
plugins: [
AntdMomentresolver()
],
注意如果使用的cnpm安装的ant-design-vue,则需要传入reg参数:/_ant-design-vue@1.7.8@ant-design-vue\\[\w-\\\/]*\.js$/
process is not defined
在vue cli中,我们会使用process.env来获取环境变量,但是在vite中是无法识别的,我们可以通过vite替换插件,在构建时替换掉,如下配置:1
2
3
4
5
6
7
8
9
10import { replaceCodePlugin } from "vite-plugin-replace";
...
replaceCodePlugin({
replacements: [
{
from: /process.env/g,
to: "import.meta.env",
},
],
}),
这样这种方案在vue cli的webpack中也可兼容。
.env变量
在vue cli的webpack中,会使用到一些变量,例如:1
2
3
4VUE_APP_BUILD_ENV='test'
VUE_APP_BASE_GRAIN_API='/dg-grain-api'
VUE_APP_BASE_GANG_API='/dg-steel-api'
VUE_APP_BASE_USER_API='/dg-user-api'
在vite中,只能使用VITE开头的变量,为了兼容两种方案,可以采用envPrefix
配置,如下所示:
1 | defineConfig({ |
/deep/使用[plugin:vite:css] expected selector.
报错如下图:
在样式中使用了<style lang="scss">
和/deep/
深度选择器时,在vite中会报错,有以下解决方案:
- 将
<style lang="scss">
替换为<style lang="less">
。 - 将
/deep/
替换为::v-deep
。
如果项目中没有使用到less,采用后者更保险,如果替换::v-deep
警告,可以采用:1
2
3:deep(.child) {
color: red;
}
注意,vite默认没有sass
解析器,需要自行安装npm install sass -D
stylus和less全局变量
Inline JavaScript is not enabled. Is it set in your options?
报错如下图:
此问题是在项目中,使用到了stylus或者less全局变量,有以下解决方案:
1 | preprocessorOptions: { |
不支持ESM的第三方库
在项目中,或多或少都会使用到一些第三方依赖包,由于依赖依赖包没有按照 ESM 编写,导致启动或者打包时报错,这种问题是最常见的,在开发环境下可以采用@originjs/vite-plugin-commonjs
转换,但是对于一些变态的写法,也会出现转换失败的情况,例如videojs-contrib-hls.js
,报错如下图:
针对此问题,可以采用Externals方式,如下配置:
1 | import { viteExternalsPlugin } from 'vite-plugin-externals' |
在index.html中引入,如下所示:1
2<script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/6.0.0/video.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-contrib-hls/5.15.0/videojs-contrib-hls.js"></script>
总结
vite在dev下有明显的性能提升,体验是飞速的,但是在浏览器请求页面时,会同时加载大量js文件,这导致在速度上也有一定的牺牲,而webpack在构建上确实会慢很多,并且项目的文件越多越慢,但是一但构建好,在浏览器端体验是要比vite快的。另外vite即便是在生产环境下采用rollup对文件进行打包,但是对于IE的支持还是不好,并且生产打包的速度和webpack基本上一致,总之,如果项目已经很稳定并且很庞大,不建议换vite。