相信很多人都有遇到这个问题,为什么 umi 打包完的产物这么大啊?
这里我们以 SaaS 基座 为例,先看一下优化后的结果(同一个电脑同一个网络环境中)。
| 比对项目 | 原始数据 | 优化后的数据 |
|---|---|---|
| dist Parsed Size | 2.14MB | 1.42 MB |
| dist Gzip Size | 710.54 **KB | 454.78 KB |
| Git tag | release-3e2c0ba0 | release-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]momentantdmaiui常用库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.js | dayjs | |
|---|---|---|
| Analyze | ||
| File size | 64.19 KB | 16.64KB |
| All Parsed size | 2.13 MB | 2.08 MB |
| All Gzip size | 700.31 KB | 686.22 KB |
使用 dayjs 比 moment 产物包,小了 50KB 左右。
关闭国际化 locale
我们项目明确未涉及 i18n 国际化问题,可以选择关闭此插件 @umijs/plugin-locale
export default defineConfig({
locale: false,
})
locale: {} | locale: false | |
|---|---|---|
| Analyze | ||
| All Parsed size | 2.08 MB | 2.02 MB |
| All Gzip size | 686.22KB | 668.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.js 和 36.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 size | 1.99 MB | 1.97 MB |
| All Gzip size | 653 KB | 649 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