Agent Developer Roadmap
构建工具

SWC:Rust 编译器在构建链路中的转换边界

核验日期:2026-07-09。示例版本来自 examples/build-tools/package.json@swc/core 1.15.43、@swc/cli 0.8.1。本文以 @swc/core 1.x 当前稳定线为基准,重点说明编译转换、宿主集成、Wasm plugin 兼容和类型检查边界。

需要掌握的问题

主题读者必须回答的问题原理与边界高频错误代码或观察证据来源
定位与职责SWC 在工具链里负责哪一段?SWC 是 Rust 实现的 JavaScript/TypeScript 编译器,核心链路是 parser → AST → transform → fixer/hygiene → codegen/minifier;它常被上层工具作为转换内核把 SWC 当完整应用打包器、开发服务器或类型检查器共享示例只生成 .js.mapSWC Getting Started
parser 与 ASTjsc.parser 决定哪些语法能进 AST?parser 根据 syntaxtsx/jsxdynamicImport 等选项解析源码;不能解析就不会进入 transformTypeScript/JSX 配置错线导致语法错误swc.config.json 的 TypeScript parserCompilation
transform、fixer、hygieneAST 改写后为什么还需要修复和作用域处理?transform 改 AST;hygiene 处理标识符作用域;fixer 修正语法细节;最后 codegen 打印 JS自定义 Wasm plugin 生成非法 AST 或作用域冲突pipeline Mermaid 和插件边界Implementing a plugin
codegen 与 minifierSWC 如何生成代码和压缩?codegen 把 AST 输出 JS 与 Source Map;minifier 是独立配置,可处理压缩和 mangle以为 jsc.target 会自动 minify;压缩后函数名/错误栈变化.swcrc minify、source map 验证Minification
jsc.targetenv.targets语法 target 和环境组合有什么区别?jsc.target 控制语法输出目标;env.targets 可接 Browserslist,并可配合 core-js 处理部分 polyfill 策略target 当 polyfill;Browserslist 路径不对导致本地/CI 输出不同示例 jsc.target: "es2022",不启用 envSupported Browsers
TS/JSX/ReactSWC 处理 TypeScript、JSX 和 React 到什么程度?parser/transform 可以处理 TS/JSX/React 语法和 runtime 选项;类型证明仍属于 TypeScript 工具链@swc/core 构建通过就删掉 tsc --noEmitcatalog.ts 类型删除但不做类型检查Compilation options
modulesmodule.type 改变什么?SWC 可把模块语法保留为 ES6,或转换为 CommonJS、UMD、AMD;默认模块语句不一定按预期改写把 ESM 转 CJS 后交给打包器,Tree Shaking 变差共享示例 module.type: "es6"Modules
宿主工具分工SWC 如何进入 Next.js、Rspack、Jest、loader 等宿主?宿主决定文件图、缓存、watch、HMR、CSS、HTML 和类型检查;SWC 只负责被调用的转换段在 SWC 配置里找不到 bundling/HMR 选项就误改上层工具边界表和故障定位表@swc/core
native binary 与缓存Rust native binding 带来什么运维边界?@swc/core 使用平台相关 native 包;缓存键应包含 SWC 版本、配置、Node、平台和宿主选项CI 平台包缺失、跨平台缓存复用、升级后旧缓存命中版本和缓存键清单@swc/cli
Wasm plugin ABI/AST 兼容1.15 对 Wasm plugin 做了什么重大变化?1.15 起 Wasm plugin 在 @swc/core 版本之间具备一定兼容性;通过自描述序列化和可扩展 enum 降低 AST 变化带来的 break以为所有旧插件永久兼容;插件没处理 Unknown AST variantWasm plugin compatibility 文档Compatibility for wasm plugin
Source Map 与严重问题怎样证明转换可追溯,而不是只看 CLI 退出 0?CLI 输出 JS 与 .map;map 要指回 .ts,不能泄露不必要路径map 链断、发布源码泄露、配置路径错artifact test 检查 sourcesmappingsConfiguring SWC

内容边界说明:

