メインコンテンツにスキップ

@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-envuseBuiltIns オプションを設定しないでください。設定した場合、このプラグインは環境を完全にサンドボックス化できない可能性があります。

理由

Babelは、_extend のような一般的な関数に非常に小さなヘルパーを使用します。デフォルトでは、これはそれを必要とするすべてのファイルに追加されます。この重複は、特にアプリケーションが複数のファイルに分散している場合、不要な場合があります。

ここで@babel/plugin-transform-runtime プラグインが登場します。すべてのヘルパーは、コンパイル済み出力全体での重複を避けるために、モジュール @babel/runtime を参照します。ランタイムはビルドにコンパイルされます.

このトランスフォーマーのもう1つの目的は、コードのサンドボックス化された環境を作成することです。core-js または @babel/polyfill と、それが提供する PromiseSetMap などのビルトインを直接インポートすると、グローバルスコープが汚染されます。これはアプリやコマンドラインツールでは問題ありませんが、コードが他の人が使用するために公開することを意図したライブラリである場合、またはコードが実行される環境を正確に制御できない場合は問題になります。

トランスフォーマーはこれらのビルトインを core-js にエイリアスするため、ポリフィルを要求することなくシームレスに使用できます。

この仕組みと発生する変換の種類の詳細については、技術的な詳細セクションを参照してください。

使用方法

オプションなし

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経由

シェル
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.0moduleName オプションを追加

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/runtimepackage.json"exports" オプションを使用して、CJSとESMヘルパーを自動的に選択します。

boolean、デフォルトは false です。

履歴
バージョン変更点
v7.13.0このオプションは非推奨になりました

有効にすると、変換は @babel/plugin-transform-modules-commonjs を介して実行されないヘルパーを使用します。これにより、commonjsセマンティクスを保持する必要がないため、webpackなどのモジュールシステムでのビルドサイズが小さくなります。

例として、useESModules が無効になっている場合の classCallCheck ヘルパーを次に示します

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

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に依存している場合、次のコードでトランスパイルできます。

babel.config.json
{
"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オプションで切り替え可能)。

これは実際にはどういう意味でしょうか?基本的には、PromiseSetSymbolなどの組み込み関数を使用できるだけでなく、ポリフィルを必要とするすべての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などの新しい組み込み関数を使用したい場合があります。これらを使用する唯一の方法は、通常、グローバルに汚染するポリフィルを含めることです。

これは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);
};