embryo

エンジニアの備忘録

ViteでLegacyブラウザ対応する方法と注意点

今日はviteを利用したprojectでブラウザ対応を宣言しpolyfillなどを対応する方法についてまとめます。

トランスパイラを用いたブラウザ対応

babelなどのトランスパイラを利用している場合はbabel-preset-envを利用してbrowserslistとコードベースの内容に応じて自動でcore-jsのimport文を追加しpolyfillを解決する方法が用いられてきました。swcを利用している場合も同等の機能が用意されています。

viteのデフォルトブラウザ対応

こちらにもある通り、viteのブラウザ対応はESMのサポート状況を基準に行っており、検証する対象は構文にとどまっています。 viteがトランスパイラとして利用しているes-buildにbabelやswc相当の機能があることを期待するかもしれませんが、esbuildのtargetAPIのサポート状況に関する検証はスコープ外としています。 そのためviteで対応ブラウザのAPI利用の検証を行いたい場合以下の2つの方針が考えられます。実際はもっと細分化されますが大まかに分けると以下の2つになるかと思います。

  1. swc, babelを利用してトランスパイル時にpolyfillを読み込むように変換する
  2. tsconfigのlib設定やes-buildのsupportedオプションを利用し静的にサポートしていないAPI利用を制限する

2に関してはbrowserslistなどの設定から適切な設定を出力するライブラリなどが有志によって作られているかもしれません。

コニュニティプラグインとして vite-plugin-react-swcが提供されているのでswcのenvを利用することも考えられますが、現状swc関連の設定はハードコーディングされているため、ユーザーが自由に設定を指定するという仕様にはなっていません。

以下のpluginはswcrcの設定を読み込んでくれるため有効な選択肢になり得ますがこちらは検証していません。

github.com

@vitejs-plugin/legacy の利用

viteはコミュニティプラグインとして @vitejs/plugin-legacy を提供しています。

github.com

内容は前述したbabel-preset-envを利用した方法ですが、core-jsへのimport文を取り除いてpolyfill用のchunkを生成する仕組みになっているところや、古いブラウザとモダンブラウザでchunkを分割している点で工夫されています (以下modern / legacy chunk)。legacy / modernの分岐は前述のESM対応状況をベースにしており、デフォルトの挙動ではESMの対応が不完全なブラウザをlegacyとして判別するためpolyfillなどもlegacyブラウザでのみ読み込まれることになります。定常的にすべてのブラウザに対してpolyfillを提供するためには以下の3つの設定を適切に行う必要があります。

  • modernTargets
  • modernPolyfills
  • renderLegacyChunks

modernTargets はmodern chunkに対する対応ブラウザの宣言でbrowserslistのフォーマットで設定できます。modernPolyfills とセットで利用されることを期待され、加えて modernPolyfills を有効にすることでmodernと判別されたブラウザでもpolyfillのchunkが読み込まれることになります。

If modernTargets is not set, it is not recommended to use the true value (which uses auto-detection) because core-js@3 is very aggressive in polyfill inclusions due to all the bleeding edge features it supports. Even when targeting native ESM support, it injects 15kb of polyfills!

と記載があるように、polyfillの内容は実際のコードベースとブラウザ対応設定に対して最適化されたものが出力されるため最小限の内容になっているものの、ランタイムで最適化されるワケではないので最新のブラウザを利用しているユーザーも同様のpolyfillを読み込むことになります。そのため、公式では modernTargets である程度対応ブラウザを絞ったうえで利用するか、polyfill.ioを利用することを推奨しています。

renderLegacyChunks は ESMはサポートされているブラウザが対象である場合 legacy chunkが不要なので false を設定することで前述のデフォルトの挙動をOFFにすることができます。

まとめ

viteでbrowserslistを用いて宣言的にブラウザ対応を行う方法についていくつか解説しました。静的に検証するか、静的に検証した上でpolyfillを導入する2つの方法がありますが、多くのユーザーをサポートする必要があるプロダクトでは後者の方が有効なケースが多そうです。