Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What are the problem?
@hkano

Polyfill.io を使って JavaScript の Polyfill を適用する

この記事は「弁護士ドットコム Advent Calendar 2020」の3日目の記事です。よろしくお願いいたします。


TL;DR

Polyfill.io という非常に便利なサービスを使って、Internet Explorer などのブラウザでも最近の JavaScript を動くようにします。その為に必要なのは、以下のような <script> を一行追加するだけです。

<script src="https://polyfill.io/v3/polyfill.min.js?features=default%2Ces2015%2C..." crossorigin="anonymous"></script>

素晴らしいことに、Polyfill.io がブラウザを判別して必要な Polyfill のみを返してくれます。ファイルサイズ(バンドルサイズ)の削減などにも効果があります。

はじめに

JavaScript の実装で Fetch API を使用したい場面がありました。
https://developer.mozilla.org/ja/docs/Web/API/Fetch_API
この機能が Internet Explorer (以下、IE) 非対応である為、何かしらの対応をすることになりました。
(尚、この解説での IE のバージョンは 11 になります。10 以前はほとんど使用されていないので、無視します。)

結果、Polyfill を効かせるライブラリを導入することになり、選定を行いました。

Polyfill とは

JavaScript (ECMAScript) は特定のブラウザやバージョンが古い場合、サポートしていない機能が存在します。Polyfill は、そういったサポートしていない最近の機能を使えるようにするためのコードです。

[参考] Polyfill (ポリフィル) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN
https://developer.mozilla.org/ja/docs/Glossary/Polyfill

Polyfill ライブラリの選定する

core-js と Polyfill.io を検討しました。

core-js

https://github.com/zloirock/core-js
実績のある Polyfill ライブラリです。

以前は Babel が提供する @babel/polyfill が core-js を内部的に読み込んでいました。
https://babeljs.io/docs/en/babel-polyfill
因みに、@babel/polyfill は Babel 7.4.0 で非推奨 (deprecated) となっています。

こちらについては、5 日目の記事「babel 環境における Polyfill のビルド最適化と async-await の扱い」で詳しく説明していただいています。気になる方は、併せてご覧ください。

今回は、core-js を jsDelivr などの CDN から読み込むことを考えました。
https://www.jsdelivr.com/package/npm/core-js


<script src="https://cdn.jsdelivr.net/npm/core-js@3.7.0/stable/index.js" integrity="sha256-HrF6MoQzzJ82sV7Ql2E5hrTW2iRlrlD54q4o/q9lIFY=" crossorigin="anonymous"></script>

対応は楽なのですが、stable だけに絞ってもファイルサイズが大きくなりページの表示速度が低下する懸念があった為、見送りました。

Polyfill.io

https://polyfill.io
指定したリクエストに応じて、必要とする Polyfill のみを返すサービスです。

ブラウザを判別して必要な Polyfill のみを返すので、Polyfill が不要な主要ブラウザであればファイルサイズは大きくならず、良さそうだと判断したので Polyfill.io について調査と検証を進めることにしました。

Polyfill.io を調査する

今は v3 なので https://polyfill.io/v3/polyfill.min.js です。
v2 を利用し続けているサイトも見かけます。v2 は https://cdn.polyfill.io/v2/polyfill.js です。
今から利用するなら v3 を使いましょう。

.min を削除した URL にアクセスすると詳細が確認できます。
https://polyfill.io/v3/polyfill.js

最新バージョンの Chrome でアクセスすると /* No polyfills needed for current settings and browser */ と出力されます。Polyfill が不要な為、このような出力になります。

CREATE A POLYFILL BUNDLE (url-builder) から、必要な Polyfill を指定できます。
https://polyfill.io/v3/url-builder/

例えば、今回の発端であった Fetch API を適用するには、以下のようになります。

<script src="https://polyfill.io/v3/polyfill.min.js?features=fetch" crossorigin="anonymous"></script>

features などの Querystring については API Reference で説明されています。
https://polyfill.io/v3/api/

こちらを参考に、Querystring に flags=always を指定すると、本来は Polyfill が不要なブラウザからのアクセスでも、適用される内容を確認することができます。
例えば、以下の URL にアクセスすると、適用が不要な Chrome であっても fetch で適用される Polyfill が確認できます。
https://polyfill.io/v3/polyfill.js?features=fetch&flags=always

Polyfill.io を検証する

この時点で Fetch API 以外にも IE 非対応の機能を使用していることに気付き、適用する features について使われている機能を洗い出しました。機能を把握し切れていなかった為、「動作を試してみて、エラーになった機能を一つずつ確認して追加して、また試す」というのを繰り返しました。

途中経過で、以下のような features になりました。

<script src="https://polyfill.io/v3/polyfill.min.js?features=Array.prototype.find%2CEvent%2CNodeList.prototype.forEach%2CPromise%2Cfetch" crossorigin="anonymous"></script>

どうも埒が明かないので、一括で読み込む方針に方向転換しました。
そもそも、ブラウザを判別して必要な Polyfill のみを返してくれるので、一括でも不要な Polyfill は通信されなので問題ないという判断です。

