Babel 7 リリースプレビュー

いよいよ Babel 7 のリリースが近づいてきました。そこで、公式ブログから個人的に気になる変更点をまとめてみました :muscle: 。

*Nearing the 7.0 Release · Babel*
https://babeljs.io/blog/2017/12/27/nearing-the-7.0-release

![image.png](https://qiita-image-store.s3.amazonaws.com/0/104952/5ba5a121-53ce-c24f-af30-32e64a1e1c46.png)

# スコープ付きパッケージへの名前変更

個人的には、今回の Babel 7 で最大の変更点は、何と言ってもスコープ付きパッケージ方式（*scoped packages* [^1]）の採用だと考えます。簡単に言うと、パッケージ名が `babel-*`　から `@babel/*` に変更された、ということです。以下、例です。

- `babel-cli` -> `@babel/cli`
- `babel-core` -> `@babel/core`
- `babel-preset-env` -> `@babel/preset-env`

この変更により、`package.json` の修正が必要となります。[自動アップグレードツールを作ろうとする issue](https://github.com/babel/notes/issues/44) も上がっていますが、どうなるかは分かりません。手動で修正する場合は、次のようになるでしょう。

```diff:package.json
{
  "dependencies": {
-   "babel-core": "6.26.0"
+   "@babel/core": "7.0.0-beta.31"
  }
}
```

```diff:.babelrc
{
-  "presets": ["env"]
+  "presets": ["@babel/preset-env"]
}
```

変更の理由を、ブログより抜粋します（私訳ですので、読みづらい部分がありましたら遠慮なくリクエストください :bow: ）。

> - 名前付けは難しい: 他の誰かが自分のプラグインに私たちの命名規約を使うことを決めたかどうかを、私たちがチェックする必要はなくなります。
>
> - Naming is difficult: we won’t have to check if someone else decided to use our naming convention for their own plugin

---

> - 同様に、パッケージ不法占拠 [^2] [^3]
>    - ときどき人々は、それが面白いからという理由で `babel-preset-20xx` やその他のパッケージを作ります。そして、私たちはそれを戻してもらうようにお願いするために issue やメールを作らなければなりません。
>    - 人々は正当なパッケージをもちますが、私たちが呼びたかったものと同じ名前になることがあります。－ 人々は（オプショナル・チェイニング、パイプライン演算子といった）新しい提案がマージされるのを見て、フォークすることを決め、同じ名前でそのバージョンを公開します。それから、私たちが公開するとき、そのパッケージはすでに公開されていると私たちに伝えてきます 🤔 。このとき、私は彼らのメールアドレスを探し、彼らと npm サポートの両方にそのパッケージを戻して再公開してくれるようにメールしなければなりません。
>
> - Similarly, package squatting
>   - Sometimes people create `babel-preset-20xx` or some other package because it’s funny, and then we have to make an issue/email to ask for it back.
>   - People have a legit package, but it happens to be the same name as what we wanted to call it.  - People see that a new proposal is merging (like optional chaining, pipeline operator) and decide to fork and publish a version of it under the same name. Then, when we publish, it tell us the package was already published 🤔. Then, I have to find their email and email both them and npm support to get the package back and republish.

---

> - 「公式」パッケージとは何でしょうか、同じ名前をもつユーザー／コミュニティパッケージとは何でしょうか？私たちは間違った名前や非公式のパッケージを使っている人々から issue レポートを受けることがあります、なぜなら彼らはそれが Babel の一部であると考えたからです。これに関する例の一つは、`babel-env` が人々の `.babelrc` ファイルを書き換えていたというレポートです、彼らがそれは `babel-preset-env` ではないと気付くまでにしばらくかかりました。 [^4]
>
> - What is an “official” package and what is a user/community package with the same name? We can get issue reports of people using misnamed or unofficial packages because they assumed it was part of Babel. One example of this was a report that `babel-env` was rewriting their `.babelrc` file, and it took them a while to realize it wasn’t `babel-preset-env`.

以上の３つの理由から、scoped packages の採用を決めています。npm パッケージの命名は紳士協定のようなところもあるので、余計なトラブルを防止する目的が大きいようです。
Angular も [scoped packages を採用している](https://www.npmjs.com/package/@angular/core)ので、比較的大きなエコシステムをもつパッケージでは、今後 scoped packages の採用が進むかもしれません（ESLint など）。
私たちユーザー側からも、公式・非公式の区別が明確になるので、余計な混乱は起こらなくなります。

ただし、名前の変更はかなり影響があると思いますので、サードパーティのパッケージが新しい名前に対応するまでに時間がかかる可能性もあります。そうなると、Babel 7 が浸透するまではしばらく時間がかかるかもしれません。

# `@babel/preset-env` (`babel-preset-env`) の推奨

もう一つ大きな変更点は、`babel-preset-es20xx` パッケージが非推奨となり、`@babel/preset-env` が推奨となる、という点です。ECMAScript 仕様は年々アップデートされるので、年次を指定する必要性が徐々に薄れてきており、また `preset-env` パッケージを使えば実行環境に合わせて自動で適切なプリセットを選んでくれます。またまた、ブログより抜粋してみます。

> どの Babel プリセットを使うべきかを決めなければならないことよりも良いこととは何でしょうか？それは、 Babel があなたのために自動で決めてくれることです！
>
> What’s better than you having to decide which Babel preset to use? Having it done for you, automatically!
>
> データのリストを維持するための作業量は膨大だとしても — 再度、なぜ私たちは助けが必要なのでしょう — それは複数の問題を解決してくれます。それはユーザーが仕様を最新にしていることを確認してくれます。それは設定・パッケージの混乱を少なくします。それはアップグレードパスを簡単にします。そして、それは何が何だかに関する issue を減らします。
>
> Even though the amount of work that goes into maintaining the lists of data is humongous — again, why we need help — it solves multiple issues. It makes sure users are up to date with the spec. It means less configuration/package confusion. It means an easier upgrade path. And it means less issues about what is what.

以上のように `preset-env` を使うことのメリットをかなり強調していますね！現在の Babel 6 でも `babel-preset-env` パッケージは使えるので、一旦 `babel-preset-20xx` を `babel-preset-env` に置き換えておいて、Babel 7 が安定してきたタイミングで `@babel/preset-env` に変更する、という方法もアリかもしれません。

# `@babel/core` の peer dependency 化

`@babel/core` パッケージが `dependencies` から `peerDependencies` に移動されました [^5] 。これにより、`@babel/core` を明示的にインストールするよう `package.json` の修正が必要になるかもしれません。必要な peer dependencies がインストールされていないと、`npm install` で次のような警告メッセージが表示されます。

> `@babel/cli@7.0.0-beta.36` requires a peer of `@babel/core@7.0.0-beta.36` but none is installed. You must install peer dependencies yourself.

```diff:package.json
{
  "dependencies": {
-   "babel-cli": "6.26.0"
+   "@babel/cli": "7.0.0-beta.36",
+   "@babel/core": "7.0.0-beta.36"
  }
}
```

どのようなケースで修正が必要になるかを見るため、再度ブログを引用します（`babel-loader` は以前から導入済み）。

> 私たちは `@babel/core` への peer dependency を導入しています、これはすべてのプラグイン（`@babel/plugin-class-properties`）、プリセット（`@babel/preset-env`）、そしてトップレベルパッケージ（`@babel/cli`、`babel-loader`）が対象です。
>
> We are introducing a peer dependencies on `@babel/core` for all the plugins (`@babel/plugin-class-properties`), presets (`@babel/preset-env`), and top level packages (`@babel/cli`, `babel-loader`).

`gulp-babel` や `rollup-plugin-babel` などの `@babel/core` を `dependencies` に指定しているサードパーティパッケージを使っている場合、すでに Beta 版がリリースされていますので、一緒にアップグレードする必要があります。
これらは Babel の作者からプルリクエストが投げられていますので、 Babel 7 リリースに合わせてすぐに対応してくれると考えられます。その他のパッケージについては、もしかしたら対応まで時間がかかるかもしれません。

- `gulp-babel@8.0.0-beta.0` ... [package.json](https://github.com/babel/gulp-babel/blob/70c2ffab5ca8f647f0a56e348d66492ed77f81e4/package.json)
- `rollup-plugin-babel@4.0.0-beta.0` ... [package.json](https://github.com/rollup/rollup-plugin-babel/blob/ad3c92ef48f83fbc1762f7aec7b98d18873f903e/package.json)

# 実際の変更例

自作ライブラリのリポジトリで Babel 7 へのアップグレードを試すプルリクエストを作ってみました。イメージがつかめるかと思います。

https://github.com/ybiquitous/ybiq/pull/96

# まとめ

以上、個人的に気になる Babel7 の３つの変更点を紹介しました。他にも `.babelrc.js` のサポートなど、便利な新機能がありますので、気になる方は[公式ブログ](https://babeljs.io/blog)や [GitHub リポジトリ](https://github.com/babel/babel)をチェックしてみてください :blush: :v: ！

また、本記事内で気になる点や、間違っている点などがありましたら、お気軽にコメント／修正リクエストをお願いします :bow: :pray: ！


[^1]: *scoped packages* についての詳細は、[こちらの npm 公式ドキュメント](https://docs.npmjs.com/misc/scope)を参照してください。

[^2]: 「パッケージ不法占拠（package squatting）」については、[こちらの npm 公式ドキュメント](https://www.npmjs.com/policies/disputes#squatting)を参照してください。npm パッケージ名は基本的に早い者勝ちで取得できるので、このようなルールがあるようです。

[^3]:  「squatting」という単語については、今回初めて知りました :sweat_smile: 。どう訳していいか分からず「不法占拠」という語を与えましたがあまりピンとこないので、適切な訳語をご存知の方は教えてください :pray: 。

[^4]: [`babel-env`](https://www.npmjs.com/package/babel-env) は `.babelrc` ファイルを書き換えるパッケージ。Babel 公式パッケージである [`babel-preset-env`](https://www.npmjs.com/package/babel-preset-env) とは別物。

[^5]: *peer dependencies* についての詳細は、[npm 公式ドキュメント](https://docs.npmjs.com/files/package.json#peerdependencies)および[ Node.js ブログ](https://nodejs.org/en/blog/npm/peer-dependencies/)を参照してください。その目的は、異なるバージョンの同一パッケージをインストールしてしまう問題を防ぐことです。