好长时间了,我的umi项目打包速度好慢。不管是平时启动开发模式,还是生产模式打包。测了一下,生产模式每次打包大概要2分钟左右。下决心优化一下。
另外,umi其实在打包加速方面已经开箱即用地帮我们做了很多优化,所以我们即使什么都不做,目前看到的打包速度,已经是umi上了种种优化手段之后的结果了。
这里主要记录一下我尝试的一些主流的、umi默认没有使用的加速手段。
❌多进程打包 —— happypack / thread-loader
webpack对文件的解析和处理默认是单线程的,文件数量很多时,解析和处理文件的时间就会越来越长,打包的速度就会变慢。
而happypack
和thread-loader
都是通过多进程打包来提升webpack打包速度。happypack
目前已经不再维护了,所以更推荐使用thread-loader
。
在umi中更改处理文件的loader需要使用webpack-chain
的api。配置thread-loader
需要把它添加到module.rule.use
数组的第一个。
在此贴一下umi配置thread-loader
的代码:
//config/config.ts
chainWebpack(config, { webpack }) {
config.module
.rule("js")
.use("thread-loader")
.loader("thread-loader")
.before("babel-loader");
config.module
.rule("ts-in-node_modules")
.use("thread-loader")
.loader("thread-loader")
.before("babel-loader");
config.module
.rule("js-in-node_modules")
.use("thread-loader")
.loader("thread-loader")
.before("babel-loader");
}
配置完成后可以通过config.toString()
查看修改后的完整配置。
但是在配置thread-loader
之后,发现对打包速度并没有提升,基本上没变化。查了一下,发现它对加速的loader是有要求的,不允许使用自定义loader的api。
umi中使用的loader是umi封装过的,而不是原装的babel-loader等。这是umi中的部分loader配置:
所以thread-loader
配置之后也没有起到加速效果,多进程打包在umi这里没有走通。
❌externals
我们项目中总是有一些很少更新的、体积又不小的第三方库,比如react / react-dom / lodash等。这些库很少发生更改,但是我们每次打包都要把它们重新构建一遍。这就造成了打包时间的浪费。为了节省这部分时间,我们就要用到webpack的externals
。
externals
配置用于将一些第三方库排除出打包过程,不出现在最终的打包结果中。再通过其他方式引入它们,比如<script>标签引入。
举个栗子:我们可以像这样配置externals
,它的值是一个对象,key是第三方库的名字,value是通过<script>引入的全局变量的名字:
{
//...other webpack config
externals: {
react: "React",
lodash: "_",
"react-dom": "ReactDOM"
},
};
这样,我们就可以把react / react-dom / lodash排除出打包过程,减少webpack需要打包的模块数量,以提升webpack的打包速度。
之后,不要忘记在项目的html中手动引入这些依赖包:
<script src="https://unpkg.com/react@16.14.0/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
<script src="https://raw.githubusercontent.com/lodash/lodash/4.17.21-npm/lodash.min.js"></script>
至此,externals
的配置就OK了。但是实际上,我测了一下,对项目的打包速度提升很有限。可能是我的项目原本的体积比较大。
另外,还有一个问题,就是externals
虽然将这些第三方库排除出了打包过程,参与打包过程的模块是少了。但并不意味着我们需要加载的文件体积减少了。通过<script>引入的文件,依然需要加载。而且通过<script>引入的这些文件,不参与打包,webpack是没有办法对其进行tree shaking的。所以对于支持tree shaking的库要注意,通过<script>引入的文件体积是不是比原来打包的产物体积大很多。
比如antd,支持tree shaking,官方文档里也提到,虽然支持通过<script>标签引入,但不建议这么做。
✔ cache
webpack 5提供了新的特性:cache
。开启cache
之后,webpack会将首次打包的结果持久化到本地文件系统中。在下一次构建时,对于未更新的文件,跳过解析、链接、编译等一系列非常消耗性能的操作,直接复用上一次打包的结果。通过这种方式,大幅度提升打包速度。
在umi项目中,需要手动开启cache
。我的项目是umi v3。通过如下选项开启:
{
//...other umi config
webpack5: {}
}
开启之后,打包快了很多很多。开启之前,每次build大概105s左右;开启之后,大概12s左右。
umi v3默认使用webpack 4打包。如果不想开启webpack 5,不用webpack 5的cache
特性的话,可以考虑通过cache-loader
/ DLL plugin
等在webpack 4中实现缓存。
原文链接:https://juejin.cn/post/7337528205618970650 作者:LiXiang