API Reference の features の説明に、以下のような記述がありました。

Omitting or setting to an empty string is equivalent to the value "default", which is an alias for a curated list of polyfills.

features を特に指定しなければ、必要な全ての機能の Polyfill が適用される(これは勘違い、詳しくは後述)と思い、以下のような指定をしました。

<script src="https://polyfill.io/v3/polyfill.min.js" crossorigin="anonymous"></script>

残念ながら、これだと上手く動きませんでした。いくつかの機能が動かずに Polyfill が効いていない挙動になってしまいました。

先の説明をよく読むと分かるのですが、features を指定しない場合は default と同等になります。
https://polyfill.io/v3/polyfill.js?features=default&flags=always
別の記事で「読み込むだけで全ての機能の Polyfill が適用される」というような記述を見掛けたのですが、それは誤りのようです。

どの Polyfill が適用されるかは、CREATE A POLYFILL BUNDLE (url-builder) の各 Polyfill の からも確認できます。
`default` feature で適用される機能の一覧

以上を踏まえて、最終的に以下のような指定になりました。

<script src="https://polyfill.io/v3/polyfill.min.js?features=default%2Ces2015%2CNodeList.prototype.forEach%2CReflect.set%2Cfetch" crossorigin="anonymous"></script>

現段階で必要と判断した以下の features を適用しています。

  • default
  • es2015
  • NodeList.prototype.forEach
  • fetch

defaultes2015 で概ね必要な Polyfill は効いたのですが、個別に NodeList.prototype.forEachfetch を追加しました。

これで最終の動作確認を行いました。

es2015 について

補足になりますが es2015 は ECMAScript 6th edition のことです。 6th edition から発行年が付加されています。つまり es6 と同じです。同様に es2016es7 も同じになります。

es2015es6 は同じなのですが、Polyfill.io だと es2015 を選択した場合は String.fromCodePoint だけ足りないようです。 => 修正の Pull request を送ったところ、取り込んでいただたきました。

es2015es6 は同じなので、Polyfill.io でも同じ Polyfill が適用されることが確認できます。
https://polyfill.io/v3/polyfill.js?features=es2015&flags=always
https://polyfill.io/v3/polyfill.js?features=es6&flags=always

現在は年号付きが推奨されている為、今回は es2015 を選択しました。

その結果どうなったか

結果、これでも動作しませんでした。

Object doesn't support property or method 'set' というエラーが発生しました。
これは IE 非対応の FormData.set() を使っていた為でした。
https://developer.mozilla.org/ja/docs/Web/API/FormData/set

FormData.set() は Polyfill.io では対応していません。
https://github.com/Financial-Times/polyfill-service/issues/1205

因みに、core-js でもスコープ外で、他プロジェクトの Polyfill を使うことを勧めています。
https://github.com/zloirock/core-js/issues/482

ここまで進めた結果、今回は「そこまで厳密に IE の動作を求めない」という決着になり、これで対応完了とすることになりました。もし厳密な IE のサポートを求められたら、JavaScript の実装コードを書き直すか、別のライブラリで対応する Polyfill を探すことになるかと思います。

まとめ

Polyfill.io だけで全ての機能に Polyfill が効くわけではないので、Polyfill 非対応の機能など注意して JavaScript を書かないと厳密な IE 対応は厳しそうでした。
別のライブラリを探せば対応する Polyfill はあるとは思いますが、個別に Polyfill を適用していくのも手間ですし、読み込むファイルが増えるとページの表示速度が低下する懸念があります。

そもそも Polyfill.io は SLA が存在しません。
https://polyfill.io/v3/terms/#polyfillio-are-provided-as-is-and-without-any-sla

We do not guarantee that Polyfill.io, or any content on them, will always be available or be uninterrupted. We may suspend or withdraw or restrict the availability of all or any part of Polyfill.io for business and operational reasons.

We do not provide any service level agreement or any other performance commitments for Polyfill.io. We are not able to participate in any technical due diligence or other procurement process that your organisation may have.

厳密な対応が必要なら、外部のサービスや CDN に頼らずに自前で運用する必要があるかもしれません。
Polyfill.io は自前で動かすパッケージも公開しています。
https://polyfill.io/v3/packages/#polyfill-library

どこまで厳密な対応を行うかは、開発や運用コストとの兼ね合いで判断が必要かと思います。

さいごに

既に IE のサポートを終了しているサイトもあるかとは思いますが、一方でまだまだサポートしていかなければいけない状況のサイトもあります。どの程度のサポートを求められるか次第ではありますが、サポートの程度によっては Polyfill.io は選択肢のひとつして、とても良いと思いました。

Polyfill.io について既に書かれた記事もあったのですが、もう少し詳細にまとめてみました。

この記事が皆様の一助となれば幸いです。


さて、明日 (12/4) の「弁護士ドットコム Advent Calendar 2020 | 4日目」は @edi_t さんの「iPhoneX以降のTrueDepthカメラを使ってオンライン会議で簡単にVTuberになる方法(お金がちょっと掛かります)」になります!お楽しみに!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
5
Help us understand the problem. What are the problem?