Terser配置实战:前端代码压缩与性能优化技巧
项目初期的技术选型
上个月接手一个老项目重构,前端是纯 React + Webpack 的 SPA,打包后体积快 3MB 了(gzip 前)。用户反馈首屏加载慢,尤其在低端安卓机上直接卡成 PPT。团队评估后决定先从压缩入手——毕竟代码体积大得离谱,连 devtool 都卡顿。
一开始我直接用 Webpack 默认的 TerserPlugin,没改任何配置。结果发现压缩率一般,而且有些 console.log 居然没删干净(后来才知道默认配置只删 production 模式下的 console)。更糟的是,打包时间暴涨到 2 分钟,CI/CD 流水线天天超时。老板问进度,我只能苦笑:“在等电脑跑完”。
最大的坑:压缩率和构建速度的拉扯
折腾的第一步是调 terserOptions。我照着文档把 drop_console 打开,以为能省不少字节:
// webpack.config.js
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
},
},
}),
],
},
};
结果呢?console.log 确实没了,但体积只少了 50KB。更离谱的是,构建时间从 90 秒飙到 150 秒。查了下 Terser 文档才发现,compress 开启后会做 AST 优化,对大型项目特别吃 CPU。我本地 16G 内存的 MacBook 都卡,别提 CI 服务器了。
后来想到个土办法:只删 console.log,不跑完整压缩。翻 GitHub 找到社区方案——用正则替换。但 Webpack 官方不推荐,说可能破坏代码。试了两天,果然在某个异步函数里把 console.error 误删了,导致线上错误监控失效。赶紧回滚。
核心代码就这几行
最后妥协方案是分层压缩:开发环境不压缩,测试环境轻量压缩,生产环境全量压缩。关键配置如下:
// webpack.prod.js
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true, // 多核并行,亲测提速 30%
terserOptions: {
parse: {
// 忽略注释,省点解析时间
comments: false,
},
compress: {
// 只删 console,不搞复杂优化
drop_console: true,
drop_debugger: true,
// 关键!禁用某些耗时优化
reduce_vars: false,
collapse_vars: false,
},
mangle: {
// 保留关键属性名,避免和第三方库冲突
reserved: ['$', 'jQuery', 'ga'],
},
output: {
// 删掉所有注释
comments: false,
},
},
// 跳过已压缩文件(比如 node_modules 里的)
exclude: /node_modules/,
}),
],
},
};
这里注意我踩过好几次坑:reduce_vars 和 collapse_vars 看似能提升压缩率,但在我们的代码库里反而引发变量名冲突(特别是用了大量闭包的旧模块)。关掉后构建时间降回 80 秒,体积只比全开大 20KB——完全值得。
另外 exclude: /node_modules/ 是救命稻草。之前没配这个,Terser 对每个 npm 包都重新压缩,光 lodash 就多花 10 秒。现在直接跳过,CI 时间稳定在 60 秒内。
还有个隐藏雷:source map 的锅
有次上线后用户报错,但 Sentry 里堆栈全是 a.b.c.d()。查了半天发现 Terser 默认生成的 source map 不包含原始变量名。赶紧补配置:
new TerserPlugin({
// ...其他配置
sourceMap: true, // 必须开
terserOptions: {
mangle: {
keep_fnames: true, // 保留函数名
},
},
}),
但 keep_fnames 会让体积增加约 1.5%。权衡后还是开了——总不能让用户问题没法 debug。不过只在 staging 环境开,生产环境关掉(用 Sentry 的 artifact 上传替代)。
回顾与反思
最终效果:生产包从 2.8MB 降到 2.1MB(gzip 后 650KB → 480KB),首屏加载快了 1.2 秒。构建时间控制在可接受范围,团队不用再干等。
做得好的地方:
- 分层配置策略,平衡速度和体积
- 明确禁用高风险压缩选项,避免线上事故
- 通过
exclude规避无效计算
不足之处也很明显:
- 没彻底解决 source map 体积问题,后续考虑用
hidden-source-map+ 单独上传 - 某些动态 require 的模块没被压缩(Webpack 的 splitChunks 配置问题,和 Terser 无关)
- 其实应该先做代码分割,而不是死磕压缩——但项目 deadline 逼得只能先救火
说到底,Terser 不是银弹。它适合处理“已经写好的代码”,但治本还得靠架构优化。不过对于赶工期的项目,合理配置确实能快速见效。
最后叨叨两句
以上是我踩坑后的总结,希望对你有帮助。如果你也在调 Terser,记住:别盲目开所有压缩选项,先 profile 构建时间;生产环境务必测试 source map 是否可用;console 删除用 drop_console 比正则安全一万倍。
有更优的实现方式欢迎评论区交流——比如你们怎么处理第三方库的重复压缩?或者有没有试过 swc 压缩?最近听说它比 Terser 快 10 倍,但还没敢在生产用……

暂无评论