@babel/preset-env和@babel/plugin-transform-runtime傻傻分不清

前言

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 including core-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 than 7.18.0, you must also load the regenerator runtime package. It is automatically loaded when using @babel/preset-env's useBuiltIns: "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结果如下:

image.png

可以看到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结果如下:


image.png

可以看到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结果如下:


image.png

可以看到内联的helper函数都被@babel/runtime-corejs3/helpers/替换,并且只导入了基于targets配置且在代码中使用到的特性

rollup编译,执行命令:
npm run build

Edge中模拟IE9顺利打印出true

你可能感兴趣的:(@babel/preset-env和@babel/plugin-transform-runtime傻傻分不清)