Babel7.4.0 から、長いことお世話になってきた @babel/polyfill が非推奨となりました。加えて、@babel/preset-env と @babel/ransform-runtime が core-js@3 に対応したようです🎉
これらに伴いpolyfill周りの設定方法が変わったので、その内容をメモしておこうと思います。

Babel と core-js の関係のおさらい

Babelが提供する @babel/polyfill や @babel/preset-env などのモジュールを利用すると

  • built-ins objects(Promise, WeakMap等)
  • static methods(Object.assign, Array.from等)
  • instance methods(Array.prototype.includes等)

といった新しい機能を使った実装が可能になりますよね。これらのBabelモジュールは core-js が提供するpolyfillを内部的に読み込んでいます。特に @babel/polyfill は core-js と regenerator-runtime を束ねて提供するpolyfill集です。

Babel7.4.0からはこの @babel/polyfill が非推奨になり、代わりにcore-jsのバージョンを指定して直接読み込む方法が提案されています。

これからのpolyfill設定方法

1. preset-env と useBuiltIns:usage で必要なpolyfillだけ読み込む方法

@babel/preset-env は(指定した実行環境にあわせた)必要な構文変換や、polyfillの読み込みをしてくれるものです。そしてこのpresetのオプションのuseBuiltinsで「どのようにpolyfillを読み込むか」を指定できます。

useBuiltIns: usageとし、必要なpolyfillだけを読み込む設定例から見ていきます。

@babel/prest-env をinstallする

npm install -D @babel/preset-env

.babelrc または babel.config.js でオプションを指定する

  presets: [
    ["@babel/preset-env", {
       useBuiltIns: "usage",
       corejs: 3 // or 2
    }]
  ]

指定したバージョンの core-js をinstallする

npm install -S core-js@3  # or core-js@2

useBuiltIns: usageとすると、コード内からpolyfillが必要な箇所を勝手に判断し、必要なcore-jsを勝手にimportしてくれます。このとき、core-js のバージョンも併せてオプションで指定し、それに応じた core-js をnpm installしておく必要があるわけですね。

ちなみに執筆時点の公式ドキュメントではuseBuiltIns: usageはまだexperimentalとなっているのですが、core-js@3 では多くの問題が解消されていてもはやexperimentalではないだろう…とのことです。

2. preset-env と useBuiltIns:entry で全polyfillを読み込む方法

上記と同様に @babel/preset-env を使う方法ですが、オプションの内容が変わります。useBuiltIns: entryとし、index.js などのjsファイルの先頭にてpolyfillをimportすることで、全部のpolyfillを読み込む方法です。

@babel/prest-env をinstallする

npm install -D @babel/preset-env

.babelrc または babel.config.js でオプションを指定する

  presets: [
    ["@babel/preset-env", {
       useBuiltIns: "entry",
       corejs: 3 // or 2
    }]
  ]

指定したバージョンの core-js と regenerator-runtime をinstallする

npm install -S core-js@3  # or core-js@2
npm install -S regenerator-runtime

jsファイルの先頭で core-js と regenerator-runtime をimportする

import "core-js/stable";
import "regenerator-runtime/runtime";

// import "@babel/polyfill" 今まではこう指定していましたね

@babel/polyfill をimportしていた頃と同じ注意になりますが、core-js や regenerator-runtime 複数回importすると問題が起きる可能性があるので、bundleされるjsの冒頭で1度だけimportするように注意する必要があります。

3. transform-runtime を使う方法

@babel/plugin-transform-runtime を使ってpolyfillを入れると、globalが汚染されないメリットが得られる反面、instance methodsが使えないというデメリットがありました。が、core-js@3に対応したことによりinstance methodsが利用できるようになります🎉

設定の際は、bundleに組み込まれる @babel/runtime と、ビルド時にpolyfill変換などを担う @babel/plugin-transform-runtime を用意します。

@babel/runtime と @babel/plugin-transform-runtime をinstallする

npm install -S @babel/runtime
npm install -D @babel/plugin-transform-runtime

.babelrc または babel.config.js でオプションを指定する

  presets: [
    ["@babel/plugin-transform-runtime", { corejs: 3 }]
  ]

指定したバージョンの core-js をinstallする

npm install -S core-js@3

Proposal の使い方

@babel/preset-env または @babel/plugin-transform-runtime どちらを利用する場合であっても、core-js@3 ではProposalの機能も利用できるようになりました。設定方法はオプションの内容を変更するだけです。

// before
{ corejs: 3 }

// after
{ 
  corejs: {
    version: 3,
    proposals: true
  }
}

公式ドキュメントには「ECMAScriptの提案は本質的に不安定であり、core-js@4 では変わる可能性があります」との注意書きがありますので、ご承知おきを。

参考