前言
babel只是转换语法,后为了解决API的兼容,又引入了pollify概念,再后来为了解决组件开发者的环境多样性,又引入了runtime。
本文以async、Promise、Array.prototype.includes三个方法如何运行在IE9中作为例子,粗略探讨两者之间的差别和使用。
详见官网
环境
为了清晰直观,本文采用两种方式编译
- @babel/cli
直接编译代码,更清晰看到babel帮我们引入了什么 - rollup
将代码编译成浏览器可运行代码,验证结果
//package.json
"devDependencies": {
"@babel/cli": "^7.18.10",
"@babel/core": "^7.18.10",
"@babel/plugin-transform-runtime": "^7.18.10",
"@babel/preset-env": "^7.18.10",
"rollup": "^2.6.1",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0"
},
"dependencies": {
"@babel/runtime": "^7.18.9",
"@babel/runtime-corejs3": "^7.18.9",
"core-js": "^2.6.12"
}
//rollup.config.js
import resolve from 'rollup-plugin-node-resolve'; //帮助rollup查找外部模块,然后导入
import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs'; //将CommonJS模块转换为ES2015供rollup处理
export default {
input: './a.js',
output: {
file: './b.js',
format: 'iife'
},
plugins: [
resolve(),
babel({
exclude: 'node_modules/**',
runtimeHelpers: true //启用babel runtime
}),
commonjs({})
]
};
preset-env
说明
preset-env本身只解决了语法层面的问题,配合polyfill(polyfill是一个统称,常见的包括@babel/polyfill和core-js等)可以解决api兼容问题
@babel/core 7.4.0后polyfill被废弃,被core-js/stable代替(因为@babel/polyfill的核心就是core-js)
来自官方:
As of Babel
7.4.0
, this package has been deprecated in favor of directly includingcore-js/stable
(to polyfill ECMAScript features)
特别注意
如果要转换generator或者async,当@babel/core版本小于7.18.0时,需要自行加载regenerator-runtime
来自官方:
If you are compiling generators or async function to ES5, and you are using a version of
@babel/core
or@babel/plugin-transform-regenerator
older than7.18.0
, you must also load theregenerator runtime
package. It is automatically loaded when using@babel/preset-env
'suseBuiltIns: "usage"
option or@babel/plugin-transform-runtime
配置
useBuiltIns
有三个值可选
false
不需要导入core-js
不用polyfill,如果入口文件中导入了core-js, 会无视targets的配置加载所有的 polyfill
entry
需要在入口文件中导入core-js
// a.js
import "core-js/stable";
(async () => {
const arr = await Promise.resolve([1,2,3]);
console.log(arr.includes(2));
})();
// .babelrc
{
"presets": [
[
"@babel/preset-env",
{
"debug": true,
"useBuiltIns": "entry",
// "corejs": { //默认version为2,使用3需要安装core-js@3
// "version": "3"
// },
"targets":{
"browsers":["ie >= 9"]
}
}
]
]
}
直接编译,执行命令:
npx babel a.js -o b.js
b.js结果如下:
可以看到babel导入了基于targets配置所有不支持的全部特性,并且注入了helper函数
rollup编译,执行命令:
npm run build
Edge中模拟IE9顺利打印出true
usage
需要在入口文件中导入core-js(a.js同上)
// .babelrc
{
"presets": [
[
"@babel/preset-env",
{
"debug": true,
"useBuiltIns": "usage",
// "corejs": { //默认version为2,使用3需要安装core-js@3
// "version": "3"
// },
"targets":{
"browsers":["ie >= 9"]
}
}
]
]
}
直接编译,执行命令:
npx babel a.js -o b.js
b.js结果如下:
可以看到babel只导入了基于targets配置且在代码中使用到的特性,并且注入了helper函数
rollup编译,执行命令:
npm run build
Edge中模拟IE9顺利打印出true
plugin-transform-runtime
说明
plugin-transform-runtime配和runtime使用可以按需引入特性,并且挂载在内建变量中,不污染全局,特别适合组件开发者使用。
runtime
组成
runtime包含了helper 的 runtime 版本,corejs,和实现 async、await 的regenerator
runtime 这3部分除了 helper 其他都是第三方的
作用
自动移除语法转换后内联的辅助函数(inline Babel helpers),使用@babel/runtime/helpers里的辅助函数来替代;
当代码里使用了core-js的API,自动引入@babel/runtime-corejs3/core-js-stable/,以此来替代全局引入的core-js/stable;
当代码里使用了generator/async函数,自动引入@babel/runtime/regenerator,以此来替代全局引入的regenerator-runtime/runtime;
到这儿你应该知道了,plugin-transform-runtime其实是preset-env的增强
特别注意
corejs2仅支持全局变量和静态属性polyfill(例如:Promise和Array.from),要兼容incluedes等实例属性需要用到corejs3
corejs option | Install command |
---|---|
false | npm install --save @babel/runtime |
2 | npm install --save @babel/runtime-corejs2 |
3 | npm install --save @babel/runtime-corejs3 |
配置
corejs
不需要导入core-js
// a.js
(async () => {
const arr = await Promise.resolve([1,2,3]);
console.log(arr.includes(2));
})();
// .babelrc
{
"presets": [
[
"@babel/preset-env",
{
"debug": true,
"targets":{
"browsers":["ie >= 9"]
}
}
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": "3"
}
]
]
}
直接编译,执行命令:
npx babel a.js -o b.js
b.js结果如下:
可以看到内联的helper函数都被@babel/runtime-corejs3/helpers/替换,并且只导入了基于targets配置且在代码中使用到的特性
rollup编译,执行命令:
npm run build
Edge中模拟IE9顺利打印出true