SWC编译器实战:提速前端构建的利器与踩坑经验
优化前:卡得不行
上周项目打包时,我盯着终端看了快一分钟,Webpack 还在吭哧吭哧地转圈。本地开发还好,但 CI/CD 流水线直接超时,测试环境部署经常失败。最离谱的是,一个中等规模的 React 项目,npm run build 要跑 5 秒多,HMR(热更新)改一行代码也要等 2 秒才能看到效果。同事都开始调侃:“你这刷新速度,比我泡面还慢。”
其实我们早就知道 Babel 是性能瓶颈——项目里用了大量 TypeScript、JSX、装饰器,还有几个大型 UI 库。Babel 插件链一长,编译时间就爆炸。试过缓存、多进程,但提升有限。直到某天刷 GitHub Trending,看到 SWC 的 star 数蹭蹭涨,心想:要不试试?
找到瓶颈了!
先别急着换工具,得确认是不是真问题。我用 speed-measure-webpack-plugin 打了下包:
SMP ⏱
General output time took 5.23 secs
Plugins:
TerserPlugin took 1.82 secs
MiniCssExtractPlugin took 0.45 secs
Loaders:
babel-loader, and
ts-loader took 3.91 secs (avg 3.91 secs)
好家伙,光 loader 就占了 75% 时间,其中 Babel 是主力。再用 Webpack 的内置分析:--profile --json > stats.json,丢进 Webpack Analyse 看,90% 的模块处理时间花在 JS/TS 转译上。基本可以确定:换掉 Babel,能救。
SWC 上手:没想象中难
SWC 宣称比 Babel 快 20 倍,Rust 写的,听起来很香。但集成到现有项目会不会翻车?我先搭了个最小 demo 验证可行性。
安装依赖:
npm install -D @swc/core @swc/cli
然后写个 .swcrc 配置(重点来了,这里我踩过坑):
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true,
"decorators": true
},
"transform": {
"react": {
"runtime": "automatic"
}
},
"target": "es2022"
},
"module": {
"type": "es6"
}
}
注意三点:
- 如果用了装饰器(比如 MobX),
decorators: true必须开,否则直接报错 - React 17+ 要配
runtime: "automatic",不然 JSX 转译会漏掉import {jsx as _jsx}导致运行时错误 - target 别设太高,ES2022 在老浏览器可能有问题,我们项目用 ES2020 兼容性刚好
跑个命令试试:npx swc src -d dist,几秒就完事,比 Babel 快多了。但这是 CLI,怎么塞进 Webpack?
核心代码就这几行
关键在替换 Webpack 的 loader。把原来的 babel-loader 换成 swc-loader:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /.[jt]sx?$/,
exclude: /node_modules/,
use: {
loader: 'swc-loader',
options: {
jsc: {
parser: {
syntax: 'typescript',
tsx: true,
decorators: true,
},
transform: {
react: {
runtime: 'automatic',
},
},
target: 'es2020',
},
},
},
},
],
},
};
注意:配置结构和 .swcrc 一样,但嵌套在 options.jsc 下。我一开始漏了 jsc 这层,结果 parser 配置没生效,TypeScript 报了一堆语法错误。
另外,exclude: /node_modules/ 一定要保留!虽然 SWC 快,但 node_modules 里有些包已经是编译好的,没必要再转一次,还能省几百毫秒。
踩坑提醒:这三点一定注意
折腾半天发现,SWC 不是万能的,有三个坑得绕开:
- 插件生态弱:Babel 有几千个插件,SWC 只有核心功能。比如我们用了
@babel/plugin-proposal-class-properties,SWC 默认支持,但像lodash的 tree-shaking 优化,就得靠 Webpack 本身,SWC 不管这事。 - Source Map 有点怪:早期版本 SWC 的 source map 和 Chrome DevTools 对不上,断点位置偏移。升级到 1.3.90+ 后基本正常,但建议打包后手动检查下 sourcemap 是否准确。
- 和 ESLint 冲突:如果用了
eslint-loader,它内部还是调 Babel 解析 AST,会导致重复解析。解决方案是关掉 ESLint 的 parser,或者用thread-loader并行处理,但收益不大,我们直接关了开发时的 ESLint 检查,只在提交前跑。
优化后:流畅多了
改完配置,重新跑 build,终端输出:
Time: 820ms
Built at: 2023-10-05 14:30:22
从 5.2 秒降到 820 毫秒,快了 6 倍多!HMR 也从 2 秒降到 300 毫秒内,改完代码几乎秒出。CI/CD 流水线不再超时,团队效率直接拉满。
附上对比数据(同一台 MacBook Pro M1):
| 指标 | 优化前 (Babel) | 优化后 (SWC) | 提升 |
|---|---|---|---|
| 全量构建 | 5230 ms | 820 ms | 6.4x |
| HMR 更新 | 2100 ms | 280 ms | 7.5x |
| 内存占用 | 1.2 GB | 650 MB | 46% |
内存占用也降了一半,这对 CI 环境特别友好——之前经常因为内存爆掉被 kill,现在稳得很。
不是最优解,但够用了
当然,SWC 也不是银弹。比如我们有个遗留模块用了 Babel 的自定义插件做代码注入,SWC 暂时不支持,只能单独用 Babel 处理那个文件。配置起来有点 ugly,但影响不大:
// webpack.config.js
{
test: /legacy-module.js$/,
use: 'babel-loader' // 仅这个文件走 Babel
},
{
test: /.[jt]sx?$/,
exclude: [/node_modules/, /legacy-module.js$/],
use: 'swc-loader'
}
另外,Vite 用户可能更幸福——它原生支持 SWC,配置更简单。但我们项目是 Webpack 老古董,迁移成本高,所以 SWC + Webpack 是现阶段最平衡的方案。
以上是我的优化经验,有更好的方案欢迎交流
这次 SWC 迁移花了不到一天,收益巨大。如果你的项目还在忍受 Babel 的慢,真心建议试试 SWC。配置不复杂,文档也够用(官网例子很全)。唯一要注意的是别指望它 100% 兼容 Babel,先小范围验证再全量推。
以上是我踩坑后的总结,希望对你有帮助。有更优的实现方式,或者遇到类似问题,欢迎评论区交流!

暂无评论