起因:公司基于 Vue2 框架开发的旧项目,经过长期迭代后,项目依赖包日益繁杂,打包体积也不断膨胀。其中,chunk-vendors.**.js 文件即便经过压缩处理,大小仍达到了惊人的 4.33M,这一情况已严重拖慢了首屏加载速度。这里专门记录一下打包优化的具体步骤,以便后续参考复用。

1. 静态资源优化
在前端项目里,静态图片资源是影响首屏加载速度的重要因素。旧项目经过长期迭代,积累了不少静态图片,若处理不当,会显著拖慢加载速度。所以,对静态图片资源进行优化是打包优化中很关键的一步。
image-webpack-loader
是一个用于 Webpack 的图像加载器模块,主要用于压缩和优化 PNG、JPEG、GIF、SVG 和 WEBP 格式的图像文件。该项目的主要编程语言是 JavaScript,适用于前端开发中的图像优化需求。
webpack配置
js
module.exports = {
chainWebpack: config => {
config.module.rule('images')
.test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({
mozjpeg: { progressive: true, quality: 65 },
optipng: { enabled: false },
pngquant: { quality: [0.65, 0.90], speed: 4 },
gifsicle: { interlaced: false }
})
.end()
}
}
优化前体积:

优化后体积:

项目静态图片文件减少了72%
2. 大文件定位
需要明确哪些模块占用了大量空间,定位问题源头
这里使用了 Webpack Bundle Analyzer
可视化工具,用于分析 Webpack 生成的 bundle 文件,帮助开发者优化前端项目的打包体积。
js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
configureWebpack: {
plugins: [
new BundleAnalyzerPlugin()
]
}
}
完成配置后,进行构建命令yarn build
Webpack Bundle Analyzer 会自动启动一个本地服务器,并在浏览器中打开可视化界面。默认地址为 http://127.0.0.1:8888
。

这里可以看到chunk-vendors.**.js
文件几乎占了半壁江山,其次是ts.worker.js
。
先来说说ts.worker.js
。这个是TypeScript 编译器的 Web Worker 脚本文件,且是异步加载方式引入的,优化点不多。
然后是app.**.js
,项目中存在不少体积较大的 SVG 文件与 views 文件。其中,views 文件作为各页面的代码载体,需结合具体业务场景逐步调整优化;而 SVG 文件则具备更直接的优化空间,可优先进行针对性处理。
SVG 文件的优化要点主要有两方面:
- 核查使用状态:长期迭代的项目中,静态资源的更替与删减难免导致部分 SVG 文件闲置。对此,我将通过脚本对项目中所有 SVG 文件进行全面筛查,确认其是否被实际使用。
- 文件体积压缩,即针对体积较大的 SVG 文件,通过压缩处理减小其占用空间。
经过脚本全面筛查,初步检测出 386 个未被引用的 SVG 文件;后续通过人工代码审查,最终确认其中 187 个为未使用文件。对这些文件进行处理后,
app.**.js
文件的体积优化效果显著。后续可根据实际需求,针对体积较大的 SVG 文件的进一步压缩处理。
3.optimization.splitChunks
optimization
配置项是用于优化打包过程和输出结果的核心配置,对于首屏加载优化显著。
经过Webpack Bundle Analyzer
对大文件进行的定位分析,chunk-vendors.**.js
文件中包含多个体积较大的依赖包,针对这一情况,下一步将通过Optimization.splitChunks配置进行分包处理。
js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\/]node_modules[\/]/,
name: 'vendors',
chunks: 'all',
priority: 10,
enforce: true
},
antd: {
test: /[\/]node_modules[\/]ant-design-vue[\/]/,
name: 'antd',
chunks: 'all',
priority: 20
},
element: {
test: /[\/]node_modules[\/]element-ui[\/]/,
name: 'element',
chunks: 'all',
priority: 20
},
monaco: {
test: /[\/]node_modules[\/]monaco-editor[\/]/,
name: 'monaco',
chunks: 'all',
priority: 30
},
maxChart: {
test: /[\/]node_modules[\/]max-charts[\/]/,
name: 'maxChart',
chunks: 'all',
priority: 20
},
antV: {
test: /[\/]node_modules[\/]@antv[\/]/,
name: 'antV',
chunks: 'all',
priority: 20
}
}
}
}
}
综合以上分析,我筛选出五个体积较大的依赖包,并对其进行了分包处理。
需要注意的是splitChunks分包只是"优化打包规则",但无法改变 "代码的引入方式和执行逻辑",如入口内同步写入的文件仍会被打包到chunk文件中。
4.其他优化手段
- 路由懒加载
为所有路由添加 webpackChunkName 注释,使打包更有组织性,确保每个路由组件独立打包,避免嵌套引入导致体积集中。
js
{
path: '/home',
name: 'Home',
// 单独打包为 home.[hash].js
component: () => import(/* webpackChunkName: "home" */ '@/views/Home.vue')
},
- 第三方库通过 CDN 引入
直接在public/index.html
中通过 CDN 引入,免除打包环节
- 启用 Gzip/Brotli 压缩
需要结合服务器配置(例如Nginx配置)
上述优化方案的实施效果同样显著,需要说明的是,其中第二项方案对内网场景下并不适用,其余两项方案已在本项目中采纳实施。
最后是成果展现
- 主包
chunk-vendors.**.js
从 4.33M 缩减至 3.41M,缩减了 0.92M,缩减比例约为 21.2% app.**.js
从 1.22M(约 1249kb)缩减至 678kb,缩减了 571kb,缩减比例约为 45.7%。
总体缩减比例约为 26.7%,这一优化显著降低了首屏加载时的 JS 资源总量,为提升页面加载速度创造了有利条件。
