大家好呀,这里是果汁,开年一直在忙公司架构升级的事情,写文章的事情就一直搁置了,实在抱歉。相信大家看标题也知道了,没错!我们项目全部用 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 的竞品,我觉得未来可期,虽然现在生态还不完善,但只要社区够活跃,总有一天能创出自己的一片天,让我们期待那一天的到来吧~