生产环境部署打包优化
Date:
生产环境部署打包优化是前端工程化中的一个重要环节
目录
部署时的打包优化
- 打包结果体积越小越好
- 文件数量优化
- 利用浏览器缓存
1. 分包
在用webpack打包时,如果不做任何配置,打包结果会是一整个文件。在多个chunck时甚至有重复代码。
我们希望进行分包,减少公共代码,降低总包体积,同时充分利用浏览器缓存。
手动分包
- 第三方库/公共模块单独打包
形成manifest.json文件,在打包时,发现已经打包了,就跳过。有点DLL的意味
// webpack.dll.config.js
const webpack = require('webpack')
const path = require('path')
module.exports = {
mode: 'production',
entry: {
lodash: ['lodash'],
jquery: ['jquery'],
},
output: {
filename: 'dll/[name].js',
library: '[name]',
},
plugins: [
new webpack.DllPlugin({
name: '[name]', // 和output.library一致
path: path.resolve(__dirname, 'dll', '[name].manifest.json'),
}),
],
}
- 使用公共模块
在html中手动引入打包的第三方库结果
<script src="dll/lodash.js"></script>
<script src="dll/jquery.js"></script>
在主配置中
// webpack.config.js
const webpack = require('webpack')
module.exports = {
mode: 'development',
plugins: [
new HtmlWebpackPlugin({
template: 'index.html',
}),
new webpack.DllReferencePlugin({
manifest: require('./dll/lodash.manifest.json'),
})
]
}
优点:
- 极大提升构建速度
- 极大缩小包体积
- 充分利用浏览器缓存
缺点:
- 需要自己维护dll目录文件,包括前置的生成、手动的引入等
- 如果第三方库有更新,需要手动更新dll目录文件
- 如果第三方库本身很小,那分包的意义不大
⚠️ DLLPlugin 适用于大型老项目,在现代项目中推荐使用 Webpack 的缓存机制(如 cache: { type: ‘filesystem’ })代替。
自动分包
控制自动分包,需要配置分包策略optimization.splitChunks
// webpack.config.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all', // 所有chunks都进行分包,默认是async,只对异步chunks进行分包
// maxSize: 20000, // 每个chunk的最大体积, 如果超过这个体积,会进行进一步分包,意义不大
// minChunks: 2, // 当模块被2个及以上的chunck引用,才进行分包
// minSize: 10240, // 当模块体积大于10kb时,才进行分包
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
// 这里可以配置 chunks\minChunks\minSize\maxSize等
priority: 10, // 先打包
},
default: {
minChunks: 2,
reuseExistingChunk: true,
priority: -20, // 后打包
},
styles:{ // 提取公共css,要配合mini-css-extract-plugin使用
test: /\.css$/,
minSize: 1024,
minChunks: 2,
}
}
},
},
}
2. 代码压缩
目标:减少代码体积(扰乱代码)
Dead Code Elimination死代码消除
常用工具:
UglifyJS
:因为不支持ES6+语法,所以不推荐Terser
:支持ES6+语法
这里可以在线测试压缩效果 try Terser
- 有的const就会被优化掉,压缩后直接变成所用之处的常量。
- 各种空格、换行符、注释等可以被压缩掉
- 变量名可以被混淆压缩
webpack内置了terser,如果需要配置,可以参考terser-webpack-plugin
// webpack.config.js
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
format: {
comments: false,
},
},
extractComments: false,
}),
],
},
};
CSS压缩 – css-minimizer-webpack-plugin
// webpack.config.js
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
optimization: {
minimize: true,
minimizer: [
new CssMinimizerPlugin(),
],
},
}
3. Tree Shaking
JS Tree Shaking
代码压缩时,可以移除一些无效的代码,Tree Shaking也是干这个事,移除掉模块中没用的导出。
解析代码时,webpack基于ES6的导入导出语法,分析模块的导入导出, 在保证稳定运行的前提下,根据每个模块的每个导出是否被使用来进行 Dead Code 标记
,最后在打包时,代码压缩工具会移除掉这些Dead Code。
对于一些第三方库,commonjs的模块无法进行TreeShaking,考虑找ESM版本的
此外,在package.json中,可以配置sideEffects
,标记哪些模块有副作用,webpack会认为这些模块的导出不能被TreeShaking, 使用需谨慎。
CSS Tree Shaking 本质上是用正则匹配css中的类名,然后移除掉没用到的类名。
purgecss-webpack-plugin
4. 懒加载
这个主要是在开发阶段,在需要的时候再加载模块,让首屏加载的代码体积更小。主要的场景有:
- 路由懒加载
const Home = React.lazy(() => import('./pages/Home'))
- 组件懒加载
const MyComponent = defineAsyncComponent(() => import('./MyComponent.vue'))
小结
通过合理的分包、代码压缩、Tree Shaking 和懒加载等手段,可以显著提升前端应用在生产环境的加载速度和用户体验。
此外还可以结合 HTTP/2、服务端渲染(SSR)、CDN 加速等手段进一步优化部署效果。