记一次 UMI Project 性能优化 - 构建产物篇

2,500 阅读4分钟

相信很多人都有遇到这个问题,为什么 umi 打包完的产物这么大啊?

这里我们以 SaaS 基座 为例,先看一下优化后的结果(同一个电脑同一个网络环境中)。

比对项目原始数据优化后的数据
dist Parsed Size2.14MB1.42 MB
dist Gzip Size710.54 **KB454.78 KB
Git tagrelease-3e2c0ba0release-ed456654

查看产物结构

使用 ANALYZE=1 环境变量来查看 build 之后的产物包结构。

{
 "scripts": {
  "analyze": "cross-env ANALYZE=1 umi build",
 },
}

编译执行完成之后,你可以查看 http://127.0.0.1:8888 包分析页面。可以看到大致如下图所示的页面。

可能第一次看这个页面,不是很明白什么意思,你可以简单的理解,页面上面积越大的库,就是包大小越大的。比如,现在所有的文件都在 umi.js 文件中,然后占体积最大的是 node_modules。

分包

项目默认开启按需加载 dynamicImport,即是否把构建产物进行拆分,在需要的时候下载额外的 JS 再执行。chunks 文件过多,为了便于分析资源加载情况,我们进一步拆包。

在 config/config 中添加按需加载配置:

  • ${chunks}-external 打包 react[-dom] moment antd maiui 常用库
  • vendors-${chunks} 分包集成剩余 node_modules 产物,引用共享模块最小次数 2
  
  chunks: ['hero-saas-external', 'vendors-saas-entry', 'umi'],
  chainWebpack(config) {
    config.optimization.splitChunks({
      automaticNameDelimiter: '.',
      cacheGroups: {
        hero: {
          name: 'hero-saas-external',
          test: /[\/]node_modules[\/](react|react-dom|moment|dayjs|antd|@ant-design|@weimai/maiui)[\/]/,
          chunks: 'all'
        },

        vendor: {
          name: 'vendors-saas-entry',
          test: /[\/]node_modules[\/]/,
          chunks: 'all',
          minSize: 30000,
          minChunks: 2
        },
      },
    });
  }

拆包后图示

产物优化

到这里终于要进入整体了,但是前面的操作都不是无用的,我们应该每个项目都通过上面的方式先分析一下,需要优化的部分。

替换 moment.js

你可以用自定义日期库 day.js 替换 Moment 以优化打包大小。使用 antd-dayjs-webpack-plugin 插件,无需对现有代码做任何修改直接替换成 day.js

umijs 使用 antd-dayjs-webpack-plugin

export default defineConfig({
 chainWebpack(config) {
  config.plugin('antd-dayjs-webpack-plugin')
   .use('antd-dayjs-webpack-plugin')
   .end();
 }
})
moment.jsdayjs
Analyze
File size64.19 KB16.64KB
All Parsed size2.13 MB2.08 MB
All Gzip size700.31 KB686.22 KB

使用 dayjsmoment 产物包,小了 50KB 左右。

关闭国际化 locale

我们项目明确未涉及 i18n 国际化问题,可以选择关闭此插件 @umijs/plugin-locale

export default defineConfig({
 locale: false,
})
locale: {}locale: false
Analyze
All Parsed size2.08 MB2.02 MB
All Gzip size686.22KB668.57 KB

关闭 locale 带来的收益是 60KB 左右。

如果你发现某一个较大的依赖包,你没有在项目中使用,那就是第三方依赖库中有使用到了,可以简单的翻一下 yarn.lock 文件,就可以发现它们的依赖关系。

react-color 是谁引入?

我们的目光接下来放到 vendors-saas-entry.js 上,这里面都是共享模块 chunk 2次以上产物。

摸排发现有 reactcss tinycolor2 被打包,源代码正则搜索,并未在项目文件中引入。

依赖关系如下:

"@weimai/maiui@^1.7.6":
   dependencies:
    react-color "^2.19.3"

react-color@^2.19.3:
  dependencies:
    reactcss "^1.2.0"
    tinycolor2 "^1.4.1"

到这里可以明确出是 @maiui 出现问题,并没有开启按需引入,赶紧给 @赤敛 提个Bug 或 PR 吧。

如果修复顺利,预计减少 21.37 KB。

移除 ihos

通过源代码搜索,只发现2个文件引入使用。

进一步分析得出使用 srg 封装的 localstorage 模块,我们改写此功能。

- srg.setItem('$$orgHotline', hotline);
+ localstorage.setItem('h5-$$orgHotline', hotline);

预计减少 7.8 KB。

@ant-design/pro-form

ProForm 在原来的 Form 的基础上增加一些语法糖和更多的布局设置,帮助我们快速的开发一个表单,Analyze 分析查看引入大小为 180.41 KB。

搜索源代码有5处引入,都是跟 登录界面相关 Form,界面如下图展示

ProForm 在 antd Form 基础上,增加一些预设行为和多种布局。但对于2个input、Button而言,过于重量,我们可降级替换 antd

预计减少 180.41 KB。 Git log 查看提交记录,@南蛇 后续需进行整改 dev/login-optimize

qs

umi.js36.js 里,都包含 qs/lib 模块。

#umi.js
umi-request
  qs: .node_modules/umi-request/node_modules/qs/lib
    version: 6.11.0
  
#36.js
qs: ./node_modules/qs/lib
  version: 6.10.3

因为版本的不同差异性,多出了 11.2 KB。分析依赖

express:
  dependencies:
    qs "6.10.3"
  
umi-request:
  dependencies:
    qs "^6.9.1"

express 锁依赖了,而 umi-request 向上查询最新依赖。

express 归属于开发依赖,不会构建到 dist 产物里,一旦在页面中有用到 qs,会默认引入 6.10.3 版本,解决方案强制页面引入 qs 版本跟 umi-request 一致即可。

yarn add qs@6.11.0
未锁版本锁版本
Analyze
All Parsed size1.99 MB1.97 MB
All Gzip size653 KB649 KB

rc-* 组件

rc locale 国际化

Analyze 面板分析所得,多次出现重复加载 rc 国际化,es/locale or lib/locale

node_module/maiui 里看到 lib 引入的是 es 目录国际化语义包。antd es目录对应 ES6版本,lib 目标对应 ES5版本。@maiui 并未按照规范引入@赤敛 。

如果修复顺利,预计减少 4.73 KB。

代码重复

hlt jscpd .

使用前端健康度分析工具得知,存在重复模块及组件。@南蛇 @白松

通过 ANALYZE 得知,摒除重复模块,预计减少 10.99 KB. 以上的大小

Tree shaking: sideEffects

Webpack 中的 sideEffects 到底该怎么用? · Issue #41 · kuitos/kuitos.github.io

待续...

继续分析大的依赖包

参考:

zhuanlan.zhihu.com/p/157540425

Optimize umi split chunk - 提供代码分割的最佳实践 · Issue #2063 · umijs/umi

webpack code splitting 解析 · Issue #242 · frontend9/fe9-library