分类本文落点
编程语言与类型系统覆盖 TS/JSX/React 语法解析、类型删除、模块输出和类型检查边界;不重复教学 TypeScript 类型系统
Browser APIs 与持久化能力只覆盖 ESM、dynamic import、Source Map 和运行时 API polyfill 边界;不讨论 IndexedDB、Storage 或权限 API
UI 框架与元框架说明 SWC 作为 React/Next/Rspack 等宿主转换内核的接口;组件调度、渲染、水合不在本文重复
构建工具与运行时覆盖 parser、transform、codegen、minifier、配置、缓存、宿主接口、产物和故障定位
后端、数据与 Agent 技术只覆盖 native binary、Wasm plugin、构建配置以开发者权限执行和 CI 平台边界;请求生命周期、数据库一致性和 Agent 评测不适用

SWC 的主问题:快的编译段,不是完整应用工具链

SWC 适合替换“把 JS/TS/JSX 变成目标 JS”的那一段。它经常被 Next.js、Rspack、Jest、loader 或自研脚本调用,但宿主仍然负责文件图、CSS、HTML、HMR、缓存策略和类型检查。

和相邻工具的边界:

工具负责不负责
SWC CLI/core单文件或目录转换、语法目标、模块格式、Source Map、minify浏览器 bundle、CSS/HTML、异步 chunk、HMR
Rspack/Next/Jest调用 SWC 并管理文件图、缓存、运行时SWC 内部 AST 兼容策略
esbuild转换和打包都覆盖一部分SWC Wasm plugin、Babel 兼容插件生态
TypeScript tsc类型检查、声明文件高速 JS 转换

严重问题完整流程:

症状根因观察命令修正
dist/swc 没有 index.html 或 CSSSWC 示例只做转换find examples/build-tools/dist/swc -maxdepth 1 -type f后接 bundler 或发布原生 ESM
构建通过但类型错SWC 删除类型,不做类型证明单独运行 tsc --noEmit类型检查保留在 CI
JSX/TSX 解析失败jsc.parser 没启用对应语法缩小到单个 .tsx fixture配置 syntax: "typescript"tsx: true 等选项

parser 与 AST:配置错了,后面都没有机会修

共享示例的配置很小:

{
  "$schema": "https://swc.rs/schema.json",
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "dynamicImport": true
    },
    "target": "es2022"
  },
  "module": {
    "type": "es6"
  },
  "sourceMaps": true
}

jsc.parser 是入口门禁:

选项作用错误表现
syntax: "typescript"允许 TS 类型语法Unexpected token 或类型标注无法解析
tsx: true允许 TSX.tsx 中 JSX 报错
jsx: trueECMAScript parser 下允许 JSXJSX 被当成小于号表达式
dynamicImport: true允许 import()动态导入语法错误
decorators允许装饰器语法decorator 报错或语义不符

错误完整流程:

症状根因观察命令修正
.ts 里类型标注报错parser 仍按 ECMAScript 解析swc src/file.ts --config-file configs/swc.config.json设置 jsc.parser.syntax: "typescript"
dynamic import 报错parser 没启用 dynamic import最小 import('./x') fixturedynamicImport: true
本地可用 CI 不可用CI 读取了另一份 .swcrc 或 cwd 不同打印 CLI --config-file 路径脚本显式传 --config-file

transform、hygiene、fixer、codegen:AST 改写后要回到合法 JS

SWC 的 transform 不是字符串替换。Rust pass 读取 AST、改写节点,再由 hygiene/fixer/codegen 保证输出能运行。

一个 Wasm plugin 的心智模型:

use swc_core::ecma::{
    ast::Program,
    visit::{visit_mut_pass, VisitMut, VisitMutWith},
};

struct Rename;

impl VisitMut for Rename {
    fn visit_mut_program(&mut self, program: &mut Program) {
        program.visit_mut_children_with(self);
    }
}

pub fn plugin() -> impl Pass {
    visit_mut_pass(Rename)
}

边界表:

阶段输入输出常见问题
parser源码 + parser optionsAST语法选项错
transformAST + transform options/plugin新 AST插件生成非法 AST
hygieneAST作用域安全的 AST标识符冲突、shadowing
fixerAST可打印 AST自动分号、括号、语法细节
codegenAST + map 选项JS + Source Mapmap 丢失、输出路径泄露

严重问题完整流程:

症状根因观察命令修正
插件后输出语法非法transform 产生不符合 AST 约束的节点最小输入跑 plugin让 pass 只改必要节点,保留 hygiene/fixer
变量名冲突插件手写 ident 未考虑作用域构造 shadowing fixture使用 SWC 的作用域/mark 机制
Source Map 指向生成代码plugin 或 codegen 未保留位置信息打开 .map.sourcesmappings保留 span,开启 sourceMaps

jsc.targetenv.targets 和 polyfill 边界

