@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
を参照します。ランタイムはビルドにコンパイルされます.
このトランスフォーマーのもう1つの目的は、コードのサンドボックス化された環境を作成することです。core-js または @babel/polyfill と、それが提供する Promise
、Set
、Map
などのビルトインを直接インポートすると、グローバルスコープが汚染されます。これはアプリやコマンドラインツールでは問題ありませんが、コードが他の人が使用するために公開することを意図したライブラリである場合、またはコードが実行される環境を正確に制御できない場合は問題になります。
トランスフォーマーはこれらのビルトインを core-js
にエイリアスするため、ポリフィルを要求することなくシームレスに使用できます。
この仕組みと発生する変換の種類の詳細については、技術的な詳細セクションを参照してください。
使用方法
設定ファイルを使用する(推奨)
オプションなし
{
"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
です。
ジェネレーター関数が、グローバルスコープを汚染しないリジェネレーターランタイムを使用するように変換されるかどうかを切り替えます。
詳細については、リジェネレーターエイリアシングを参照してください。
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
を介して実行されないヘルパーを使用します。これにより、commonjsセマンティクスを保持する必要がないため、webpackなどのモジュールシステムでのビルドサイズが小さくなります。
例として、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/runtime@7.0.0
がインストールされていると想定しています。@babel/runtime
の新しいバージョン(または対応するcorejs、例:@babel/runtime-corejs3
)がインストールされているか、依存関係としてリストされている場合、transform-runtimeはより高度な機能を使用できます。
たとえば、@babel/runtime-corejs2@7.7.4
に依存している場合、次のコードでトランスパイルできます。
{
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": 2,
"version": "^7.7.4"
}
]
]
}
これにより、バンドルサイズが小さくなります。
技術的な詳細
transform-runtime
トランスフォーマープラグインは3つのことを行います。
- ジェネレーター/非同期関数を使用すると、自動的に
@babel/runtime/regenerator
を要求します(regenerator
オプションで切り替え可能)。 - 必要に応じて、ユーザーによってポリフィルされると想定する代わりに、ヘルパーに
core-js
を使用できます(corejs
オプションで切り替え可能)。 - インラインBabelヘルパーを自動的に削除し、代わりにモジュール
@babel/runtime/helpers
を使用します(helpers
オプションで切り替え可能)。
これは実際にはどういう意味でしょうか?基本的には、Promise
、Set
、Symbol
などの組み込み関数を使用できるだけでなく、ポリフィルを必要とするすべての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
などの新しい組み込み関数を使用したい場合があります。これらを使用する唯一の方法は、通常、グローバルに汚染するポリフィルを含めることです。
これは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);
};