likes
comments
collection
share

umi项目构建加速:多进程 / externals / cache

作者站长头像
站长
· 阅读数 3

 好长时间了,我的umi项目打包速度好慢。不管是平时启动开发模式,还是生产模式打包。测了一下,生产模式每次打包大概要2分钟左右。下决心优化一下。

 另外,umi其实在打包加速方面已经开箱即用地帮我们做了很多优化,所以我们即使什么都不做,目前看到的打包速度,已经是umi上了种种优化手段之后的结果了。

 这里主要记录一下我尝试的一些主流的、umi默认没有使用的加速手段。

❌多进程打包 —— happypack / thread-loader

 webpack对文件的解析和处理默认是单线程的,文件数量很多时,解析和处理文件的时间就会越来越长,打包的速度就会变慢。

 而happypackthread-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项目构建加速:多进程 / externals / cache

 umi中使用的loader是umi封装过的,而不是原装的babel-loader等。这是umi中的部分loader配置:

umi项目构建加速:多进程 / externals / cache

 所以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>标签引入,但不建议这么做。

umi项目构建加速:多进程 / externals / cache

✔ 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中实现缓存。