SWC编译器实战:提速前端构建的利器与踩坑经验

公孙誉琳 优化 阅读 2,874
赞 16 收藏
二维码
手机扫码查看
反馈

优化前:卡得不行

上周项目打包时,我盯着终端看了快一分钟,Webpack 还在吭哧吭哧地转圈。本地开发还好,但 CI/CD 流水线直接超时,测试环境部署经常失败。最离谱的是,一个中等规模的 React 项目,npm run build 要跑 5 秒多,HMR(热更新)改一行代码也要等 2 秒才能看到效果。同事都开始调侃:“你这刷新速度,比我泡面还慢。”

SWC编译器实战:提速前端构建的利器与踩坑经验

其实我们早就知道 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,先小范围验证再全量推。

以上是我踩坑后的总结,希望对你有帮助。有更优的实现方式,或者遇到类似问题,欢迎评论区交流!

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论