SWC插件开发前必须确认:一、必须用Rust编写并编译为动态库,JS/TS仅作配置;二、.swcrc中plugins字段须指向动态库绝对路径;三、插件入口函数签名须严格匹配SWC官方ABI。
不写 Rust 就没法开发 SWC 插件——这是最常被忽略的前提。SWC 的插件系统原生基于 Rust,@swc/core 提供的是 Rust 编译器的绑定接口,所有自定义转换逻辑(比如代码注入、条件编译)都得用 Rust 实现,JS/TS 层只能做配置或调用,不能替代核心逻辑。
常见错误现象:swc 命令报错 unknown plugin "my-inject",或者 plugin not found,基本都是因为只写了 JS 配置但没编译 Rust 插件二进制,或没把 .so/.dylib/.dll 文件路径正确传给 jsc.transform.plugins。
使用场景有限制:如果你只是想在 React 组件里加个 console.log 或注入样式,直接用 @swc/plugin-transform-react-jsx 或 @swc/plugin-transform-emotion 更合适;真要写插件,通常是为了解决框架未覆盖的定制需求,比如按环境变量剔除调试代码、自动包裹特定函数调用、或对接内部 DSL 编译流程。
cargo build --release 编译插件,并确保输出动态库文件.swcrc 中的 plugins 字段必须指向该动态库的绝对路径,不能是相对路径或包名#[no_mangle] pub extern "C" fn transform(...)
SWC 插件不是靠文件名或目录过滤来“按需”,而是靠解析后的 AST 节点特征做实时决策。比如你想只对带 @env("prod") 注释的函数做死代码删除,就得在 VisitMut 实现中检查 FnDecl 节点是否附带对应 Comment,而不是在插件外层做 if (filePath.includes("prod")) 这种粗粒度判断。
性能影响很实际:SWC 默认启用增量编译,但如果你的插件在 visit_mut_program 里做了全局状态缓存(比如 HashMap<Span, bool>),又没正确处理 Span 的跨文件唯一性,会导致缓存污染,二次构建时误删本该保留的代码。
Span + FileName 组合作为缓存 key,避免仅依赖 Span
fs.readFileSync),这会阻塞并行编译线程JsxElement 和 JsxFragment 的差异,后者没有 opening/closing,容易漏处理直接往 Program 顶层 unshift 一个 ExprStmt 看似简单,但会导致 source map 错位、HMR 失效,甚至破坏 Tree Shaking。SWC 的注入逻辑必须尊重作用域和执行时序。
典型错误:在 visit_mut_module_decl 里插入 ImportDecl,结果生成的代码里 import 语句出现在 export default 后面,违反 ES 模块规范,浏览器直接报 Unexpected token 'export'。
visit_mut_module_items 阶段,且插入到所有 ModuleItem::ModuleDecl 的最前面Program.body 的第一个 Stmt 之前,而非追加到末尾ast::Expr::Tpl 或 ast::Expr::JsxElement 构造,不能拼接字符串再 parse——后者会丢失原始 Span,导致调试困难别信“用 console.log 在 Rust 里打印就能看到输出”这种说法。SWC 插件运行在独立进程或 WASM 环境中,标准输出默认被重定向或丢弃。真正有效的调试方式只有两种:写日志文件,或用 gdb attach 到 swc 进程。
你写的插件在 CI 上跑通,但在本地 swc src -d dist 却没生效?大概率是 .swcrc 没被正确加载——SWC 默认只找当前工作目录下的 .swcrc,不会向上遍历父目录。而 Vite 或 Rspack 集成时,往往通过 API 显式传入配置对象,绕过了文件查找逻辑。
--config <code>.swcrc 参数强制指定配置路径,确认是否加载成功std::fs::write("/tmp/swc-plugin-debug.log", "start").ok();,验证是否被调用swc --dump-ast input.ts 先看原始 AST 结构,再决定在哪个 visitor 方法里下手,比盲猜高效得多复杂点在于,Rust 插件的编译产物与 Node.js 运行时 ABI 版本强绑定,@swc/[email protected] 可能无法加载用 swc_core v0.87 编译的插件,这类兼容性问题不会报明确错误,只会静默失败。