跳至主要内容

@babel/plugin-transform-runtime

一个插件,可以重复使用 Babel 注入的辅助代码以节省代码大小。

注意

实例方法(例如 "foobar".includes("foo"))仅适用于 core-js@3。 如果您需要填充它们,可以直接导入 "core-js" 或使用 @babel/preset-envuseBuiltIns 选项。

安装

将其作为开发依赖项安装。

npm install --save-dev @babel/plugin-transform-runtime

并将 @babel/runtime 作为生产依赖项安装(因为它用于“运行时”)。

npm install --save @babel/runtime

转换插件通常仅在开发中使用,但运行时本身将由您部署的代码依赖。有关更多详细信息,请参见下面的示例。

危险

启用此插件后,不得设置 @babel/preset-env 中的 useBuiltIns 选项。 否则,此插件可能无法完全隔离环境。

为什么?

Babel 对 _extend 等常用函数使用非常小的辅助函数。 默认情况下,这将添加到需要它的每个文件中。 这种重复有时是不必要的,尤其是当您的应用程序分布在多个文件中的时候。

这就是 @babel/plugin-transform-runtime 插件的用武之地:所有辅助函数都将引用模块 @babel/runtime,以避免在编译后的输出中出现重复。 运行时将被编译到您的构建中。

此转换器的另一个目的是为您的代码创建一个沙盒环境。 如果您直接导入 core-js@babel/polyfill 以及它提供的内置函数(如 PromiseSetMap),则这些函数会污染全局作用域。 虽然这对于应用程序或命令行工具来说可能没问题,但如果您的代码是一个库,您打算将其发布供其他人使用,或者您无法完全控制代码运行的环境,那么这将成为一个问题。

转换器会将这些内置函数别名为 core-js,因此您可以无缝使用它们,而无需 require polyfill。

有关此工作原理和发生的转换类型的更多信息,请参见技术细节部分。

用法

无选项

babel.config.json
{
"plugins": ["@babel/plugin-transform-runtime"]
}

带选项(及其默认值)

babel.config.json
{
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": false,
"helpers": true,
"regenerator": true,
"version": "7.0.0-beta.0"
}
]
]
}

该插件默认假设所有可填充 API 都将由用户提供。 否则,需要指定 corejs 选项。

通过 CLI

Shell
babel --plugins @babel/plugin-transform-runtime script.js

通过 Node API

JavaScript
require("@babel/core").transformSync("code", {
plugins: ["@babel/plugin-transform-runtime"],
});

选项

corejs

false23{ version: 2 | 3, proposals: boolean },默认为 false

例如 ['@babel/plugin-transform-runtime', { corejs: 3 }],

历史
版本更改
v7.4.0支持 { proposals: boolean }

指定一个数字将重写需要可填充 API 的辅助函数,以引用来自该(主要)版本的 core-js 的辅助函数。 请注意,corejs: 2 仅支持全局变量(例如 Promise)和静态属性(例如 Array.from),而 corejs: 3 还支持实例属性(例如 [].includes)。

默认情况下,@babel/plugin-transform-runtime 不会填充提案。 如果您使用的是 corejs: 3,则可以通过启用 proposals: true 选项来选择加入。

此选项需要更改用于提供必要运行时辅助函数的依赖项

corejs 选项安装命令
falsenpm install --save @babel/runtime
2npm install --save @babel/runtime-corejs2
3npm install --save @babel/runtime-corejs3

helpers

boolean,默认为 true

切换是否将内联 Babel 辅助函数(classCallCheckextends 等)替换为对 @babel/runtime(或等效包)的调用。

有关更多信息,请参见辅助函数别名

moduleName

历史
版本更改
v7.24.0添加了 moduleName 选项

string,默认为 @babel/runtime

此选项控制 @babel/plugin-transform-runtime 在注入导入时将使用哪个辅助函数包。 它使用以下优先级

  • moduleName 选项(如果已指定)
  • 任何 babel-plugin-polyfill-* 插件建议的辅助函数模块
    • babel-plugin-polyfill-corejs3 建议使用 @babel/runtime-corejs3
    • babel-plugin-polyfill-corejs2 建议使用 @babel/runtime-corejs2
  • 回退到 @babel/runtime

请注意,指定 corejs 选项将在内部启用相应的 babel-plugin-polyfill-corejs* 插件,因此它会影响最终的模块名称。

polyfill

危险

此选项已在 v7 中删除。

regenerator

boolean,默认为 true

切换是否将生成器函数转换为使用不污染全局作用域的 regenerator 运行时。

有关更多信息,请参见Regenerator 别名

useBuiltIns

危险

此选项已在 v7 中删除。

useESModules

注意

此选项已被弃用,并将在 Babel 8 中删除:从版本 7.13.0 开始,@babel/runtimepackage.json 使用 "exports" 选项来自动在 CJS 和 ESM 辅助函数之间进行选择。

boolean,默认为 false

历史
版本更改
v7.13.0此选项已被弃用

启用后,转换将使用不会通过 @babel/plugin-transform-modules-commonjs 运行的辅助函数。 这允许在 webpack 等模块系统中进行更小的构建,因为它不需要保留 commonjs 语义。

