跳至主内容

@babel/plugin-transform-runtime

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

该插件支持复用 Babel 注入的辅助代码,以减小代码体积。

备注

实例方法如 "foobar".includes("foo") 仅在 core-js@3 环境下有效。如需 polyfill 这些方法,可直接导入 "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,使您无需导入 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"
}
]
]
}

插件默认假设所有可 polyfill 的 API 均由用户提供,否则需指定 corejs 选项。

通过命令行

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

通过 Node API

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

配置选项

absoluteRuntime

booleanstring 类型,默认值 false

此选项允许在整个项目中广泛使用 transform-runtime。默认情况下,transform-runtime 直接从 @babel/runtime/foo 导入,但这仅当 @babel/runtime 位于被编译文件的 node_modules 中时才有效。对于嵌套的 node_modules、npm 链接模块或位于用户项目外的 CLI 等场景,这会导致问题。为避免解析运行时模块位置的困扰,此选项允许用户预先解析运行时路径,并将绝对路径插入输出代码。

若文件需编译后延迟使用,则绝对路径并不可取;但在即编即用的场景中,该方案非常实用。

提示

你可以在此处阅读更多关于配置插件选项的信息。

corejs

false, 2, 3 or { version: 2 | 3, proposals: boolean }, defaults to false.

e.g. ['@babel/plugin-transform-runtime', { corejs: 3 }],

History
VersionChanges
v7.4.0Supports { proposals: boolean }

Specifying a number will rewrite the helpers that need polyfillable APIs to reference helpers from that (major) version of core-js instead Please note that corejs: 2 only supports global variables (e.g. Promise) and static properties (e.g. Array.from), while corejs: 3 also supports instance properties (e.g. [].includes).

By default, @babel/plugin-transform-runtime doesn't polyfill proposals. If you are using corejs: 3, you can opt into this by enabling using the proposals: true option.

This option requires changing the dependency used to provide the necessary runtime helpers:

corejs optionInstall command
falsenpm install --save @babel/runtime
2npm install --save @babel/runtime-corejs2
3npm install --save @babel/runtime-corejs3
注意

The corejs option will be removed in Babel 8. To inject polyfills, you can use babel-plugin-polyfill-corejs3 or babel-plugin-polyfill-corejs2 directly.

helpers

boolean, defaults to true.

Toggles whether or not inlined Babel helpers (classCallCheck, extends, etc.) are replaced with calls to @babel/runtime (or equivalent package).

For more information, see Helper aliasing.

注意

The helpers option will be removed in Babel 8, as this plugin will only be used to inject helpers (including regeneratorRuntime, which will be handled as any other Babel helper).

moduleName

History
VersionChanges
v7.24.0Added moduleName option

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* 插件,因此会影响最终的模块名称。

regenerator

boolean, defaults to true.

In older Babel version, this option used to toggles whether or not generator functions were transformed to use a regenerator runtime that does not pollute the global scope.

For more information, see Regenerator aliasing.

注意

The regenerator option will be removed in Babel 8, as it will not be necessary anymore.

useESModules

boolean, defaults to false.

History
VersionChanges
v7.13.0This option has been deprecated

When enabled, the transform will use helpers that do not get run through @babel/plugin-transform-modules-commonjs. This allows for smaller builds in module systems like webpack, since it doesn't need to preserve commonjs semantics.

For example, here is the classCallCheck helper with useESModules disabled:

JavaScript
exports.__esModule = true;

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

And, with it enabled:

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

The useESModules option has been deprecated and will be removed in Babel 8: starting from version 7.13.0, @babel/runtime's package.json uses "exports" option to automatically choose between CJS and ESM helpers.

version

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

例如,如果您依赖 @babel/runtime@^7.24.0,可以通过以下配置转译代码:

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

这样可以减小包体积。

技术细节

transform-runtime 转换器插件实现三个核心功能:

  • 当使用生成器/异步函数时自动引入 @babel/runtime/regenerator(可通过 regenerator 选项控制)
  • 必要时可使用 core-js 替代用户提供的 polyfill(通过 corejs 选项控制)
  • 自动移除内联 Babel 辅助函数,改用 @babel/runtime/helpers 模块(通过 helpers 选项控制)

这实际意味着什么?简而言之,您可以无缝使用 PromiseSetSymbol 等内置对象以及所有需要 polyfill 的 Babel 功能,同时避免全局污染,这使其特别适合库开发。

备注

请务必将 @babel/runtime 添加为依赖项。

生成器函数别名处理

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

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);
};

已移除的选项

以下选项已在 Babel 7.0.0 中移除:

以下选项已在 Babel 7.0.0 中移除:

  • useBuiltIns

  • polyfill