持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情。
1. 背景
前不久接了一个大屏可视化项目,后端服务不动,前端页面按照新版UI重新开发,由于是在前人的基础上做开发,就没有考虑其他方面,等开发完成,部署上线后,发现首次加载需要很长时间,查看资源大小,发现vendors.js体积过大,达到了1.8M,耗时1.2s左右,虽然甲方没有性能优化的需求,可我实在看不下去了,帮他们优化一下吧。
2. 安装webpack-bundle-analyzer
安装命令:npm install --save-dev webpack-bundle-analyzer或者yarn add -D webpack-bundle-analyzer
3. 使用webpack-bundle-analyzer
由于项目是以前的开发人员用webpack搭建的,找到webpack.prod.conf.js,添加如下代码:
// ...
import WebpackBundleAnalyzer from 'webpack-bundle-analyzer';
// ...
const devWebpackConfig = merge(baseWebpackConfig, {
// ...
plugins: [
// 依赖包大小分析
new WebpackBundleAnalyzer.BundleAnalyzerPlugin()
]
// ...
})
4. 打包项目
运行npm run build命令,浏览器会自动打开如下页面,发现vendors.js包含了整个echarts库及其他三方库。
5. 按需引入echarts
由于项目使用了echarts-for-react和echarts的组合,所以需要按需引入两者,首先按需引入echarts-for-react,然后打开echarts官方文档,按需引入(PS: 项目用的echarts@4.9.0,而官方文档默认是5.x),所以终端会报以下错误:
出现这个问题,第一反应就是找到node_modules文件夹下面的echarts目录,看看有没有对应的文件,如下图
发现并没有core目录,于是怀疑是版本问题,于是查看了package.json,对比echarts的版本:
果然与官方文档的版本不同,于是打开npm官网,查找echarts@4.9.0版本的官网地址,打开官网,点击网站底部的切换旧版本,即为echarts4.x的文档,顺便也把5.x的按需引入记录一下。
5.1 按需引入echarts 5.x
// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from 'echarts/core';
import {
BarChart,
LineChart,
PieChart,
MapChart
// ScatterChart
} from 'echarts/charts';
// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
import {
TitleComponent,
LegendComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
GeoComponent
} from 'echarts/components';
// 标签自动布局,全局过渡动画等特性
import { LabelLayout, UniversalTransition } from 'echarts/features';
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer } from 'echarts/renderers';
// 注册必须的组件
echarts.use([
TitleComponent,
LegendComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
GeoComponent,
LabelLayout,
UniversalTransition,
CanvasRenderer,
BarChart,
LineChart,
PieChart,
MapChart
// ScatterChart
]);
5.2 按需引入echarts-for-reac和echarts 4.x
import ReactEchartsCore from 'echarts-for-react/lib/core';
import echarts from 'echarts/lib/echarts';
// 按需引入图表
import 'echarts/lib/chart/bar'; // 柱状图需要
import 'echarts/lib/chart/line'; // 折线图需要
import 'echarts/lib/chart/lines'; // 多折线图需要
import 'echarts/lib/chart/pie'; // 饼图需要
import 'echarts/lib/chart/map'; // 地图需要
import 'echarts/lib/component/geo'; // 地图需要
import 'echarts/lib/chart/effectScatter'; // 散点图需要
// 按需引入组件
import 'echarts/lib/component/title'; // 标题组件
import 'echarts/lib/component/legend'; // 图例组件
import 'echarts/lib/component/tooltip'; // hover组件
import 'echarts/lib/component/grid'; // 坐标组件
import 'echarts/lib/component/dataZoom'; // 区域缩放组件
import 'echarts/lib/component/polar'; // 极坐标组件
export default class EchartBase extends Component {
render() {
return (
<ReactEchartsCore
echarts={echarts}
option={this.getOption()}
notMerge={true}
lazyUpdate={true}
theme={"theme_name"}
onChartReady={this.onChartReadyCallback}
onEvents={EventsDict}
opts={}
/>
)
}
}
5.3 记录按需引入出现的错误
5.3.1 Uncaught TypeError: Cannot read properties of undefined (reading 'findAxisModel')
解决方法:
// ...
import 'echarts/lib/component/polar';
// ...
5.3.2 Uncaught Error: Component series.effectScatter not exists. Load it first.
解决方法:
// ...
import 'echarts/lib/chart/effectScatter';
// ...
5.3.3 Uncaught Error: Component series.lines not exists. Load it first.
解决方法:
// ...
import 'echarts/lib/chart/lines';
// ...
5.4 按需加载echarts后的效果
可以看到vendors.js由最初的1.8M左右减小到了1.2M左右。
6. @ant-design/icons/lib
注意到vendors.js包含了 antd@3.26.20 UI库,根据官网的说明,ant-design默认开启了tree shaking,上图右边红框里面有一个antd/es模块,只有110KB左右大小,而且里面包含的组件也是项目里面实际引入的,说明是正常的按需加载,但是上图左边红框的@ant-design/icons/lib模块,足足有500KB左右,项目里面根本没有使用ant-design的icon,却把icon全部打包进来了。
查看 antd@3.26.20 官方文档得知3.9.0之后的版本全量引入了所有icon,所以打包体积会显著增加,由于项目使用的版本是3.26.20,所以也存在这个问题。
6.1 方法一:使用webpack-ant-icon-loader@^1.0.8(不推荐)
通过使用 webpack-ant-icon-loader@^1.0.8 将@antd-design/icons/lib/dist的图标文件拆分成独立的chunk,且异步加载后自动注册图标,详细内容可以查看插件的readme,配置如下:
// webpack.base.conf.js
export default function() {
return {
// ...
optimization: {
splitChunks: {
minSize: 10,
minChunks: 1,
chunks: function(chunk) {
// 这里的name 可以参考在使用`webpack-ant-icon-loader`时指定的`chunkName`
return chunk.name !== 'antd-icons';
},
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors'
}
}
},
noEmitOnErrors: true
},
modules: {
rules: [
// ...
{
loader: 'webpack-ant-icon-loader',
enforce: 'pre',
options: {chunkName: 'antd-icons'},
include: [require.resolve('@ant-design/icons/lib/dist')]
}
]
}
// ...
}
}
打包效果如下:
可以看到之前vendors.js里面的@antd-design/icons/lib/dist图标文件,被单独拆分成antd-icons.js,这时vendors.js只有824KB左右了。
6.2 方法二:升级到antd到4.x(推荐)
从 4.0 开始,antd 不再内置 Icon 组件,请使用独立的包
@ant-design/icons。
且评估了升级版本不会带来额外的问题,因此直接升级到 antd@^4.19.5 效果如下:
可以看到vendors.js中的红框部分正是icon图标,vendors.js整体体积减小到了780KB左右。
7. 接下来的事情
- 1.
vendors.js体积还是比较大,一般webpack对超过300KB的文件出产生警告,将继续拆分独立的chunk; - 2. 启动项目的端口固定是
8080,如果该端口被占用,将无法启动,将参考vue-cli修改成搜索没有被占用的端口作为启动端口;