大家好呀,这里是果汁,开年一直在忙公司架构升级的事情,写文章的事情就一直搁置了,实在抱歉。相信大家看标题也知道了,没错!我们项目全部用 Vite
进行重构了,抛弃了笨重的 webpack
,迎接新时代的开发方式。我把我们重构时遇到的坑,全部记录了下来,回馈社区,希望看过本文的人不要重复踩坑了。
为什么选择 Vite?
看过我之前文章的童鞋应该知道,我解读过 vite1.x
版本的源码,说实话那时候的 vite
更像是一个实验性质的 demo
形态,距离上生产环境还有很大的距离,但是这个项目本身我还是在持续关注的,直到 2021.2.17 ,vite
发布了 2.0.0-release
项目本身也和 Rollup 进行了深度合作,重构了底层代码,引入了插件机制,Vite
也不单单只是为 Vue
服务的了,成为了一个真正意义上的跨框架开发服务器。
看到这些我想是时候了!随着业务越来越多,项目的本地开发效率也越来越低,保存一下代码,webpack
打包更新得等好几秒,实在不能忍。线上打包的速度也越发慢,严重影响迭代的效率!Vite
正好能解决这些痛点,为了能更轻松的面对以后的业务,我们决定用 Vite
重构整个项目。
Vite 采坑记录
然而理想是美好的,现实啪啪啪打了我的脸,因为 Vite
的生态还没起来,大部分问题其实还是需要自己规避,下面列举一些我们项目重构时遇到的比较明显的坑。
Uncaught ReferenceError: require is not defined
问题原因
这个问题应该是出现最多的一个问题了,原因在于 Vite
是完全依靠 ESM
原生能力的,也就是他只认识 import
,因为 Vite
依赖 script
的 module
属性。我们的代码最终都会被送到浏览器里执行,require
是 cjs
的关键词,浏览器环境本身就没定义这个方法,自然就报错了。这里和 webpack
不一样,webpack
把文件送到浏览器之前是会进行预打包的,这时候已经将 require
转换成 浏览器能兼容的方法了。
解决办法
目前没有特别好的办法,如果是自己写的模块里有用 require
关键词的,需要替换成 import
,但如果是第三方模块的话,如果包里面用到了 require
可能就无解了,目前项目中遇到的包包括 react-intl
、bizcharts
等,如果大家项目中也用到了这些,可以尝试找替换包。
顺便一提,
antd
的样式导入不能用css.js
导入,因为里面有用到require
关键词引less
文件,浏览器运行也会出错。
Node 相关方法都无法使用
问题原因
也是因为直接送到浏览器的原因,没有预先做过处理,像 process 、event 这些 node
对象都无法在浏览器里找到定义。
解决办法
可以用社区的兼容浏览器的包进行 polyfill,目前作者项目中主要用到 process 、event,process 可以用 process-es6 做兼容。
import process from 'process-es6/browser.js'
//浏览器里赋值给 window
global.process = process
event 可以通过 events 做兼容,装完就可以了,不需要额外配置。
xxx does not provide an export named 'xxx'
问题原因
大部分第三方包都是 cjs
导出的,也就是只有一个导出口,比如 axios
、jquery
、lodash
等,他们的导出方式类似下面这样。
module.exports = require('./xxx');
显然,这并不能被 Vite
识别,因为 Vite
只支持 ESM
的导出方式,这部分第三方包需要做个兼容。
解决办法
好在官方已经提供了解决办法,参考这次 issue 。viteConfig
里提供了 optimizeDeps
参数,专门来处理这些 cjs
导出的包,使他变为 ESM
导出,像这样。
//viteConfig.js
...
optimizeDeps: {
include: ['axios','jquery','lodash']
},
加完之后,错误消除。
Failed to resolve entry for package 'xxx'
问题原因
部分第三方包在 package.json
里的导出位置是错误的,导致 Vite
查找的时候出现了错误。
解决办法
通过 viteConfig
的 resolve
参数,强制将路径换成正确的地址。
//viteConfig.js
...
resolve: {
alias: [
{
find: 'intl-locales-supported',
replacement: path.resolve('node_modules/intl-locales-supported/src/index.ts')
}
]
}
静态资源目录问题
问题原因
Vite
默认的静态目录是 public
,如果需要定义其他目录就无法生效。
解决办法
通过 viteConfig
的 publicDir
参数,将静态目录修改为你需要的目录。
//viteConfig.js
...
publicDir: 'static',
alias '@' to path.resolve(__dirname, './src') is not working
问题原因
由于 Vite
本身已经用了 @ 去做模块导入工作,如果用 @ 别名当绝对路径去使用会有问题
解决办法
通过多加一个 / 来规避 @ 冲突的问题,具体见这次issue
// vite.config.js
module.exports = {
alias: {
'/@/': path.resolve(__dirname, './src')
}
}
兼容性
Vite
默认是用的浏览器原生的导模块能力,也就意味着,他需要现代浏览器的支持。以下是最低支持的浏览器版本
Chrome >=61
Firefox >=60
Safari >=11
Edge >=16
也就是说,这些版本以下的都是不支持 module
属性的,好在我们项目不需要兼容古老的浏览器,像 IE
各种版本,都不需要支持,这也是为啥我们敢重构的原因之一。
当然,官方也提供了低浏览器版本的解决方案,@vitejs/plugin-legacy,这个插件可以让 Vite
打包的项目在老的浏览器里面运行,主要用 @babel/preset-env
来进行转换,不过用了之后,打包速度会明显变慢,这点看取舍了。
替换建议
如果符合以下几点中的一点,我建议不要替换
- 如果项目的历史包袱比较重,杂七杂八的代码很多,替换带来的成本会很高,而且可能最终会失败。
- 如果对浏览器兼容性要求较高的,比如需要兼容 IE 老版本。
- 目前项目并没有那么大的打包压力,本地开发效率也还行。
- 用了一些特殊的插件,
Vite
找不到同类替代品。
如果你都没有以上的问题,那我觉得 Vite
还是很值得一试的,开发体验确实很棒,响应为毫秒级,感受真正的热更新。打包也从原来 3分钟 ,降到了现在的 50s。
写在最后
Vite
作为 webpack
的竞品,我觉得未来可期,虽然现在生态还不完善,但只要社区够活跃,总有一天能创出自己的一片天,让我们期待那一天的到来吧~