@babel/plugin-transform-runtime
一个插件,可以重复使用 Babel 注入的辅助代码以节省代码大小。
实例方法(例如 "foobar".includes("foo")
)仅适用于 core-js@3
。 如果您需要填充它们,可以直接导入 "core-js"
或使用 @babel/preset-env
的 useBuiltIns
选项。
安装
将其作为开发依赖项安装。
- npm
- Yarn
- pnpm
npm install --save-dev @babel/plugin-transform-runtime
yarn add --dev @babel/plugin-transform-runtime
pnpm add --save-dev @babel/plugin-transform-runtime
并将 @babel/runtime
作为生产依赖项安装(因为它用于“运行时”)。
- npm
- Yarn
- pnpm
npm install --save @babel/runtime
yarn add @babel/runtime
pnpm add @babel/runtime
转换插件通常仅在开发中使用,但运行时本身将由您部署的代码依赖。有关更多详细信息,请参见下面的示例。
启用此插件后,不得设置 @babel/preset-env
中的 useBuiltIns
选项。 否则,此插件可能无法完全隔离环境。
为什么?
Babel 对 _extend
等常用函数使用非常小的辅助函数。 默认情况下,这将添加到需要它的每个文件中。 这种重复有时是不必要的,尤其是当您的应用程序分布在多个文件中的时候。
这就是 @babel/plugin-transform-runtime
插件的用武之地:所有辅助函数都将引用模块 @babel/runtime
,以避免在编译后的输出中出现重复。 运行时将被编译到您的构建中。
此转换器的另一个目的是为您的代码创建一个沙盒环境。 如果您直接导入 core-js 或 @babel/polyfill 以及它提供的内置函数(如 Promise
、Set
和 Map
),则这些函数会污染全局作用域。 虽然这对于应用程序或命令行工具来说可能没问题,但如果您的代码是一个库,您打算将其发布供其他人使用,或者您无法完全控制代码运行的环境,那么这将成为一个问题。
转换器会将这些内置函数别名为 core-js
,因此您可以无缝使用它们,而无需 require polyfill。
有关此工作原理和发生的转换类型的更多信息,请参见技术细节部分。
用法
使用配置文件(推荐)
无选项
{
"plugins": ["@babel/plugin-transform-runtime"]
}
带选项(及其默认值)
{
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": false,
"helpers": true,
"regenerator": true,
"version": "7.0.0-beta.0"
}
]
]
}
该插件默认假设所有可填充 API 都将由用户提供。 否则,需要指定 corejs
选项。
通过 CLI
babel --plugins @babel/plugin-transform-runtime script.js
通过 Node API
require("@babel/core").transformSync("code", {
plugins: ["@babel/plugin-transform-runtime"],
});
选项
corejs
false
、2
、3
或 { 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 选项 | 安装命令 |
---|---|
false | npm install --save @babel/runtime |
2 | npm install --save @babel/runtime-corejs2 |
3 | npm install --save @babel/runtime-corejs3 |
helpers
boolean
,默认为 true
。
切换是否将内联 Babel 辅助函数(classCallCheck
、extends
等)替换为对 @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/runtime
的 package.json
使用 "exports"
选项来自动在 CJS 和 ESM 辅助函数之间进行选择。
boolean
,默认为 false
。
历史
版本 | 更改 |
---|---|
v7.13.0 | 此选项已被弃用 |
启用后,转换将使用不会通过 @babel/plugin-transform-modules-commonjs
运行的辅助函数。 这允许在 webpack 等模块系统中进行更小的构建,因为它不需要保留 commonjs 语义。
例如,以下是禁用 useESModules
的 classCallCheck
辅助函数
exports.__esModule = true;
exports.default = function(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
};
以及启用它
export default function(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
absoluteRuntime
boolean
或 string
,默认为 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]
,则可以使用以下命令转换代码
{
"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
选项切换)。
但这实际上意味着什么呢? 基本上,你可以使用内置函数,例如 Promise
、Set
、Symbol
等,以及使用所有需要 polyfill 的 Babel 功能,而不会造成全局污染,使其非常适合库。
确保将 @babel/runtime
作为依赖项包含在项目中。
Regenerator 别名
每当你使用生成器函数或异步函数时
function* foo() {}
会生成以下代码
"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
转换器,它会被编译为
"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
别名
有时你可能想使用新的内置函数,例如 Map
、Set
、Promise
等。通常,使用这些函数的唯一方法是包含一个会污染全局作用域的 polyfill。
这是使用 corejs
选项实现的。
该插件将以下代码
var sym = Symbol();
var promise = Promise.resolve();
var check = arr.includes("yeah!");
console.log(arr[Symbol.iterator]());
转换为以下代码
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
转换器将所有辅助函数调用替换为模块。
这意味着以下代码
class Person {}
通常会转换为
"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
转换器会将其转换为
"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);
};