2019/06/21 追記
記事内容を Babel 7.4.0 に対応したものに更新しました。
主に追記した箇所は以下に関してです。
@babel/polyfill
が非推奨になった(Babel 7.4.0 から)@babel/preset-env
のuseBuiltIns
を利用して、core-js@3
から必要な polyfill のみを import できるようになった(Babel 7.4.0 から)- Stage 4 未満のプロポーザルの polyfill も import する(Babel 7.4.0 から)
- (補足)
@babel/polyfill
とcore-js@3
で、「どのブラウザでどの polyfill を import する必要があるかを判別するために利用するデータ」が異なる
はじめに
今更ですが、Babel 7 の主な変更点をまとめた備忘録です。
ほとんどの内容は公式ドキュメントである「Upgrade to Babel 7 」と「Usage Guide」を参考にしているため、既にこちらを読んで理解した方々には不要な記事だと思います。
また、普段 Babel と webpack を併用しているため、Babel CLI や.babelrc
などに関しては触れません。
記事本文でも紹介しますが、Babel 7 にマイグレーションしたサンプル(webpack と併用)は GitHub に置いてあります。
本記事での「プロポーザル」の定義
以下のような意味があるが
- ECMAScript の新たな仕様として提案された機能
- ECMAScript の新たな仕様として提案され、策定中の機能
- ECMAScript の新たな仕様として追加する機能の提案書
本記事では「(ECMAScript の新たな仕様として提案され、)策定中の機能」ぐらいな認識で問題ない。
そのため、以下の言葉の意味は大体同じ。
- 「Stage 4 未満のプロポーザル」 = 「Stage 4 未満の策定中の機能」
プロポーザルや Stage などをより詳しく知りたい方は以下を参照。
目次
- yearly presets は非推奨になった
- stage-x presets は非推奨になった
- babel-upgrade を利用して Babel 7 へのアップグレードを自動で行える(環境によっては完全にアップグレードできるわけではない)
babylon
がリネームされた- 多くのパッケージの提供が Scoped Packages に変更された
- Stage 4 未満のプロポーザルのパッケージがリネームされた
- パッケージ名から ECMASCript の Edition は削除された
@babel/polyfill
が非推奨になった(Babel 7.4.0 から)@babel/preset-env
のuseBuiltIns
を利用して、core-js@3
から必要な polyfill のみを import できるようになった(Babel 7.4.0 から)- TypeScript のトランスパイルが可能になった
yearly presets は非推奨になった
以下のような yearly presets は非推奨になった(Babel 6 から非推奨だった気がするが、一応記載)。
babel-preset-es2015
babel-preset-es2016
babel-preset-es2017
babel-preset-latest
そのため preset は@babel/preset-env
を利用する。
Babel 6
babel-preset-es2015
を利用する場合。
npm install --save-dev babel-preset-es2015
Babel 7
npm install --save-dev @babel/preset-env
stage-x presets は非推奨になった
preset-stage-0
などの stage-x presets は非推奨になった。
Babel 6
preset-stage-1
を利用する場合。
npm install --save-dev babel-preset-stage-1
Babel 7
個別にプラグインをインストールする必要がある(以下は 2018-10-11 時点での Stege 1 のプラグイン)。
npm install --save-dev @babel/plugin-proposal-export-default-from @babel/plugin-proposal-logical-assignment-operators @babel/plugin-proposal-optional-chaining @babel/plugin-proposal-pipeline-operator @babel/plugin-proposal-nullish-coalescing-operator @babel/plugin-proposal-do-expressions
babel-upgrade を利用して Babel 7 へのアップグレードを自動で行える(環境によっては完全にアップグレードできるわけではない)
babel-upgradeを利用すれば、Babel 7 へのアップグレードに伴う依存関係、設定ファイルや JavaScript ファイルをに自動的に更新できる。
例えば、以下のようなpackage.json
のある階層でnpx babel-upgrade --write
を実行すると
{
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.4",
"babel-preset-env": "^1.7.0",
"babel-preset-stage-1": "^6.24.1"
}
}
以下のようにpackage.json
が更新される。
{
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/plugin-proposal-decorators": "^7.0.0",
"@babel/plugin-proposal-do-expressions": "^7.0.0",
"@babel/plugin-proposal-export-default-from": "^7.0.0",
"@babel/plugin-proposal-export-namespace-from": "^7.0.0",
"@babel/plugin-proposal-function-sent": "^7.0.0",
"@babel/plugin-proposal-json-strings": "^7.0.0",
"@babel/plugin-proposal-logical-assignment-operators": "^7.0.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0",
"@babel/plugin-proposal-numeric-separator": "^7.0.0",
"@babel/plugin-proposal-optional-chaining": "^7.0.0",
"@babel/plugin-proposal-pipeline-operator": "^7.0.0",
"@babel/plugin-proposal-throw-expressions": "^7.0.0",
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
"@babel/plugin-syntax-import-meta": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"babel-loader": "^8.0.0"
}
}
現時点では、webpack.config.js
などの設定ファイルは更新されないため、開発環境によっては babel-upgrade を利用してもアップグレードを完全に行えない可能性もあるため注意。
webpack.config.js
の更新は今後実装予定である。他にどのような機能を実装する予定なのかはこちらを参照。
babylon がリネームされた
Babel で利用されている JavaScript のパーサーであるbabylon
は@babel/parser
にリネームされた。
多くのパッケージの提供が Scoped Packages に変更された
多くのパッケージは scoped packages として提供されるようになった。
つまり、@babel/preset-env
のように@babel/
(スコープ)がついて提供されるようになった。
そのため、様々なパッケージがリネームされており、babel-cli
-> @babel/cli
のようにbabel-
がついていたパッケージは、基本的にbabel-
が@babel/
に置き換わっている。
自分が利用しているパッケージがリネームされていないか確認した方が良い(大体リネームされているらしい)。
リネームに伴い、コンフィグの記述も変更
以下はその例
Babel 6
module.exports = {
presets: ['preset-env'],
plugins: ['plugin-transform-arrow-functions']
};
以下のようにショートハンド(preset-
やplugin-
の短縮)も利用できた。
module.exports = {
presets: ['env'],
plugins: ['transform-arrow-functions']
};
Babel 7
module.exports = {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-transform-arrow-functions']
};
ショートハンド(preset-
やplugin-
の短縮)は引き続き利用できるが、@babel/
の指定は必須。
module.exports = {
presets: ['@babel/env'],
plugins: ['@babel/transform-arrow-functions']
};
ショートハンドは便利だが、パッケージ名をフルで書いた方が何のパッケージを利用しているのかを確実且つ即座に理解できる。
全員がショートハンドを利用できることを知っているわけではないため、チーム開発などの時は認識合わせをした方が良いかもしれない。
Stage 4 未満のプロポーザルのパッケージがリネームされた
Stage 4 未満のプロポーザルのパッケージは以下のように-proposal-
が付いたものにリネームされた。
-
@babel/plugin-transform-function-bind
(Stage 0) ->@babel/plugin-proposal-function-bind
-
@babel/plugin-transform-class-properties
(Stage 3) ->@babel/plugin-proposal-class-properties
プロポーザルの Stage が 4 に移行したら、パッケージ名がリネームされるので留意しておく。
(と書いておきながら、Stage 4 であるObject Rest/Spread Propertiesが@babel/plugin-proposal-object-rest-spread
で提供されているので、ドキュメントを読み間違えているかもしれない。)
パッケージ名から ECMASCript の Edition は削除された
いくつかのプラグインは名前に-es3-
、または-es2015-
が付いていたが、以下のように削除された。
-
@babel/plugin-transform-es2015-classes
->@babel/plugin-transform-classes
@babel/polyfill が非推奨になった(Babel 7.4.0 から)
以下は@babel/polyfillのページから抜粋したもの。
As of Babel 7.4.0, this package has been deprecated in favor of directly including core-js/stable (to polyfill ECMAScript features) and regenerator-runtime/runtime (needed to use transpiled generator functions):
そのため、@babel/polyfill
の代わりに、core-js
とregenerator-runtime/runtime
を利用する。
Babel 7
import '@babel/polyfill';
Babel 7.4.0
import 'core-js/stable';
import 'regenerator-runtime/runtime';
core-js
は@babel/polyfill
も利用している polyfill。利用が推奨されているのは v3 で@babel/polyfill
が利用しているのは v2。
regenerator-runtime
は async/await を利用するために必要な polyfill。
@babel/preset-env の useBuiltIns を利用して、core-js@3 から必要な polyfill のみを import できるようになった(Babel 7.4.0 から)
以下のようにcore-js
などを import すると、利用していない不要な polyfill も import されてしまい、トランスパイル後のファイルサイズが非常に大きくなってしまう。
import 'core-js/stable';
import 'regenerator-runtime/runtime';
Babel 7.4.0 では@babel/preset-env
のuseBuiltIns
という設定を利用し、必要な polyfill のみを import できる。
以下はそのサンプル(webpack と併用)。
サンプルの babel.config.js で指定している Babel の設定は以下の通り。
module.exports = function(api) {
api.cache(true);
const presets = [
[
// プリセットに @babel/preset-env を指定する
'@babel/preset-env',
{
// サポートするブラウザ、この設定に応じて、必要な polyfill のみが import される
targets: {
edge: '13'
},
// 必要な polyfill のみを import させたい場合、'usage'を指定する(必須)
useBuiltIns: 'usage',
// polyfill を利用する core-js のバージョンを指定する(指定しないとバージョン2が利用され警告が出力される)
corejs: 3,
// trueにすると利用しているポリフィルなどの情報が出力される
// polyfill が import されているかどうかを確認するためのものなので必須ではない
debug: true
}
]
];
return {
presets
};
};
targets
で指定したブラウザをサポートするために必要な polyfill が import される。useBuiltIns: 'usage'
とcorejs: 3
の指定は必須。
また、エントリーポイントである src/app.js は以下の通り。
[1, 2, 3].includes(2);
利用されているArray.prototype.includes()
は、Edge 14 からサポートされている。
今回、targets
でedge: '13'
を指定しているため、Edge 13 をサポートするためにArray.prototype.includes()
の polyfill が import される。
上記のように Babel の設定をすれば、import '@babel/polyfill';import 'regenerator-runtime/runtime';
を記述せずに polyfill を import できるが、core-js
とregenerator-runtime
自体はインストールしておく必要があるので注意する。
Stage 4 未満のプロポーザルの polyfill も import する(Babel 7.4.0 から)
Babel 7.4.0 から、@babel/preset-env
のuseBuiltIns
で、Stage 4 未満のプロポーザルの polyfill も import できるようになった。
以下のようにcorejs: { version: 3, proposals: true }
を指定すれば Stage 4 未満のプロポーザルの polyfill も import される。
module.exports = function(api) {
api.cache(true);
const presets = [
[
// プリセットに @babel/preset-env を指定する
'@babel/preset-env',
{
// サポートするブラウザ、この設定に応じて、必要な polyfill のみが import される
targets: {
edge: '14'
},
// 必要な polyfill のみを import させたい場合、'usage'を指定する(必須)
useBuiltIns: 'usage',
// core-js のバージョンを指定する(指定しないとバージョン2が利用され警告が出力される)
// corejs: 3,
// Stage 4 未満のプロポーザルの polyfill も import される
corejs: { version: 3, proposals: true },
// trueにすると利用しているポリフィルなどの情報が出力される
// polyfill が import されているかどうかを確認するためのものなので必須ではない
debug: true
}
]
];
return {
presets
};
};
上記の状態で、以下のような Stage 2(2019/06/20 時点)のString.prototype.replaceAll
を利用したコードをトランスパイルすると、自動で polyfill が import される。
const queryString = 'q=query+string+parameters';
const withSpaces = queryString.replaceAll('+', ' ');
console.log(withSpaces); // => q=query string parameters
(補足)@babel/polyfill と core-js@3 で、「どのブラウザでどの polyfill を import する必要があるかを判別するために利用するデータ」が異なる
それぞれが利用するデータは以下の通り。
-
@babel/preset-env
+@babel/polyfill
: compat-table -
@babel/preset-env
+core-js@3
: core-js-compat
そのため、@babel/preset-env
と@babel/polyfill
を利用した場合と@babel/preset-env
とcore-js@3
を利用した場合で import される polyfill が異なる時がある。
たとえば、targets
にedge: '18'
を指定して、以下のようなPromise.prototype.finally()
が含まれるコードをトランスパイルすると
Promise.resolve().finally();
@babel/preset-env
と@babel/polyfill
を利用した場合はPromise.prototype.finally()
の polyfill が import されないが、@babel/preset-env
とcore-js@3
(core-js-compat
が v3.1.4 の時点)を利用した場合は Promise.prototype.finally()
の polyfill が import される。
そのため、「targets
の指定はそのままで@babel/preset-env
で利用する polyfill を@babel/polyfill
からcore-js@3
に変更してトランスパイルしたら、import される polyfill が無茶苦茶変わった...!!なぜ...!?」といった状況が発生する可能性はあるが、バグではない。
なぜ core-js@3 では core-js-compat を利用しているのか?
compat-tableだと細かい点で不備があり、完全に正しいわけではないから(らしい)。
くわしくはこちらを参照。
core-js-compat は常に最新のものを利用した方が良い(かもしれない)
現時点では core-js-compat が頻繁に更新されているため、バーションが上がると polyfill の import のされ方が結構異なる気がした。
そのため、常に最新の core-js-compat を利用した方が良い(かもしれない)。
TypeScript のトランスパイルが可能になった
@babel/preset-typescript
を利用して、TypeScript のトランスパイルが可能になった(型チェックはできないため、型チェックするためには TypeScript が必要)。
※トランスパイルの仕方は別の記事に書きましたので、こちらを参考にしてください。
webpack 4 + Babel 7 + TypeScript + TypeScript EsLint + Prettier の開発環境を構築する
終わり
本記事で記載した変更点は、ざっくり分類すれば以下の通りです。
- 様々なパッケージがリネームされた
-
@babel/polyfill
の変更点 -
@babel/preset-env
のuseBuiltIns
の利用方法
上記を理解すれば、とりあえず Babel 7 へのマイグレーションはできると思います。
変更点をより詳しく知りたい方は以下をご参照ください。
お知らせ
Udemy で webpack の講座を公開したり、Kindle で技術書を出版しています。
Udemy:
webpack 最速入門(10,800 円 -> 2,000 円)
Kindle(Kindle Unlimited だったら無料):
React Hooks 入門(500 円)
興味を持ってくださった方はご購入いただけると大変嬉しいです。よろしくお願いいたします。