jsc.target 是语法输出目标。共享示例写 es2022,意思是保留现代语法到 ES2022 左右,不做旧浏览器降级:

{
  "jsc": {
    "target": "es2022"
  }
}

env.targets 是环境组合,可接 Browserslist,也可配合 mode/coreJs 处理部分 polyfill 策略:

{
  "env": {
    "targets": "> 0.25%, not dead",
    "mode": "entry",
    "coreJs": "3.22"
  }
}

不要混用这三件事:

需求配置入口边界
降级 class/private field/可选链等语法jsc.targetenv.targets不自动证明类型正确
按浏览器验证范围选择 transformsenv.targets/BrowserslistBrowserslist 路径会影响 CI/local 一致性
注入 runtime polyfillenv.mode + coreJsusage 模式有表达式分析边界;仍需产物验证
保留现代 bundle 给上层打包器jsc.target: "es2022"module.type: "es6"老浏览器不兼容

严重问题完整流程:

症状根因观察命令修正
老 WebView 语法报错jsc.target 太现代检查产物是否保留 class/optional chaining明确目标环境或交给上层工具
String.prototype.at polyfilltarget 不等于 polyfill;env.usage 有分析限制浏览器报错或搜索 core-js入口显式 polyfill,或配置 env.mode: "entry"
本地和 CI 输出不同Browserslist 文件查找路径不同打印 cwd 和 config path显式 env.path 或统一 cwd

modules、TS/JSX/React:保留 ESM 通常更适合打包器

SWC 可以把模块语法输出为 commonjses6amdumd。共享示例选择:

{
  "module": {
    "type": "es6"
  }
}

原因很简单:这份输出还可能交给 Rollup/Vite/Rspack 等打包器,保留 ESM 更利于后续依赖图和 Tree Shaking。把 ESM 提前转成 CommonJS 会让下游少很多静态信息。

TypeScript 和 React 边界:

能力SWC 能做仍需要
删除 TS 类型tsc --noEmit 做类型检查
解析 TSX/JSX能,按 parser/transform 配置框架运行时和 JSX runtime 策略
React transform能配置 classic/automatic 等框架级 Fast Refresh/HMR
生成声明文件不负责tsc 或 API extractor
路由/组件水合不负责框架工具链

错误完整流程:

症状根因观察命令修正
下游 Tree Shaking 变差SWC 先把 ESM 转成 CJS`rg "require\(exports\." dist/swc`
类型声明缺失SWC 只输出 JS/map查 dist 是否有 .d.ts单独运行 tsc --emitDeclarationOnly
React refresh 不工作SWC 只做 transform,HMR 由宿主负责看宿主插件配置在 Vite/Next/Rspack 层配置 Fast Refresh

宿主工具、native binary 与缓存

SWC 常以三种方式进入项目:

入口负责范围常见缓存来源
@swc/cli批量转换目录或文件CLI 输出目录、CI 缓存
@swc/coreNode API,被工具调用宿主工具缓存
swc-loader/Rspack/Next/Jest作为宿主的一段 transformwebpack/Rspack/Next/Jest cache

缓存键至少包含:

const swcCacheKey = [
  process.version,
  process.platform,
  process.arch,
  '@swc/core@1.15.43',
  JSON.stringify(swcConfig),
  process.env.NODE_ENV ?? 'development',
].join('|');

严重问题完整流程:

症状根因观察命令修正
CI 安装后 native binding 报错平台包缺失或缓存跨平台复用查看 process.platform、lockfile、install 日志不跨平台复用 node_modules,保留 lockfile
.swcrc 输出没变宿主缓存 key 漏配置清缓存前后比较输出.swcrc、SWC 版本、env 加入 cache key
升级 SWC 后插件崩溃Wasm plugin 和 @swc/core AST/ABI 不兼容查看 plugin 依赖的 swc_core升级插件或按 1.15 兼容规则处理

Wasm plugin ABI/AST 兼容:1.15 降低成本,不取消回归

SWC Wasm plugin 过去常被 @swc/core 版本变化打断,因为 host 和 plugin 都要序列化/反序列化 AST。官方兼容文档说明,从 @swc/core v1.15.0 开始,Wasm plugin 在版本之间具备一定兼容性,核心变化包括使用自描述序列化方案和给 AST enum 增加可扩展处理。

但这不是“所有插件永远兼容”。官方也说明字段删除、字段类型变化等情况仍可能造成不兼容。插件作者需要依赖足够新的 swc_core,并处理 Unknown variant。

