Babel 7 の主な変更点まとめ

## 2019/06/21 追記

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

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

- [`@babel/polyfill` が非推奨になった（Babel 7.4.0 から）](https://qiita.com/soarflat/items/21b8955f992bf7d38581#babelpolyfill-%E3%81%8C%E9%9D%9E%E6%8E%A8%E5%A5%A8%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9Fbabel-740-%E3%81%8B%E3%82%89)
- [`@babel/preset-env`の`useBuiltIns`を利用して、`core-js@3`から必要な polyfill のみを import できるようになった（Babel 7.4.0 から）](https://qiita.com/soarflat/items/21b8955f992bf7d38581#babelpreset-env-%E3%81%AE-usebuiltins-%E3%82%92%E5%88%A9%E7%94%A8%E3%81%97%E3%81%A6core-js3-%E3%81%8B%E3%82%89%E5%BF%85%E8%A6%81%E3%81%AA-polyfill-%E3%81%AE%E3%81%BF%E3%82%92-import-%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9Fbabel-740-%E3%81%8B%E3%82%89)
- [Stage 4 未満のプロポーザルの polyfill も import する（Babel 7.4.0 から）](https://qiita.com/soarflat/items/21b8955f992bf7d38581#stage-4-%E6%9C%AA%E6%BA%80%E3%81%AE%E3%83%97%E3%83%AD%E3%83%9D%E3%83%BC%E3%82%B6%E3%83%AB%E3%81%AE-polyfill-%E3%82%82-import-%E3%81%99%E3%82%8Bbabel-740-%E3%81%8B%E3%82%89)
- [（補足）`@babel/polyfill` と `core-js@3` で、「どのブラウザでどの polyfill を import する必要があるかを判別するために利用するデータ」が異なる](https://qiita.com/soarflat/items/21b8955f992bf7d38581#%E8%A3%9C%E8%B6%B3babelpolyfill-%E3%81%A8-core-js3-%E3%81%A7%E3%81%A9%E3%81%AE%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%A7%E3%81%A9%E3%81%AE-polyfill-%E3%82%92-import-%E3%81%99%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8B%E3%81%8B%E3%82%92%E5%88%A4%E5%88%A5%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%8C%E7%95%B0%E3%81%AA%E3%82%8B)

## はじめに

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

ほとんどの内容は公式ドキュメントである「[Upgrade to Babel 7](https://babeljs.io/docs/en/v7-migration) 」と「[Usage Guide](https://babeljs.io/docs/en/usage)」を参考にしているため、既にこちらを読んで理解した方々には不要な記事だと思います。

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

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

[hira777/webpack-with-babel7](https://github.com/hira777/webpack-with-babel7)

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

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

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

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

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

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

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

- [ECMAScript の仕様/プロポーザルの調べ方を知る](https://efcl.info/2018/03/07/ecmascript-usage/)
- [ES.next と策定プロセス · ECMAScript とは何か？](https://azu.github.io/slide-what-is-ecmascript/slide/10.html)

## 目次

- [yearly presets は非推奨になった](https://qiita.com/soarflat/items/21b8955f992bf7d38581#yearly-presets-%E3%81%AF%E9%9D%9E%E6%8E%A8%E5%A5%A8%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F)
- [stage-x presets は非推奨になった](https://qiita.com/soarflat/items/21b8955f992bf7d38581#stage-x-presets-%E3%81%AF%E9%9D%9E%E6%8E%A8%E5%A5%A8%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F)
- [babel-upgrade を利用して Babel 7 へのアップグレードを自動で行える（環境によっては完全にアップグレードできるわけではない）](https://qiita.com/soarflat/items/21b8955f992bf7d38581#babel-upgrade-%E3%82%92%E5%88%A9%E7%94%A8%E3%81%97%E3%81%A6-babel-7-%E3%81%B8%E3%81%AE%E3%82%A2%E3%83%83%E3%83%97%E3%82%B0%E3%83%AC%E3%83%BC%E3%83%89%E3%82%92%E8%87%AA%E5%8B%95%E3%81%A7%E8%A1%8C%E3%81%88%E3%82%8B%E7%92%B0%E5%A2%83%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6%E3%81%AF%E5%AE%8C%E5%85%A8%E3%81%AB%E3%82%A2%E3%83%83%E3%83%97%E3%82%B0%E3%83%AC%E3%83%BC%E3%83%89%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%8F%E3%81%91%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84)
- [`babylon`がリネームされた](https://qiita.com/soarflat/items/21b8955f992bf7d38581#babylon-%E3%81%8C%E3%83%AA%E3%83%8D%E3%83%BC%E3%83%A0%E3%81%95%E3%82%8C%E3%81%9F)
- [多くのパッケージの提供が Scoped Packages に変更された](https://qiita.com/soarflat/items/21b8955f992bf7d38581#%E5%A4%9A%E3%81%8F%E3%81%AE%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E6%8F%90%E4%BE%9B%E3%81%8C-scoped-packages-%E3%81%AB%E5%A4%89%E6%9B%B4%E3%81%95%E3%82%8C%E3%81%9F)
- [Stage 4 未満のプロポーザルのパッケージがリネームされた](https://qiita.com/soarflat/items/21b8955f992bf7d38581#stage-4-%E6%9C%AA%E6%BA%80%E3%81%AE%E3%83%97%E3%83%AD%E3%83%9D%E3%83%BC%E3%82%B6%E3%83%AB%E3%81%AE%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%8C%E3%83%AA%E3%83%8D%E3%83%BC%E3%83%A0%E3%81%95%E3%82%8C%E3%81%9F)
- [パッケージ名から ECMASCript の Edition は削除された](https://qiita.com/soarflat/items/21b8955f992bf7d38581#%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E5%90%8D%E3%81%8B%E3%82%89-ecmascript-%E3%81%AE-edition-%E3%81%AF%E5%89%8A%E9%99%A4%E3%81%95%E3%82%8C%E3%81%9F)
- [`@babel/polyfill` が非推奨になった（Babel 7.4.0 から）](https://qiita.com/soarflat/items/21b8955f992bf7d38581#babelpolyfill-%E3%81%8C%E9%9D%9E%E6%8E%A8%E5%A5%A8%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9Fbabel-740-%E3%81%8B%E3%82%89)
- [`@babel/preset-env`の`useBuiltIns`を利用して、`core-js@3`から必要な polyfill のみを import できるようになった（Babel 7.4.0 から）](https://qiita.com/soarflat/items/21b8955f992bf7d38581#babelpreset-env-%E3%81%AE-usebuiltins-%E3%82%92%E5%88%A9%E7%94%A8%E3%81%97%E3%81%A6core-js3-%E3%81%8B%E3%82%89%E5%BF%85%E8%A6%81%E3%81%AA-polyfill-%E3%81%AE%E3%81%BF%E3%82%92-import-%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9Fbabel-740-%E3%81%8B%E3%82%89)
- [TypeScript のトランスパイルが可能になった](https://qiita.com/soarflat/items/21b8955f992bf7d38581#typescript%E3%81%AE%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B9%E3%83%91%E3%82%A4%E3%83%AB%E3%81%8C%E5%8F%AF%E8%83%BD%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F)

## 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`を利用する場合。

```bash
npm install --save-dev babel-preset-es2015
```

**Babel 7**

```bash
npm install --save-dev @babel/preset-env
```

## stage-x presets は非推奨になった

`preset-stage-0`などの stage-x presets は非推奨になった。

**Babel 6**

`preset-stage-1`を利用する場合。

```bash
npm install --save-dev babel-preset-stage-1
```

**Babel 7**

個別にプラグインをインストールする必要がある（以下は 2018-10-11 時点での Stege 1 のプラグイン）。

```bash
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](https://github.com/babel/babel-upgrade#todos)を利用すれば、Babel 7 へのアップグレードに伴う依存関係、設定ファイルや JavaScript ファイルをに自動的に更新できる。

例えば、以下のような`package.json`のある階層で`npx babel-upgrade --write`を実行すると

```json
{
  "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`が更新される。

```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`の更新は今後実装予定である。他にどのような機能を実装する予定なのかは[こちら](https://github.com/babel/babel-upgrade#todos)を参照。

## babylon がリネームされた

Babel で利用されている JavaScript のパーサーである`babylon`は`@babel/parser`にリネームされた。

## 多くのパッケージの提供が Scoped Packages に変更された

多くのパッケージは scoped packages として提供されるようになった。

つまり、`@babel/preset-env`のように`@babel/`（スコープ）がついて提供されるようになった。

そのため、様々なパッケージがリネームされており、`babel-cli` -> `@babel/cli`のように`babel-`がついていたパッケージは、基本的に`babel-`が`@babel/`に置き換わっている。

自分が利用しているパッケージがリネームされていないか確認した方が良い（大体リネームされているらしい）。

### リネームに伴い、コンフィグの記述も変更

以下はその例

**Babel 6**

```js
module.exports = {
  presets: ['preset-env'],
  plugins: ['plugin-transform-arrow-functions']
};
```

以下のようにショートハンド（`preset-`や`plugin-`の短縮）も利用できた。

```js
module.exports = {
  presets: ['env'],
  plugins: ['transform-arrow-functions']
};
```

**Babel 7**

```js
module.exports = {
  presets: ['@babel/preset-env'],
  plugins: ['@babel/plugin-transform-arrow-functions']
};
```

ショートハンド（`preset-`や`plugin-`の短縮）は引き続き利用できるが、`@babel/`の指定は必須。

```js
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](https://github.com/tc39/proposal-object-rest-spread)が`@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](https://babeljs.io/docs/en/next/babel-polyfill.html)のページから抜粋したもの。

> 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**

```js
import '@babel/polyfill';
```

**Babel 7.4.0**

```js
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 されてしまい、トランスパイル後のファイルサイズが非常に大きくなってしまう。

```js
import 'core-js/stable';
import 'regenerator-runtime/runtime';
```

Babel 7.4.0 では`@babel/preset-env`の`useBuiltIns`という設定を利用し、必要な polyfill のみを import できる。

以下はそのサンプル（webpack と併用）。

[hira777/webpack-with-babel7](https://github.com/hira777/webpack-with-babel7)

サンプルの [babel.config.js](https://github.com/hira777/webpack-with-babel7/blob/master/babel.config.js) で指定している Babel の設定は以下の通り。

```js: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](https://github.com/hira777/webpack-with-babel7/blob/master/src/app.js) は以下の通り。

```js: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 される。

```js: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 される。

```js
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](https://github.com/kangax/compat-table)
- `@babel/preset-env`+`core-js@3`: [core-js-compat](https://github.com/zloirock/core-js/tree/master/packages/core-js-compat)

そのため、**`@babel/preset-env`と`@babel/polyfill`を利用した場合と`@babel/preset-env`と`core-js@3`を利用した場合で import される polyfill が異なる時がある**。

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

```js
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](https://github.com/kangax/compat-table)だと細かい点で不備があり、完全に正しいわけではないから（らしい）。

くわしくは[こちら](https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md#babelpreset-env)を参照。

#### 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 の開発環境を構築する](https://qiita.com/soarflat/items/d583356e46250a529ed5)

## 終わり

本記事で記載した変更点は、ざっくり分類すれば以下の通りです。

- 様々なパッケージがリネームされた
- `@babel/polyfill`の変更点
- `@babel/preset-env`の`useBuiltIns`の利用方法

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

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

- [Upgrade to Babel 7](https://babeljs.io/docs/en/v7-migration)

## お知らせ

Udemy で webpack の講座を公開したり、Kindle で技術書を出版しています。

Udemy:
[webpack 最速入門](https://www.udemy.com/course/practical-webpack/?couponCode=B6D5AE3897554CBBDAD7)（**~~10,800 円~~ -> 2,000 円**）

Kindle（Kindle Unlimited だったら無料）:
[React Hooks 入門](https://www.amazon.co.jp/gp/product/B08JTXQ2M6)（500 円）

興味を持ってくださった方はご購入いただけると大変嬉しいです。よろしくお願いいたします。