コンパイラの前提事項
デフォルトでは、Babelはネイティブの動作にできる限り一致するようにコードをコンパイルしようとします。しかし、これは、気にしないエッジケースをサポートするためだけに、より多くの出力コードを生成したり、出力コードが遅くなったりすることを意味する場合があります。
Babel 7.13.0以降では、設定でassumptions
オプションを指定して、コンパイル結果をより最適化するために、Babelがコードに関してどのような前提を置けるかを伝えることができます。注意: これは、複数のプラグインに適用できるトップレベルオプションを優先して、プラグインのさまざまなloose
オプションを置き換えます(RFCリンク)。
例:
{
"targets": ">0.5%",
"assumptions": {
"noDocumentAll": true,
"noClassCalls": true
},
"presets": ["@babel/preset-env"]
}
これは高度な機能です。前提を有効にする場合は注意してください。これらは仕様に準拠しておらず、予期しない方法でコードを破損させる可能性があります。
@babel/preset-env
のloose
およびspec
オプションから、細かい前提事項への移行を検討していますか?「@babel/preset-env
の"loose"
および"spec"
モードからの移行」で、コピーして貼り付けるだけで開始できる、同等の前提ベースの設定を確認してください。
arrayLikeIsIterable
配列のようなオブジェクトをスプレッドまたは反復処理する場合、ネイティブのArray.prototype[Symbol.iterator]
と同じ動作をする[Symbol.iterator]
メソッドを実装していると仮定し、したがって、インデックスによって直接要素を反復処理します。
たとえば、これは古いブラウザでDOMコレクションを反復処理するのに役立ちます。
let images = $("img");
for (const img of images) {
console.log(img);
}
const copy = [...images];
constantReexports
モジュールからバインディングを再エクスポートする場合、変更されないと仮定して、次のように直接エクスポートしても安全です。
import { value as val } from "dep";
export const value = val;
注: これは、transform-modules-umd
およびtransform-modules-amd
プラグインにも影響します。
export { value } from "dependency";
constantSuper
クラスのスーパークラスはObject.setPrototypeOf
を使用していつでも変更できるため、Babelが静的にそれを知ることは不可能です。このオプションが有効になっている場合、Babelは変更されないと仮定し、したがって、クラス宣言のextends
句に配置された値が常に使用されます。
class Child extends Base {
method() {
super.method(2);
}
}
enumerableModuleMeta
ESMをCJSにコンパイルするとき、Babelはmodule.exports
オブジェクトに__esModule
プロパティを定義します。for..in
またはObject.keys
を使用してmodule.exports
またはrequire("your-module")
のキーを反復処理しないと仮定し、したがって、__esModule
を列挙可能として定義しても安全です。
export const number = 2;
ignoreFunctionLength
関数には、最後の非デフォルトパラメーターまでのパラメーター数を反映する.length
プロパティがあります。このオプションが有効になっている場合、コンパイルされたコードがこの.length
プロパティに依存しないと仮定します。
function fn(a, b = 2, c, d = 3) {
return a + b + c + d;
}
ignoreToPrimitiveHint
オブジェクトの[Symbol.toPrimitive]
メソッドを呼び出す可能性がある言語機能を使用する場合、hint
パラメーターに基づいて動作を変更しないと仮定します。
let str = `a${foo}b`;
iterableIsArray
反復可能なオブジェクト(配列の分割代入、for-of、またはスプレッド)を使用する場合、それが配列であると仮定します。
const [first, ...rest] = obj;
call(first, ...obj);
let arr = [first, ...obj];
for (const el of obj) {
console.log(el);
}
mutableTemplateObject
タグ付きテンプレートリテラルのために作成されたテンプレートオブジェクトにObject.freeze
を使用しないでください。これは、事実上taggedTemplateLiteral
の代わりにtaggedTemplateLiteralLoose
ヘルパーを使用することを意味します。
let str = tag`a`;
noClassCalls
クラスを変換するとき、常にnew
でインスタンス化され、関数として呼び出されることはないと仮定します。
class Test {
constructor() {
this.x = 2;
}
}
noDocumentAll
null
またはundefined
を確認する演算子を使用する場合、特別な値document.all
では使用されないと仮定します。
let score = points ?? 0;
let name = user?.name;
noIncompleteNsImportDetection
モジュールエクスポートオブジェクトの独自のプロパティは初期化前に観察されないと仮定します。たとえば、ns.foo
にアクセスしようとすると、この前提をオンまたはオフにしても、undefined
が返されます。違いは、noIncompleteNsImportDetection: true
の場合、Object.prototype.hasOwnProperty.call(ns, "foo")
がfalse
を返すことです。
export var foo;
noNewArrows
コードが仕様に従って許可されていないnew
を使用してアロー関数をインスタンス化しようとしないと仮定します。
注: この前提は、デフォルトでtrue
です。Babel 8からは、デフォルトでfalse
になります。
let getSum = (a, b) => {
return { sum: a + b }
};
noUninitializedPrivateFieldAccess
履歴
バージョン | 変更点 |
---|---|
v7.24.0 | noUninitializedPrivateFieldAccess の前提を追加 |
コードが初期化される前にクラスのプライベートフィールドにアクセスしようとしないと仮定します。例:
class Foo {
x = this.#y; // #y is not initialized yet
#y = 2;
}
class MyClass {
static #id = 123;
method() {
return MyClass.#id;
}
}
objectRestNoSymbols
オブジェクトの分割代入でrestパターンを使用する場合、分割代入されたオブジェクトにシンボルキーがないか、コピーされない場合に問題がないと仮定します。
let { name, ...attrs } = obj;
privateFieldsAsProperties
プライベートフィールドには「ソフトプライバシー」で十分であると仮定し、したがって、外部のWeakMap
を使用するのではなく、一意の名前を持つパブリックな非列挙可能なプロパティとして保存できます。これにより、コンパイルされたプライベートフィールドのデバッグが容易になります。
class Foo {
#method() {}
#field = 2;
run() {
this.#method();
this.#field++;
}
}
インラインBabelヘルパーを使用する場合、生成された文字列キーはファイルごとに一意であり、グローバルではありません。これにより、同じ名前のプライベートフィールドを持つ異なるフィールドからクラスを拡張する場合に競合が発生する可能性があります。
privateFieldsAsSymbols
履歴
バージョン | 変更点 |
---|---|
v7.21.0 | privateFieldsAsSymbols の前提を追加 |
プライベートフィールドには「ソフトプライバシー」で十分であると仮定し、したがって、(外部のWeakMap
を使用するのではなく)シンボルキーを持つパブリックプロパティとして保存できます。これにより、コンパイルされたプライベートフィールドのデバッグが容易になります。
class Foo {
#method() {}
#field = 2;
run() {
this.#method();
this.#field++;
}
}
pureGetters
ゲッターが存在する場合、副作用がなく、複数回アクセスできると仮定します。
let a = obj;
a.b?.();
setClassMethods
クラスを宣言する場合、メソッドがスーパークラスプロトタイプのアクセサーまたは書き込み不可のプロパティをシャドウしないこと、およびプログラムが列挙不可能なメソッドに依存しないと仮定します。したがって、Object.defineProperty
を使用するのではなく、メソッドを代入しても安全です。
class Foo extends Bar {
method() {}
static check() {}
}
setComputedProperties
計算されたオブジェクトプロパティを使用する場合、オブジェクトに同じオブジェクトで定義されたセッターを上書きするプロパティが含まれていないと仮定し、したがって、Object.defineProperty
を使用して定義するのではなく、それらを代入しても安全です。
let obj = {
set name(value) {},
[key]: val
}
setPublicClassFields
パブリッククラスフィールドを使用する場合、現在のクラス、サブクラス、またはスーパークラスのゲッターをシャドウしないと仮定します。したがって、Object.defineProperty
を使用するのではなく、それらを代入しても安全です。
class Test {
field = 2;
static staticField = 3;
}
setSpreadProperties
オブジェクトのスプレッドを使用する場合、スプレッドされたプロパティがターゲットオブジェクトのゲッターをトリガーしないと仮定し、したがって、Object.defineProperty
を使用して定義するのではなく、それらを代入しても安全です。
const result = {
set name(value) {},
...obj,
};
skipForOfIteratorClosing
イテレーターでfor-of
を使用する場合、エラーが発生した場合は、常に.return()
と.throw()
で閉じる必要があります。このオプションが呼び出されると、Babelはこれらのメソッドが定義されていないか空であると仮定し、それらを呼び出すことを回避します。
for (const val of iterable) {
console.log(val);
}
superIsCallableConstructor
クラスを拡張する際、スーパークラスは呼び出し可能であると想定してください。これは、ネイティブクラスや組み込みクラスを拡張することはできず、コンパイル済みのクラスまたは ES5 の function
コンストラクターのみを拡張できることを意味します。
class Child extends Parent {
constructor() {
super(42);
}
}
@babel/preset-env
の "loose"
および "spec"
モードからの移行
@babel/preset-env
の loose
オプションは、以下の構成と同等です。
{
"presets": [
["@babel/preset-env", { "exclude": ["transform-typeof-symbol"] }]
],
"assumptions": {
"arrayLikeIsIterable": true,
"constantReexports": true,
"ignoreFunctionLength": true,
"ignoreToPrimitiveHint": true,
"mutableTemplateObject": true,
"noClassCalls": true,
"noDocumentAll": true,
"noObjectSuper": true,
"noUndeclaredVariablesCheck": true,
"objectRestNoSymbols": true,
"privateFieldsAsProperties": true,
"pureGetters": true,
"setClassMethods": true,
"setComputedProperties": true,
"setPublicClassFields": true,
"setSpreadProperties": true,
"skipForOfIteratorClosing": true,
"superIsCallableConstructor": true
}
}
@babel/preset-env
の spec
オプションは、以下の構成と同等です。
{
"presets": ["@babel/preset-env"],
"assumptions": {
"noNewArrows": false,
}
}