[target.'cfg(target_arch = "wasm32")']
rustflags = [
  "--cfg=swc_ast_unknown"
]

迁移判断:

场景动作
只用官方 transform,不用 Wasm plugin正常升级 @swc/core,跑转换 fixture
使用第三方 Wasm plugin检查插件是否支持 SWC 1.15 兼容策略
自研 Wasm plugin升级 swc_core >= 47,开启 swc_ast_unknown,补 Unknown match
插件处理新 ECMAScript 语法增加新语法 fixture,不能只看旧代码

严重问题完整流程:

症状根因观察命令修正
升级 @swc/core 后 Wasm plugin 直接失败旧插件依赖旧 AST 序列化看错误和插件 swc_core 版本升级插件,按兼容文档启用 Unknown
新语法输入导致 plugin panicplugin 不认识新 AST node最小新语法 fixture补 Unknown 分支和兼容测试
性能下降新序列化方案有兼容性成本benchmark 插件前后耗时只在需要插件时启用,避免全量插件链

Source Map:转换可追溯,也可能泄露源码路径

共享示例开启 sourceMaps: true,CLI 也传了 --source-maps

swc src --out-dir dist/swc \
  --config-file configs/swc.config.json \
  --source-maps \
  --extensions .ts \
  --strip-leading-paths \
  --delete-dir-on-start

artifact test 要求:

观察点预期结果
文件列表catalog.jsdetail.jsmain.jsside-effect.js 和对应 .map
catalog.js不包含 export type: Tool,保留 ESM export
.map.version等于 3
.map.sources能追溯到对应 .ts
.map.mappings非空

严重问题完整流程:

症状根因观察命令修正
DevTools 指向生成代码source map 未生成或 URL 丢失tail -n 2 dist/swc/main.js开启 sourceMaps 和 CLI --source-maps
map 泄露绝对路径source path 未处理`rg "$PWDfile:" dist/swc`
map 指向 .js 而非 .ts上游/插件 span 丢失解析 .map.sources保留 span,减少破坏性插件

共享示例:SWC 只转换 TypeScript 模块

运行命令:

pnpm --filter @roadmap/build-tools-slice build:swc

输入:

examples/build-tools/src/main.ts
examples/build-tools/src/catalog.ts
examples/build-tools/src/detail.ts
examples/build-tools/src/side-effect.ts

预期结果:

examples/build-tools/dist/swc/catalog.js
examples/build-tools/dist/swc/catalog.js.map
examples/build-tools/dist/swc/detail.js
examples/build-tools/dist/swc/detail.js.map
examples/build-tools/dist/swc/main.js
examples/build-tools/dist/swc/main.js.map
examples/build-tools/dist/swc/side-effect.js
examples/build-tools/dist/swc/side-effect.js.map

不会出现:

index.html
assets/*.css
assets/*.js
manifest.json

验证观察:

find examples/build-tools/dist/swc -maxdepth 1 -type f | sort
node --test --test-name-pattern swc examples/build-tools/test/artifacts.test.mjs

预期输出要点:

观察点预期结果
TypeScript类型声明被删除
ESM仍有 export
Source Map每个 .js 都有对应 .js.map
CSS/HTML不生成,因为 SWC 示例只做转换

迁移、重大变化和严重问题总表

SWC 1.x 的工程风险主要来自宿主集成、配置错线、native binary、Wasm plugin 和 source map,而不是“能不能解析一段 TypeScript”。

重大变化或风险表现根因最小观察修正
Wasm plugin 1.15 兼容变化升级后插件行为变化AST 序列化/Unknown variant 处理插件 fixture升级插件并按兼容文档改造
jsc.target/env.targets 错线产物语法或 polyfill 不符合预期target 与环境组合混淆对比输出和浏览器 fixture明确使用 jsc.targetenv
类型检查缺失构建通过但类型错误SWC 只转换tsc --noEmitCI 保留类型检查
ESM 被转 CJS下游 Tree Shaking 变差module.type 设置错误搜索 require(/exports.给 bundler 输入保留 ES6
native binding 缺失CI 或新平台构建失败平台包/缓存问题install 日志和 process.platform不复用跨平台 node_modules
Source Map 泄露公开源码或绝对路径map 发布策略粗糙`rg "$PWDfile:" dist/swc`

资料入口

在 GitHub 上编辑此页

本页目录