SWC 是一个用 Rust 写的编译工具,功能跟 babel 很类似。它的优势在于速度,按照官网所说,在单核上它的速度是 babel 的 20倍,四核上是 babel 的 70 倍。
我最近尝试升级工具链,第一步是使用 esbuild-loader 替代 babel-loader,比较顺利。但是 esbuild 只支持 ES2015,为了支持 IE11,我们还需要再转译一次。这次我想试试 SWC。
安装与配置
安装 swc 很简单。我打算 build 的时候用 @swc/cli 转译;debug IE11 的时候把 swc-loader 套在 esbuild-loader 前面输出。所以需要安装三个包:
nom i @swc/core @swc/cli swc-loader -D
接下来添加配置文件 .swcrc
:
{
"sourceMaps": false,
"module": {
"type": "umd"
},
"minify": true
}
默认目标平台 target: 'es5'
,不需要再写。其它语言选项也走默认即可。
SWC sourceMap
支持三种配置:true
、false
、inline
,意思一看就明白。但目前 bug 比较多,即使设置 sourceMap:false
,也只是不生成 sourcemap 文件,对应的链接标记仍然会生成。
module.type
有另一个 bug:即使目标平台是 ES5,它也会使用 ESM 引入依赖,导致语法解析出错。比如代码中使用了 async function,SWC 转译时就需要 import regeneratorRuntime from 'regenerator-runtime'
。所以上面我配置 module.type
为 "umd"
,一方面避免错误的 ESM import
,另一方面可以通过全局方式引用这些库。
minify: true
表示我们希望 SWC 转译代码时顺便把它们压缩一下。官方文档说这个功能还不是很完善,不过我暂时没发现明显的问题。
swc 游乐场
SWC 官方提供预览网站:SWC Playground – SWC。我们可以把源码贴上去,查看编译结果。也可以调整选项,看看不同选项对结果的影响。
问题
把 SWC 放进工具链的过程还算顺利,不过接下来使用的时候却遭遇了不少问题。
首先就是上文说的 ESM 导入的问题。默认情况下 SWC 会 import 'regenerator-runtime'
,这个问题必须解决。考虑到这个代码特征比较明显,起初,我打算直接字符串过滤掉。后来翻了文档,又在 playground 里尝试了一下,发现 UMD 应该可以解决问题。
然后是语法问题。下面这段代码 SWC 编译错误:
// 输入
let a = 10;
for (let b = 0; b < a; b++) {
let c = 0, b = 10, d = 100;
console.log(b);
}
// 输出
var a = 10;
for (var b = 0; b < a; b++) {
var c = 0, b = 10, d = 100;
console.log(b);
}
这段代码其实有点意思,我看了很久才找到问题:let
声明变量时,for ()
相对于下面的代码块,是上级 context;而 var
时,它们处于同级 context。所以下面这段循环只会运行一次,而不是像上面一样,执行 10 次。
(这段代码很能考察 let
和 var
的不同,我准备把它加入我的面试题库。)
还有其它一些语法问题,因为上面这个问题无法绕过,意味着使用 SWC 这条路不可行,所以我也没有深入研究,就不一一列举了。
总结
SWC 用户量太小,未知 Bug 很多;开发团队不大,又是用 Rust 写的,也给想贡献代码的前端社区带来很大阻碍。所以目前还难以应对大型项目、工业级别的需求。
不过它的速度的确很快,对改进项目构建速度有很大帮助。希望那些 bug 能尽快修复,我们可以早点把它应用到产品当中。
欢迎吐槽,共同进步