例如,以下是禁用 useESModulesclassCallCheck 辅助函数

JavaScript
exports.__esModule = true;

exports.default = function(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
};

以及启用它

JavaScript
export default function(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}

absoluteRuntime

booleanstring,默认为 false

这允许用户在整个项目中广泛运行 transform-runtime。 默认情况下,transform-runtime 直接从 @babel/runtime/foo 导入,但这仅在 @babel/runtime 位于正在编译的文件的 node_modules 中时才有效。 对于嵌套的 node_modules、npm 链接的模块或位于用户项目之外的 CLI,这可能会出现问题。 为了避免担心如何解析运行时模块的位置,这允许用户预先解析一次运行时,然后将运行时的绝对路径插入到输出代码中。

如果文件被编译以供以后使用,则不希望使用绝对路径,但在编译文件后立即使用文件的上下文中,它们可能会非常有用。

提示

您可以在此处阅读有关配置插件选项的更多信息

version

默认情况下,transform-runtime 假设安装了 @babel/[email protected]。 如果您安装了更高版本的 @babel/runtime(或其 corejs 对应版本,例如 @babel/runtime-corejs3)或将其列为依赖项,则 transform-runtime 可以使用更多高级功能。

例如,如果您依赖于 @babel/[email protected],则可以使用以下命令转换代码

babel.config.json
{
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": 2,
"version": "^7.7.4"
}
]
]
}

这将导致更小的包大小。

技术细节

transform-runtime 转换器插件执行三件事

  • 当您使用生成器/异步函数时,自动 require @babel/runtime/regenerator(可使用 regenerator 选项切换)。
  • 如果需要,可以使用 core-js 作为辅助函数,而不是假设它会被用户填充(可使用 corejs 选项切换)
  • 自动删除内联 Babel 辅助函数,并使用模块 @babel/runtime/helpers 代替(可使用 helpers 选项切换)。

但这实际上意味着什么呢? 基本上,你可以使用内置函数,例如 PromiseSetSymbol 等,以及使用所有需要 polyfill 的 Babel 功能,而不会造成全局污染,使其非常适合库。

确保将 @babel/runtime 作为依赖项包含在项目中。

Regenerator 别名

每当你使用生成器函数或异步函数时

JavaScript
function* foo() {}

会生成以下代码

JavaScript
"use strict";

var _marked = [foo].map(regeneratorRuntime.mark);

function foo() {
return regeneratorRuntime.wrap(
function foo$(_context) {
while (1) {
switch ((_context.prev = _context.next)) {
case 0:
case "end":
return _context.stop();
}
}
},
_marked[0],
this
);
}

这并不理想,因为它依赖于包含 regenerator 运行时,这会污染全局作用域。

但是,使用 runtime 转换器,它会被编译为

JavaScript
"use strict";

var _regenerator = require("@babel/runtime/regenerator");

var _regenerator2 = _interopRequireDefault(_regenerator);

function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}

var _marked = [foo].map(_regenerator2.default.mark);

function foo() {
return _regenerator2.default.wrap(
function foo$(_context) {
while (1) {
switch ((_context.prev = _context.next)) {
case 0:
case "end":
return _context.stop();
}
}
},
_marked[0],
this
);
}

这意味着你可以使用 regenerator 运行时,而不会污染当前环境。

core-js 别名

有时你可能想使用新的内置函数,例如 MapSetPromise 等。通常,使用这些函数的唯一方法是包含一个会污染全局作用域的 polyfill。

这是使用 corejs 选项实现的。

该插件将以下代码

JavaScript
var sym = Symbol();

var promise = Promise.resolve();

var check = arr.includes("yeah!");

console.log(arr[Symbol.iterator]());

转换为以下代码

JavaScript
import _getIterator from "@babel/runtime-corejs3/core-js/get-iterator";
import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
import _Promise from "@babel/runtime-corejs3/core-js-stable/promise";
import _Symbol from "@babel/runtime-corejs3/core-js-stable/symbol";

var sym = _Symbol();

var promise = _Promise.resolve();

var check = _includesInstanceProperty(arr).call(arr, "yeah!");

console.log(_getIterator(arr));

这意味着你可以无缝地使用这些原生内置函数和方法,而无需担心它们的来源。

**注意:** 实例方法,例如 "foobar".includes("foo"),只有在使用 corejs: 3 时才有效。

辅助函数别名

通常,Babel 会将辅助函数放在文件的顶部,以执行常见任务,从而避免在当前文件中重复代码。有时,这些辅助函数可能会变得很大,并在文件中造成不必要的重复。runtime 转换器将所有辅助函数调用替换为模块。

这意味着以下代码

JavaScript
class Person {}

通常会转换为

JavaScript
"use strict";

function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}

var Person = function Person() {
_classCallCheck(this, Person);
};

但是,runtime 转换器会将其转换为

JavaScript
"use strict";

var _classCallCheck2 = require("@babel/runtime/helpers/classCallCheck");

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}

var Person = function Person() {
(0, _classCallCheck3.default)(this, Person);
};