在当下搭建前端工程时一定避不开babel,对于babel最常用的两个库@babel/polyfill和@babel/plugin-transform-runtime,需要搞清楚他们的作用和区别。
@babel/polyfill
@babel/polyfill主要提供需要修改内置api(实例方法)才能达成的功能,譬如:扩展Object.prototype,给上面加上assign方法,就属于修改内置API的范畴。
Babel 7.4.0后,这个包被弃用并被两个子包替代:core-js/stable(提供polyfill)和regenerator-runtime/runtime(提供generator和async方法,可以用runtime实现)。这里就要说到babel 7后的另一个库:@babel/preset-env
@babel/preset-env
@babel/preset-env根据指定的执行环境提供配置polyfill。之前的stage-X库都已废弃。
@babel/preset-env主要是依赖browserslist来设置target进而判断运行环境,然后根据useBuiltIns的配置来决定如何引入polyfill。
useBuiltIns属性主要有三个值:"usage" | "entry" | false,默认是false。这里建议安装core-js替代@babel/polyfill
1 2 3 4 5
| npm install core-js@3 --save
npm install core-js@2 --save
|
useBuiltIns: false
不自动引入polyfills,也不会转换import "core-js"和import "@babel/polyfill"引用为单独的polyfill。
useBuiltIns: 'entry'
处理在项目入口的引入,注意你的整个应用(bundle)只能使用一次import "core-js和import "regenerator-runtime/runtime"。如果多次引入会报错。推荐创建一个只包含import声明的单入口文件。
in
out(基于不同的环境)
1 2
| import "core-js/modules/es.string.pad-start"; import "core-js/modules/es.string.pad-end";
|
in
1 2
| import "core-js/es/array"; import "core-js/proposals/math-extensions";
|
out(基于不同的环境)
1 2 3 4 5 6 7 8 9
| import "core-js/modules/es.array.unscopables.flat"; import "core-js/modules/es.array.unscopables.flat-map"; import "core-js/modules/esnext.math.clamp"; import "core-js/modules/esnext.math.deg-per-rad"; import "core-js/modules/esnext.math.degrees"; import "core-js/modules/esnext.math.fscale"; import "core-js/modules/esnext.math.rad-per-deg"; import "core-js/modules/esnext.math.radians"; import "core-js/modules/esnext.math.scale";
|
useBuiltIns: 'usage'
在文件需要的位置单独按需引入,可以保证在每个bundler中只引入一份。
in
a.js
b.js
out(如果环境不支持上述语法)
1 2
| import "core-js/modules/es.promise"; var a = new Promise();
|
1 2
| import "core-js/modules/es.map"; var b = new Map();
|
out(如果环境支持上述语法)
tips
理论上useBuiltIns: 'entry'这种由入口文件一股脑把所有pollfill全部引入的方式是不推荐的,而useBuiltIns: 'usage'这种按需引入应该是最优的处理方式,但是要注意一点就是useBuiltIns: 'usage'不会处理第三方依赖包的引入模块,所以如果第三方依赖包使用了高级语法而未处理兼容性的话,可能会出bug。
corejs
2,2或{ version: 2 | 3, proposals: boolean },默认是2
这个配置项只有当useBuiltIns: usage或useBuiltIns: entry时才有效,指定@babel/preset-env引入的core-js版本。
当使用useBuiltIns: entry时,你可以直接引入指定的polyfill比如import "core-js/proposals/string-replace-all"
当使用useBuiltIns: usage时,有两种选择:
1、将shippedProposals设置为’true`
2、使用corejs: { version: 3, proposals: true }
@babel/plugin-transform-runtime主要提供全局内置对象比如Promise、Set、Map,并将全局内置对象抽取成单独的模块,通过模块导入的方式引入,避免了对全局作用域的修改(污染)。
有人会奇怪babel里为什么会有@babel/plugin-transform-runtime和@babel/runtime?刚开始是只有@babel/runtime插件,但是@babel/runtime有个问题,在代码中直接引入helper函数,意味着不能共享,造成最终打包出来的文件里有很多重复的helper代码。所以,Babel又开发了@babel/plugin-transform-runtime,这个模块会将我们的代码重写,如将Promise重写成_Promise(举例),然后引入_Promise helper函数。这样就避免了重复打包代码和手动引入模块的痛苦。
总结
当前babel版本最优的使用方式应该是@babel/preset-env搭配@babel/plugin-transform-runtime,能够很好的处理高级语法的兼容性问题。