前言
最近发现公司前端项目打包后生成的单个文件都超过4Mb了,导致页面打开的时候非常慢,于是着手优化打包,目标是实现单个文件大小低于1Mb。
准备
在优化之前我们先提出两个优化思路,如下所示:
1、使用CDN引入包文件
2、使用npm引入的第三方包文件进行拆包
3、将项目文件的公共部分进行拆包,如src/components和src/views文件夹
有了思路之后,接下来我们就开干。注意:下面我是用vue项目做为演示。
使用CDN引入包文件
适用的场景:
公共的框架或者库单独引入,防止nodejs打包引入,如:vue.js、vuex、vue-router和elementui。
实现:
我们可以使用第三方CDN库复制链接放入public/index.html文件中,如下所示 :
虽然我们引入了,但是我们还要配置webpack不要把nodejs引入的包进行打包。
修改vue.config.js文件,如下所示:
configureWebpack: {
name: name,
externals: {
// 包名: '引入名'
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter',
'element-ui': 'Element',
moment: 'moment',
dayjs: 'dayjs',
axios: 'axios',
clipboard: 'ClipboardJS',
echarts: 'echarts',
html2canvas: 'html2canvas',
'js-beautify': 'beautifier',
'js-cookie': 'Cookies',
lodash: '_',
qrcode: 'QRCode',
screenfull: 'screenfull',
'vue-clipboard2': 'VueClipboard',
'vue-i18n': 'VueI18n'
}
上面externals中key是包名,value是引入名,大家按照这个参考设置就好。这样就完成了第1步的操作。
使用npm引入的第三方包文件进行拆包
接下来我们分析一下前端项目打包后的报告,分析文件大小情况,根据这个报告我们来判断是否要分包,如下所示。
修改vue.config.js文件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
configureWebpack: {
name: name,
externals: {
// 包名: '引入名'
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter',
'element-ui': 'Element',
moment: 'moment',
dayjs: 'dayjs',
axios: 'axios',
clipboard: 'ClipboardJS',
echarts: 'echarts',
html2canvas: 'html2canvas',
'js-beautify': 'beautifier',
'js-cookie': 'Cookies',
lodash: '_',
qrcode: 'QRCode',
screenfull: 'screenfull',
'vue-clipboard2': 'VueClipboard',
'vue-i18n': 'VueI18n'
},
resolve: {
alias: {
'@': resolve('src'),
'@@': resolve('src/x7')
}
}
plugins: [
new BundleAnalyzerPlugin()
]
}
修改package.json文件
"scripts": {
"build:report": "vue-cli-service build --report"
},
运行命令:
pnpm run build:report
如下所示,当前文件打包情况:
通过分析可以知道,chunk文件和app文件比较大,我们再看下图表看看能不能把里面大的包拆分出来,如下所示:
通过图表可以看出来,这些包都可以拆分出来,于是我们改下vue.config.js把上面的包全部拆分出来,如下所示:
config.optimization.splitChunks({
chunks: 'all',
minSize: 20000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
automaticNameDelimiter: '\~',
enforceSizeThreshold: 50000,
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 120,
chunks: 'initial' // only package third parties that are initially dependent
},
corejs: {
name: 'chunk-corejs', // split elementUI into a single package
priority: 141, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?core-js(.*)/ // in order to adapt to cnpm
},
graphic: {
name: 'chunk-zrender', // split elementUI into a single package
priority: 142, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?zrender(.*)/ // in order to adapt to cnpm
},
viewerjs: {
name: 'chunk-viewerjs', // split elementUI into a single package
priority: 143, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?viewerjs(.*)/ // in order to adapt to cnpm
},
hotFormulaParser: {
name: 'chunk-hotFormulaParser', // split elementUI into a single package
priority: 144, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?hot-formula-parser(.*)/ // in order to adapt to cnpm
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
priority: 130, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
},
einUI: {
name: 'chunk-einUI', // split elementUI into a single package
priority: 125, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?ein-ui(.*)/ // in order to adapt to cnpm
},
echarts: {
name: 'chunk-echarts', // split elementUI into a single package
priority: 122, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?echarts(.*)/ // in order to adapt to cnpm
},
handsontable: {
name: 'chunk-handsontable', // split elementUI into a single package
priority: 123, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?handsontable(.*)/ // in order to adapt to cnpm
},
codemirror: {
name: 'chunk-codemirror',
test: /[\\/]node_modules[\\/]_?codemirror(.*)/, // in order to adapt to cnpm
minChunks: 1, // minimum common number
priority: 140,
reuseExistingChunk: true
}
}
})
我们把想要拆分的包都放到cacheGroups中,