webpack打包优化之分析打包图

开发环境下利用webpack-bundle-analyzer来生成打包依赖图进行分析,进行项目优化

分析问题

1
yarn add webpack-bundle-analyzer -D
1
2
3
4
5
// webpack.dev.conf.js

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

plugins: [new BundleAnalyzerPlugin()]

问题一

优化前,打包了两个echartszrender,分别在两个chunk

问题二

还有就是引入的moment.js偏大,因为引入了其他语言和地区,而这个项目只需要中文区域的

问题三

iview需要打包到vendor里

开始优化

解决问题一

问题一是自己的代码问题,两个相似的组件没有提取成一个公共组件,两次引入了v-charts的图表,而v-charts又依赖于echarts,所以就出现了重复性引用,不过项目也启用CommonsChunkPlugin来分割代码了,按照一般的引入的依赖,都会打包到vendor里,为什么 e-charts 没被打包到 vendor 中呢?

发现是异步组件的问题。

在引用这两个组件的方式上,我使用的是异步组件的方式,而vue的异步组件配合webpack的代码分割使用的话,webpack会将一个异步组件单独打包成一个chunk

这种引入组件的写法,会使得 webpack 打包两个 js 文件,所以因为默认是显示MysqlReport的,可以将其改写为直接引入,RedisReport保持异步引入

1
2
3
4
5
6
7
8
import MysqlReport from './mysqlReport.vue'

export default {
components: {
MysqlReport,
RedisReport: () => import('./RedisReport.vue'),
},
}

echarts 已经被打包到 vendor 里,目的达成

但是为了少写重复性代码,最后我还是将MysqlReportRedisReport进行重构,写成一个单独的组件。

解决问题二

iview所依赖的moment.js,默认引入所有区域,所以多了很多未使用到的代码,可以利用ContextReplacementPlugin来优化。

1
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn/)

解决问题三

将iview打包到vendor.js里,在output的entry字段,设置vendor,将iview添加进去。

1
2
3
4
5
6
output: {
entry: {
index: '../src/index.html',
vendor: ['iview']
}
}

优化结果

最终打包文件的大小,大概有 600KB 的优化


总结

使用异步组件引入的方式引入组件,因为异步组件会被单独打包成一个chunk,所以需要考虑到项目的多个异步组件有没有引入相同的依赖模块,如果有,该依赖模块会被打包多次。

开发的时候可以配置BundleAnalyzer来分析打包文件的结构,进行审查以及进一步优化。

因为vendor.js到后面由于依赖的包比较多,所以体积较大,我也尝试过用Dllplugin去将vendor里的一些固定模块,如vue,echarts,d3,axios,vue-router分离出来,不过最后发现打包出来的dll文件比较大,而vendor.js就小了很多,全部资源的体积比使用Dllplugin之前还大了一倍,但是使用Dllplugin有一个好处就是,当你引入新的外部模块的时候,vendor.dll不会发生改变,有变动的是vendor.js和其他一些相关的文件,所以这个时候就可以利用页面缓存来减少资源的加载时间。

之后可以继续利用异步组件代码分割,也就是路由懒加载来加快首次进入页面的加载速度。之后按需加载资源。