背景
开门尖山,swc 目前在 polyfill 上存在一些问题:
es2022 不支持
当使用 es2022 特性(如 array.at
)时(目前未发布),无论使用哪种 swc 提供的 polyfill 策略(usage
/ entry
),都无法提供 es2022 的 polyfill (其中 entry
策略最多提供至 es2021 )。
swc polyfill 查询列表已过时
swc 的 polyfill 策略是自己维护了一份 core-js-compat
的 modules-by-versions.json
列表(已过时),无法即时同步上游 core-js
的最新 polyfill 变动。
swc polyfill 未积极维护
swc 长时间未积极维护 polyfill 功能模块。
综上所述,我们当前使用任何 swc 的 polyfill 策略均不是最优解。
下面我们将探求权衡一种相对最优的 swc polyfill 解法。
解法
幸运的是,swc 提供了手动声明需要导入的 polyfill 选项,即 env.include
( Additional Options - include ),通过指定所需 polyfill modules 列表即可达到预期。
先安装所需依赖:
pnpm add browserslist core-js core-js-compat
实现自动获取 polyfill modules :
// getPolyfills.ts
import browserslist from 'browserslist'
export const getPolyfills = () => {
// ↓ 项目的根目录,会从这里自动寻找 browserslistrc 配置
const root = process.cwd()
const env = process.env.NODE_ENV
const browsers = browserslist(undefined, { path: root, env })
const { list } = require('core-js-compat')({
targets: browsers,
// ↓ 此处必须指定 core-js 的 前两位 具体版本,如 `3.20` / `3.21` ,否则会 polyfill 不完全!
version: '3.21',
})
// ['es.error.cause', 'es.aggregate-error', 'es.aggregate-error.cause', ...]
return list as string[]
}
注:
-
若无需自动
browserslistrc
配置,可改为手动指定browsers
(如['chrome 80']
)。 -
当读取不到
browserslistrc
配置时,默认使用defaults
配置,详见 browserslist / browserslist 。
最终传入 swc 配置即可:
// .swcrc 片段
import { getPolyfills } from './getPolyfills'
{
"env": {
"include": getPolyfills()
}
}
到此为止,swc 便可自动注入所有我们通过 browserslistrc
配置的 targets 对应的 polyfill,注意是全量注入,类似于 babel 的 entry
策略。
总结
使用 swc 的快速,必然会带来一些 side effect,我们需要在其中权衡和选择,本质上是一种 trade off 。
产物大小权衡
由于是全量导入 polyfill,不是按需策略,所以产物体积会增大 100KB - 200KB
,但现代如此快速的网络环境之下,对比 swc 带给我们的编译速度收益,也是可以接受的。
当然我们也可以指定更高阶的 targets ,来减少 polyfill 的量,如使用:
// .browserslistrc
chrome 80
这种较高的 targets 会得到相对较小的产物体积。
对比 esbuild
swc 的 polyfill 策略一大好处是他可以把注入策略放入框架层,而无需让用户感知到,因为类 babel 的 entry
策略均需要 “显示” 的在项目代码内声明 core-js
导入,这会让使用者感到不适。
定位为 babel 替代的 swc 相对比定位为转译器的 esbuild ,esbuild 则不能很好的在框架层解决这个问题(umijs
等可以提供中间层代码的框架除外)。
其他
-
core-js-compat:modules-by-versions.json
-
swc issue #1604:Direct usage of core-js-compat
-
swc issue #2607:swc not polyfill string.replaceAll
终局
由于 swc 是作者大学时期的作品,且作者也认为其架构较为混乱,正准备重构的工作,预计未来,我们会看到更好的 swc ,不需要这么多的 workaround 和 trade off,真正迈向替代 babel 的道路。
再见,babel !