一次 webpack5 项目优化的经历(构建产物从13.8 MB 到 2.12 MB,构建速度提升一倍)

329 阅读5分钟

前些日子,项目在发包的时候失败了,竟然是因为构建产物太大导致的,而我又对这块可以说是完全不了解了,出于好奇心和学习的心态,开始尝试优化一下这个项目,在请教了大佬之后,又在 webpack 官网以及掘金等学习网站查阅了大量资料后,开始上手。

  先启用 webpack-bundle-analyzer 查看打包体积。(这是一个查看构建产物体积树图的插件,非常好用,安装之后在 webpack 的 plugins 下使用)

image.png

一眼看去,体积惊人,而且充斥着大量的 less 代码,首先想到的是应该拆分 css。

于是开始使用 webpack 官方开箱可用的 mini-css-extract-plugin 插件来进行拆分 css。

使用起来也是非常方便,在同样的 webpack 的插件配置里

image.png

(命名规则可查看官方文档)

使用之后,再次运行构建,发现还是13.8 MB,完全没有变化,这就很令人头秃。

image.png

一番搜索之后,原来是忽略了使用这个插件最重要的一步:配置 loader

image.png

学习了官网后,我按图索骥配置了一番,在经历一些挫折(style-loader 和 MiniCssExtractPlugin.loader 不能混用!如果混用会出现报错)之后,终于成功的分离出来了

image.png

image.png

本以为分离的事告一段落,然后随手看了下构建产物的大小

image.png

22 MB.。。我这是整了个负优化吗?不应该呀,确定分离 css 是正确的实践。

点进去查看文件夹体积才发现,css 文件超大

image.png

这显然是不合理的,随便点开一个 css 后看到一行接着一行,这才恍然大悟,原来还需要手动压缩呀(这里还是因为不仔细看官方文档)

image.png

又是一番查看文档

image.png

又是一番 copy(注意,这里的插件是放在优化 optimization 这一栏里),然后再次执行构建

image.png

css 文件体积大幅度减小。

这一套操作下来,体积来到了 12.3 MB,减小是减小了,但是感觉还是和预期相差很大,这个项目的体量不该有这么大的。

于是乎查看构建的 js 文件

image.png

发现 好多文件里都存在一个叫 @tencent/omui/dist 的包(omui 组件库,团队大佬封装的 react 组件库),这显然是重复打包了,又是一番搜索后,锁定到了 webpack 配置中 optization 里的 splitChunks 中

这个配置讲解的文章很多,例如 如何使用 splitChunks 精细控制代码分割 - 掘金 (juejin.cn)
这里配置就可以根据项目来自由配置了,我选择直接先干掉现有的配置,使用默认的

image.png (现有配置)

image.png (官方默认配置)

干掉之后再次构建

image.png

代码体积光速下降到了 2.14 MB,整体上大的改动基本就没了,后续就是针对部分细节进行小的优化

比如左下角两张 png,在项目里完全可以使用 cdn 的形式替代,比如 lodash 的按需加载,或者一些模块采用外部导入 externals,这里就不再过多赘述,根据项目实际情况自行优化

由于项目是服务端渲染的,所以使用到 webpack-manifest-plugin 这个插件,插件会生成一个资源和路径的映射

image.png

css 也很很贴心的自动生成了映射放在构建产物文件夹中,所以这里就不用管。

接下来改一下接入层 view 渲染的 ejs 模板就好,在 ejs 里引入上传好的 main.css 样式就可以了。

然后在测试环境先看看优化后的提升,这里随便打开一个页面来对比分离前后的变化

image.png

image.png

可以看到,未分离的资源加载是只有 js 文件,没有 css,大小在 3.9 MB

下面打开分离后的资源加载

image.png

image.png

可以看到,分离后的资源加载 css + js 大小是3.5 MB,也比分离前的要小,而且切换页面更有种“按需加载”的酸爽感

但是只有0.4 MB的优化,并不能达到预期呀。

当我点开这些加载的 css 文件发现,每个 css 文件里竟然都有大量重复的样式代码,看来是重复打包,观察到样式来源都是 mixin 的样式

image.png

后续解决方案是给这些 mixin 样式加上括号(如图最上方的样式)就可以避免重复打包的问题

image.png (原理如图所示)

再次构建。

image.png

css 构建产物只剩 558 KB!大大减少资源的使用

image.png

后续还有一些小改动,比如 放弃使用 awesome-typescript-loader(已经不维护了,而且不够统一) ,直接使用 babel-loader 来打包 ts 文件

使用 fork-ts-checker-webpack-plugin 来单独进行 ts 校验,加快构建速度

开启 webpack5 的 cache,构建速度有了缓存之后大幅度提升

 cache: {
      type: 'filesystem',
      buildDependencies: {
        config: [
          __filename,
        ],
      },
    },

(基于文件系统的缓存配置)

到这里,这波构建优化基本就算完成了,构建产物也从13.8 MB 优化到了 2.12 MB.

构建速度也有大幅度提升

中间还和大佬讨论了一波“拆分 css 会不会对模块联邦造成影响”的问题,后来经过测试,是不会有影响的,模块联邦导出的组件会带有打包的样式。

最后,这次优化操作都是些很常规的操作,在很多优化教程和文档里都有提到, 但是涉及到的一些细节还是值得注意的,比如到现在我也不太明白为什么这个项目离原有的 splitChunks 配置会引起 omui 重复打包那么多次的问题,以及自己尝试独特配置这个的时候,打包没问题,但是页面会出现白屏的问题,后续也会再研究研究相关配置,splitChunks 还是很香的。。