Vite生产环境踩坑记录,满满的干货,建议收藏!

12,855 阅读6分钟

大家好呀,这里是果汁,开年一直在忙公司架构升级的事情,写文章的事情就一直搁置了,实在抱歉。相信大家看标题也知道了,没错!我们项目全部用 Vite 进行重构了,抛弃了笨重的 webpack ,迎接新时代的开发方式。我把我们重构时遇到的坑,全部记录了下来,回馈社区,希望看过本文的人不要重复踩坑了。

为什么选择 Vite?

看过我之前文章的童鞋应该知道,我解读过 vite1.x 版本的源码,说实话那时候的 vite 更像是一个实验性质的 demo 形态,距离上生产环境还有很大的距离,但是这个项目本身我还是在持续关注的,直到 2021.2.17vite 发布了 2.0.0-release

Xnip2021-03-31_10-29-35.png 项目本身也和 Rollup 进行了深度合作,重构了底层代码,引入了插件机制,Vite 也不单单只是为 Vue 服务的了,成为了一个真正意义上的跨框架开发服务器。

看到这些我想是时候了!随着业务越来越多,项目的本地开发效率也越来越低,保存一下代码,webpack 打包更新得等好几秒,实在不能忍。线上打包的速度也越发慢,严重影响迭代的效率!Vite 正好能解决这些痛点,为了能更轻松的面对以后的业务,我们决定用 Vite 重构整个项目。

Vite 采坑记录

然而理想是美好的,现实啪啪啪打了我的脸,因为 Vite 的生态还没起来,大部分问题其实还是需要自己规避,下面列举一些我们项目重构时遇到的比较明显的坑。

Uncaught ReferenceError: require is not defined

问题原因

这个问题应该是出现最多的一个问题了,原因在于 Vite 是完全依靠 ESM 原生能力的,也就是他只认识 import ,因为 Vite 依赖 scriptmodule 属性。我们的代码最终都会被送到浏览器里执行,requirecjs 的关键词,浏览器环境本身就没定义这个方法,自然就报错了。这里和 webpack 不一样,webpack 把文件送到浏览器之前是会进行预打包的,这时候已经将 require 转换成 浏览器能兼容的方法了。

解决办法

目前没有特别好的办法,如果是自己写的模块里有用 require 关键词的,需要替换成 import ,但如果是第三方模块的话,如果包里面用到了 require 可能就无解了,目前项目中遇到的包包括 react-intlbizcharts等,如果大家项目中也用到了这些,可以尝试找替换包。

顺便一提,antd的样式导入不能用 css.js 导入,因为里面有用到 require 关键词引 less 文件,浏览器运行也会出错。

Node 相关方法都无法使用

问题原因

也是因为直接送到浏览器的原因,没有预先做过处理,像 processevent 这些 node 对象都无法在浏览器里找到定义。

解决办法

可以用社区的兼容浏览器的包进行 polyfill,目前作者项目中主要用到 processeventprocess 可以用 process-es6 做兼容。

import process from 'process-es6/browser.js'
//浏览器里赋值给 window
global.process = process

event 可以通过 events 做兼容,装完就可以了,不需要额外配置。

xxx does not provide an export named 'xxx'

问题原因

大部分第三方包都是 cjs 导出的,也就是只有一个导出口,比如 axiosjquerylodash等,他们的导出方式类似下面这样。

module.exports = require('./xxx');

显然,这并不能被 Vite 识别,因为 Vite 只支持 ESM 的导出方式,这部分第三方包需要做个兼容。

解决办法

好在官方已经提供了解决办法,参考这次 issueviteConfig 里提供了 optimizeDeps 参数,专门来处理这些 cjs 导出的包,使他变为 ESM 导出,像这样。

//viteConfig.js
  ...
  optimizeDeps: {
    include: ['axios','jquery','lodash']
  },

加完之后,错误消除。

Failed to resolve entry for package 'xxx'

问题原因

部分第三方包在 package.json 里的导出位置是错误的,导致 Vite 查找的时候出现了错误。

解决办法

通过 viteConfigresolve 参数,强制将路径换成正确的地址。

//viteConfig.js
...
resolve: {
    alias: [
      {
        find: 'intl-locales-supported',
        replacement: path.resolve('node_modules/intl-locales-supported/src/index.ts')
      }
   ]
 }  

静态资源目录问题

问题原因

Vite 默认的静态目录是 public,如果需要定义其他目录就无法生效。

解决办法

通过 viteConfigpublicDir 参数,将静态目录修改为你需要的目录。

//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 来进行转换,不过用了之后,打包速度会明显变慢,这点看取舍了。

替换建议

如果符合以下几点中的一点,我建议不要替换

  1. 如果项目的历史包袱比较重,杂七杂八的代码很多,替换带来的成本会很高,而且可能最终会失败。
  2. 如果对浏览器兼容性要求较高的,比如需要兼容 IE 老版本。
  3. 目前项目并没有那么大的打包压力,本地开发效率也还行。
  4. 用了一些特殊的插件,Vite 找不到同类替代品。

如果你都没有以上的问题,那我觉得 Vite 还是很值得一试的,开发体验确实很棒,响应为毫秒级,感受真正的热更新。打包也从原来 3分钟 ,降到了现在的 50s

写在最后

Vite 作为 webpack 的竞品,我觉得未来可期,虽然现在生态还不完善,但只要社区够活跃,总有一天能创出自己的一片天,让我们期待那一天的到来吧~