@babel/preset-envのuseBuiltInsを使ってpolyfillする

[@babel/preset-envのuseBuiltIns](https://babeljs.io/docs/en/next/babel-preset-env.html#usebuiltins)に関する記事です。
Babel v7以降で使えるようになるpolyfillを自動補完してくれる機能について紹介します。

#### 更新(2018/08/27)
2018/08/27にBabel v7が正式リリースされました🎉
https://babeljs.io/blog/2018/08/27/7.0.0

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

# [@babel/polyfill](https://babeljs.io/docs/en/babel-polyfill#docsNav)
- babelは文法の変換のみ。ブラウザによっては使えない機能はあります。
- 例えば、IEはPromiseとかSymbolとか使えません。これは文法ではなく、機能です。
- @babel/polyfillを使えばその辺の穴埋め(polyfill)をしてくます。
- ソースコードを直接改変する必要があり。以下のようにpolyfillをimportしなければいけません。

```js
import "@babel/polyfill"

```

# [@babel/plugin-transform-runtime](https://babeljs.io/docs/en/babel-plugin-transform-runtime)
- こちらもpolyfillするbabelのプラグイン
- babel-polyfillとは違いimportを書く必要がない。babelの設定に追加するだけ
- babelのプラグインなので変換時にpolyfillします
- 指定したブラウザとか関係なく問答無用で変換する。ようするにchromeには既に実装済の機能でChromeの最新バージョンに合わせて変換してもChromeがネイティブ対応済のものまでpolyfillします

# 求めているもの
- polyfillのためにimportを書いたり、polyfill用のパッケージをインストールしたくない
- 指定したブラウザやバージョンに無い機能だけpolyfill入れてほしい

# [@babel/preset-env](https://babeljs.io/docs/en/babel-preset-env#docsNav)
- babel 6の頃は[babel-preset-env](https://github.com/babel/babel-preset-env)だった
- 指定したブラウザやNodeのバージョンに合わせてネイティブサポートしていない文法のみ変換
- cssのAutoprefixerのように[browserslist](https://github.com/browserslist/browserslist)を使って文法の変換を行う
- 上記で書いた「求めているもの」を叶えてくれる優れもの

## Install
まずは@babel/preset-envのインストール方法

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


## useBuiltIns: "usage"オプション
- polyfillのための@babel/polyfillのインストールが不要
- 指定したブラウザやバージョンに合わせて必要なpolyfillだけをimport
 
**@babel/polyfillとbabel-plugin-transform-runtimeのいいとこどり！**

## Babel v6のbabel-preset-envのpolyfill
useBuiltInsオプションは1.x系からありました。


```json
{
  "presets": [
    [
      "env",
      {
        "targets": {
          "ie": 11
        },
        // trueにすることで必要なpolyfillだけをimportするようにします
        "useBuiltIns": true
      }
    ]
  ]
}
```

- 必要なpolyfillのみインポート
- ただし前述の通り@babel/polyfillをimportしなければいけません。

イメージ的には以下のように@babel/polyfillをimportするコードが必要な分のpolyfillをimportするコードに変換されます

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

↓ 

```js
require("babel-polyfill/lib/core-js/modules/es6.promise");
```

---

## Babel v7の@babel/preset-envからのpolyfill

```json
{
  "presets": [
    [
      "env",
      {
        "targets": {
          "ie": 11
        },
        // 必要な分だけのpolyfillを自動でインポート
        "useBuiltIns": "usage"
      }
    ]
  ]
}
```

- @babel/polyfillの別途インストールが不要
- @babel/polyfillをインポートするコードが不要
- usageにしてbabelを実行すると勝手に以下ような必要な分だけpolyfillが埋め込まれる

これが自動でコード内に挿入される

```js
require("babel-polyfill/lib/core-js/modules/es6.promise");
```

**開発者はpolyfillいるかいらないか気にしなくてよい**ようになります


## 注意
場合によっては別途polyfillが必要だったりもするので万能ではない
以下のような実行しないと型がわからない場合とかは自動でpolyfillできません
そういった場合は必要なpolyfillをimportする必要があります

```js
users.includes("hoge")
```


# GitHubにサンプル置いときました！
[shisama/babel-preset-env-useBuiltIns-sample](https://github.com/shisama/babel-preset-env-useBuiltIns-sample)
npm updateしてnpm run buildすれば以下のトランスパイルした結果を出力
- Node.js(4/6/8)
- chrome(v60/v50)
- firefox(v55/beta)
- Safari
- Edge
- IE11

# まとめ
- babelは文法の変換だけ
- polyfillは@babel/preset-envで
```
"useBuiltIns": "usage"
```
すればどのpolyfillが必要か考えなくてよくなるし、不要なpolyfillは入らない

最後までお読みいただきありがとうございました。質問や不備がございましたらコメント欄またはTwitter([@shisama_](https://twitter.com/shisama_))までお願いいたします。