数据可视化大屏设计器开发-umi打包体积优化

数据可视化大屏设计器开发-打包体积优化

开头

本文是数据可视化开始的开发细节第四章。关于项目打包体积优化。
虽然内容似乎不应该按这个顺序产出,不过因为最近的迭代中突然有涉及到这个方面,故就趁这个时机赶紧先记下来。

简单声明
本人只是一个菜鸡,所以并没有什么新的东西,只是把网上碰到的一些点给统一处理了下。

开始

大屏是基于umi进行开发的,关于此库相信大家都不陌生,只需很少的配置即可开始研发。

但是随着时间的推移,项目的代码量越来越大,打包出来的产物也越来越大,这个时候便需要做一些优化配置。

体积优化是在开发1.17版本的时候,首先是上一个版本的打包详情。

然后是当前优化后的打包详情。

本文说得更明白些,应该说是主文件的体积优化,整体的思路:拆分主文件、按需加载、压缩。

umi配置优化

dynamicImport

正常情况下,umi打包只会生成一个umi.js,简单项目这样也很简洁,但是项目大的时候,网络加载速度就会变慢,此时就需要按照逻辑进行拆分。
可以看下官网的按需加载,开启按需加载后,umi就会将项目按模块进行拆分。

targets

根据实际情况,针对项目应用的浏览器版本范围,按需引入polyfill,可以很好的减少产出代码体积。
如果项目只会应用于高版本的浏览器,就可以设置成高版本浏览器的配置,减少polyfill

externals

即是webpackexternals,把一些模块从打包项中直接给去除掉,采用cdn的形式引入。

  • ps
    本来是准备打算将echarts采用cdn形式引入的,奈何还依赖了词云水球组件,删除了echartsnpm后,报错了,故没有做这个选择。

ignoreMomentLocale

大多数情况下,业务项目基本都没有多语言的需求,把moment的语言包给去除。

当然更好的办法是把moment替换成dayjs,毕竟其实平时没有太多时间转换的需求,采用更轻量的库是更好的选择。

splitChunks

根据上面的dynamicImport拆分了模块后,模块当中的第三方引入却被同时打进了不同的模块中,重复打包。

使用webpacksplitChunks配置,将一些比较大的,常用的第三方依赖单独抽离,可以有效减少包体积。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
chunks: ['antdesigns', 'vendors', 'commons', 'umi'],
chainWebpack(config: any) {
config.merge({
optimization: {
minimize: true,
splitChunks: {
chunks: 'all',
minSize: 30000,
minChunks: 1,
automaticNameDelimiter: '.',
cacheGroups: {
antdesigns: {
name: 'antdesigns',
chunks: 'all',
test: /[\\/]node_modules[\\/](antd|@ant-design)/,
priority: 10,
},
echarts: {
name: 'echarts',
chunks: 'async',
test: /[\\/]node_modules[\\/](echarts|zrender)/,
priority: 10,
},
vendors: {
name: 'vendors',
chunks: 'all',
test: /[\\/]node_modules[\\/](lodash|moment|react|dva)/,
priority: 10,
},
commons: {
name: 'commons',
// 其余同步加载包
chunks: 'all',
minChunks: 2,
priority: 1,
enforce: true,
},
},
},
});
}
},
}
注意的地方

splitChunks中还有几个需要注意的地方。

  • priority
    拆分的优先级,当一个包同时被多个cacheGroups中的test匹配上时,会将包priority最高的那个cacheGroups中。
  • minSize
    包被压缩前的体积超过minSize才会被拆包。
  • chunks(个人理解)
    umi配置中的chunks,表示预先需要加载的cacheGroups,比如上面的echarts模块不需要一开始就加载,则不需要添加到chunks中。

按需加载

这里说的按需加载,说的是代码的按需加载。
比如在加载首页的时候,我们不需要加载个人中心的页面代码,这样可以大大加快首页加载的速度。

此时就可以用到React的语法来达到这个效果(其实完全可以使用umidynamic,但是不不知道为啥报错了)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React, { lazy, Suspense } from 'react'

// 一个比较大的组件
const HugeComponent = lazy(() => {
return import(/* webpackChunkName: "Chunk_Name" */ './path/to/component')
})

const App = () => {

return (
<Suspense fallback={<div>loading...</div>}>
<HugeComponent />
</Suspense>
)

}

按需加载组件,只有使用到组件的时候才进行加载,lazy支持一个异步函数,返回一个组件,Suspense组件的children为一些懒加载的组件,在未加载完成时,会显示fallback的加载内容。

大屏设计器当中有非常多的依赖,且体积巨大,通过此方法,实现了一个非常不错的效果。
比如经常使用的代码编辑器monaco-editor
还有每一个图表组件,默认都不进行加载,只有当拖拽到画布当中时,才会真正去加载图表。

其他优化

gzip

之前的优化效果虽然显著,但是当开启了gzip之后,给项目最后的效果来了一个质的提升。

这是压缩前和压缩后的两个对比,效果非常明显。

  • 安装依赖
    yarn add compression-webpack-plugin@5.0.1 -D
    为什么安装这个版本
    项目使用的是umi3,而插件的最新版本是10.0.0,打包发现报错Cannot read properties of undefined (reading ‘tapPromise‘)
    大概率是webpack版本不匹配,查看插件package.json发现其依赖的webpack版本为5
    故选择了插件5.0.1版本(webpack可为4)。

  • 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import CompressionPlugin from 'compression-webpack-plugin';
const config = {
chainWebpack(config: any) {
// 生产环境配置
if (REACT_APP_ENV === 'prod') {
config.plugin('compression-webpack-plugin').use(CompressionPlugin, [
{
test: /\.(js|css|html)$/i, // 匹配
threshold: 102400, // 超过10k的文件压缩
deleteOriginalAssets: false, // 不删除源文件
},
]);
}
},
}
  • nginx配置
    当然只完成打包还不够,需要服务端也支持gzip
    只需要简单的在nginx配置当中添加如下配置,重启,即可。
1
gzip_static on;

剩余待优化

组件优化

现在各个图表组件的配置渲染已完成按需加载,但是每个组件的默认配置数据仍然是同步全量加载。
因为代码逻辑原因可能需要一番大修改,故在之后完善。

图片优化

图片现在也是全量加载,待优化。

依赖包替换

有相当多的依赖包只是简单使用,但占用体积巨大,考虑使用同功能的小包进行替换。

结束

结束🔚。

顺便在下面附上相关的链接。

试用地址
试用账号
静态版试用地址
操作文档
代码地址

参考链接

https://juejin.cn/post/7081453829375393823
https://blog.csdn.net/moozixiao/article/details/115791524
https://juejin.cn/post/7103831294013865992
https://juejin.cn/post/7155652261660590116
https://juejin.cn/post/6844903728374546445
https://juejin.cn/post/6844904183917871117