Help us understand the problem. What is going on with this article?

Babel 7 の主な変更点まとめ

More than 1 year has passed since last update.

2019/06/21 追記

記事内容を Babel 7.4.0 に対応したものに更新しました。

主に追記した箇所は以下に関してです。

はじめに

今更ですが、Babel 7 の主な変更点をまとめた備忘録です。

ほとんどの内容は公式ドキュメントである「Upgrade to Babel 7 」と「Usage Guide」を参考にしているため、既にこちらを読んで理解した方々には不要な記事だと思います。

また、普段 Babel と webpack を併用しているため、Babel CLI や.babelrcなどに関しては触れません。

記事本文でも紹介しますが、Babel 7 にマイグレーションしたサンプル(webpack と併用)は GitHub に置いてあります。

hira777/webpack-with-babel7

本記事での「プロポーザル」の定義

以下のような意味があるが

  • ECMAScript の新たな仕様として提案された機能
  • ECMAScript の新たな仕様として提案され、策定中の機能
  • ECMAScript の新たな仕様として追加する機能の提案書

本記事では「(ECMAScript の新たな仕様として提案され、)策定中の機能」ぐらいな認識で問題ない。

そのため、以下の言葉の意味は大体同じ。

  • 「Stage 4 未満のプロポーザル」 = 「Stage 4 未満の策定中の機能」

プロポーザルや Stage などをより詳しく知りたい方は以下を参照。

目次

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-jsregenerator-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-envuseBuiltInsという設定を利用し、必要な polyfill のみを import できる。

以下はそのサンプル(webpack と併用)。

hira777/webpack-with-babel7

サンプルの babel.config.js で指定している Babel の設定は以下の通り。

babel.config.js
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 は以下の通り。

src/app.js
[1, 2, 3].includes(2);

利用されているArray.prototype.includes()は、Edge 14 からサポートされている。

今回、targetsedge: '13'を指定しているため、Edge 13 をサポートするためにArray.prototype.includes()の polyfill が import される。

上記のように Babel の設定をすれば、import '@babel/polyfill';import 'regenerator-runtime/runtime';を記述せずに polyfill を import できるが、core-jsregenerator-runtime自体はインストールしておく必要があるので注意する。

Stage 4 未満のプロポーザルの polyfill も import する(Babel 7.4.0 から)

Babel 7.4.0 から、@babel/preset-envuseBuiltInsで、Stage 4 未満のプロポーザルの polyfill も import できるようになった。

以下のようにcorejs: { version: 3, proposals: true }を指定すれば Stage 4 未満のプロポーザルの polyfill も import される。

babel.config.js
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を利用した場合と@babel/preset-envcore-js@3を利用した場合で import される polyfill が異なる時がある

たとえば、targetsedge: '18'を指定して、以下のようなPromise.prototype.finally()が含まれるコードをトランスパイルすると

Promise.resolve().finally();

@babel/preset-env@babel/polyfillを利用した場合はPromise.prototype.finally()の polyfill が import されないが、@babel/preset-envcore-js@3core-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-envuseBuiltInsの利用方法

上記を理解すれば、とりあえず Babel 7 へのマイグレーションはできると思います。

変更点をより詳しく知りたい方は以下をご参照ください。

soarflat
フロントエンドエンジニア🐶
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした