2026年、まだポリフィルを使っている人はいるのか?
2026年のpolyfillは必要? core-js、Browserslist、Babelを監査し、不要な負荷を削減しつつTemporalとpolyfill.ioを見直します。
いる——ただし、バンドラーが引き継いだポリフィルのほとんどは、もはや必要ない。2019年当時は合理的だった「広範なBrowserslistターゲットに対して@babel/preset-envをuseBuiltIns: 'entry'で適用する」という一括ポリフィルのデフォルト設定は、今やシェアがほぼゼロに等しいブラウザをサポートするために、圧倒的多数のユーザーに不要なバイトを送り続けている。ポリフィルは2026年においても、真にサポートされていない機能の短い明示的なリストに対しては依然として適切なツールだ——しかし、それ以外のすべてに対しては負債でしかない。
この記事は一つの判断を明確にする:現在のビルドパイプラインに含まれるポリフィルが、そのバイト数に見合う価値を持っているかどうかだ。どのAPIが不要な重荷なのか、どれが正当にポリフィルを必要としているのか、polyfill.ioのサプライチェーンインシデントがポリフィルの読み込み方法をどう変えたのか、そして実際に何を配信しているかを監査するための具体的なコマンドを示す。
重要なポイント
- 2026年においてエバーグリーンブラウザをターゲットとするReact、Vue、Svelte、またはNext.jsアプリの場合、ほとんどのチームにとって適切なポリフィルの数はほぼゼロに近い——Decorators、クロスブラウザ移行期のTemporal、そしてロックされたエンタープライズブラウザの制約は例外だ。
Array.flat、Object.entries、Promise.allSettled、structuredClone、オプショナルチェーン、Nullish合体演算子、fetchはすべて2026年において広くサポートされており、これらをポリフィルしても実際のユーザーにはほぼ無意味なバイトを送ることになる。- リモートポリフィルサービスのパターン(polyfill.ioからスクリプトを読み込む方法)は、2024年のサプライチェーンインシデント後に終わりを迎えた。CloudflareとFastlyがミラーを立ち上げたが、このパターン自体はもはや擁護できない。
npx browserslistを実行して設定がターゲットとする正確なブラウザを確認し、次にsource-map-explorerで配信しているcore-jsの重量を調べよう。- web.devのEnhancement / Additive / Criticalの分類は、欠落した機能がポリフィルに値するかどうかを判断するための最も優れたフレームワークだ。
2026年のネイティブサポートのベースライン:もはやポリフィル不要なもの
ビルド設定が依然として定期的にポリフィルしているJavaScriptの機能のほとんどは、すべてのエバーグリーンブラウザでサポートされており、ポリフィルしても実際のユーザーにはほぼ不要なバイトを送ることになる。10年間ポリフィルのチュートリアルを支えてきた機能——Math.trunc、Array.prototype.flat、オプショナルチェーン——は今や広くサポートされており、2026年の監査で真っ先に削除すべき不要な重荷だ。
このジャンルの代表的な教材例であるjavascript.infoのMath.truncポリフィルは、最もわかりやすい例だ。Math.truncは2015年以来、すべてのブラウザで普遍的にサポートされている——MDNの互換性データによると、Chrome 38、Firefox 25、Safari 8でリリースされている。2026年にMath.truncのポリフィルを書いたりバンドルしたりすることは、誰も使っていないブラウザのためのガード節を配信することに等しい。
古くなった設定がターゲットとするAPIサーフェス全体でも同様だ。以下のサポート率はcaniuse.comのグローバル使用データ(StatCounter、2026年5月)から引用している。「グローバルサポート」とは、追跡されているすべてのバージョンにわたるcaniuseの加重ブラウザシェアを指す。
| 機能 | グローバルサポート(caniuse、2026年) | まだポリフィルする価値があるか? |
|---|---|---|
Array.prototype.flat | 94.11% | いいえ |
Object.entries | 95.06% | いいえ |
Promise.allSettled | 94.04% | いいえ |
structuredClone | 93.84% | いいえ |
オプショナルチェーン(?.) | 93.99% | いいえ(構文——ポリフィルではなくトランスパイルで対応) |
Nullish合体演算子(??) | 93.99% | いいえ(構文——ポリフィルではなくトランスパイルで対応) |
fetch | 96.3% | いいえ |
Temporal | 65.16% | はい——移行期として |
| Decorators | ネイティブサポート0% | はい |
Array.flat、Object.entries、Promise.allSettled、structuredClone、オプショナルチェーン、Nullish合体演算子、fetchはいずれもグローバルサポートが94〜96%前後だ——もしBabelの設定がこれらをまだポリフィルしているなら、ほぼどのユーザーにも不要なバイトを配信していることになる。
構文と関数の違い: オプショナルチェーンとNullish合体演算子は構文であり、欠落した関数ではない。そのため、ポリフィルではなくトランスパイラで処理される。javascript.infoが述べているように:モダンな構文や演算子にはトランスパイラを使い、欠落した関数にはポリフィルを使う。監査の際にこの区別は重要だ——設定の中に
??の「ポリフィル」があれば、それは設定が両者を混同しているサインだ。
2026年においてもポリフィルが正当化されるケースは?
Discover how at OpenReplay.com.
ポリフィルが適切なツールであり続けるのは、少数の明確なケースに限られる:どのブラウザでもネイティブサポートがない機能、ブラウザ間で移行中の機能、そしてエバーグリーンの前提が成り立たないロックされたブラウザ環境だ。これらの例外こそが、パイプラインにポリフィルの仕組みを残す理由となる。
Decorators。 TC39のDecoratorsプロポーザルはStage 3にあり、ネイティブブラウザ実装はまだない。Decoratorsを直接使う場合、またはAngularのようなフレームワークや依存するライブラリを通じて使う場合、トランスパイラと場合によってはランタイムヘルパーに依存することになる。現時点では「ネイティブを待つ」という選択肢はない——この機能はまだブラウザに実装されていないからだ。
クロスブラウザ移行期のTemporal。 TemporalはTC39の完成済みプロポーザルであり——TC39の完成済みプロポーザルリストに掲載されている——ネイティブでの実装が始まっている。MDNのTemporal互換性データによると、Firefox 139+、Chrome 144+、Edge 144+、Node.js 26+で利用可能だが、Safariはまだ有効なサポートがない。この不均一なロールアウトにより、Temporalのポリフィルは恒久的なものではなく移行期の必要性となる。TC39のproposal-temporalリポジトリでは、@js-temporal/polyfillをアルファリリースの選択肢として他の代替案とともに挙げているが、これが唯一の正式な選択肢ではない。
エンタープライズおよびロックされたブラウザ環境。 規制された金融システム、政府のイントラネット、キオスクやPOSデバイスは、ブラウザのバージョンを何年も固定することがある。実際のユーザーベースに更新できないブラウザが含まれる場合、Browserslistのターゲットはエバーグリーンのデフォルトより広くなり、一部のポリフィルは必要不可欠になる。重要なのは実際にそうであるということだ——このケースは測定されるよりも主張されることの方がはるかに多い。ポリフィルを維持する前に、アナリティクスで検証しよう。
JSポリフィルが必要な限定的なCSSの機能。 コンテナクエリのような一部のCSS機能は、古いSafariでのロールアウト中にJavaScriptでポリフィルされていた。web.devが指摘するように、コンテナクエリポリフィルはResizeObserverとMutationObserverを使ってネイティブの動作を模倣しているが、そのREADMEはメンテナンスが終了していることを示している。これらのポリフィルには後述する動作上の注意点がある。
「ターゲットを絞ったポリフィルを使い、データに基づいて判断する」という広く共有されているコンセンサスは間違っていないが、どれほど状況が変わったかを過小評価している。2026年のほとんどのアプリにとって、「ポリフィルは引き続き重要な役割を果たす」はもはや真実ではない。その役割は今や狭く、明確に定義されている。
polyfill.ioのインシデントがリモートポリフィルサービスパターンを終わらせた
リモートポリフィルサービスパターン——ブラウザに合わせたポリフィルを返すサードパーティCDNから<script>を読み込む方法——は、2024年のpolyfill.ioサプライチェーン攻撃の後、もはや擁護できるアーキテクチャではなくなった。このインシデントにより、チームはサードパーティから何を読み込んでいるかを監査せざるを得なくなり、ほとんどのチームはそのほとんどが不要だったことを発見した。
タイムライン:
- 2024年初頭——所有権の変更。 polyfill.ioドメインが別の所有者に移った。Fastlyのコミュニティ投稿には、この変更と影響を受けたユーザーへのFastlyの対応が記録されている。
- 2024年6月25日——マルウェアの報告。 セキュリティ企業のSansecが、polyfill.ioサービスがエンドユーザーに配信するスクリプトにマルウェアを注入していたと報告した。
- 2024年6月——ミラーと緩和策の対応。 Cloudflareがpolyfill.ioのリンクを自社ミラーに自動置換することを発表し、Fastlyも代替エンドポイントを提供した。
ミラーは既存のサイトを機能させ続けるが、このパターン自体を正当化するものではない。このインシデントが露わにした典型的な本番環境の失敗パターン:チームはcdn.polyfill.ioのスクリプトタグを持ち、何年も前に不要になったポリフィルのバンドルを読み込み、すでに更新されたブラウザをサポートするためにすべてのページ読み込みでサードパーティのJavaScriptを実行していた。CloudflareやFastlyのミラーを「安全な」代替として扱ってはいけない——このインシデントをスクリプトタグを完全に削除し、本当に必要なポリフィルを自分のバンドルに移す契機として捉えるべきだ。そうすれば、管理とレビューを自分でコントロールできる。
バンドラーが実際に配信しているものを監査する方法
ポリフィルのフットプリントを監査するには4つのステップがある:実際のBrowserslistターゲットを確認し、バンドル内のcore-jsの重量を調べ、Babelの設定を修正し、実際のユーザーデータで検証する。これらはすべて推測を必要としない——各ステップは今日実行できるコマンドまたは設定の差分だ。
ステップ1:実際のターゲットリストを確認する
Browserslistのクエリが設定でサポートするブラウザを決定するが、自分の設定が何に解決されるかを知る唯一の確実な方法は、直接確認することだ:
npx browserslist
このコマンドは、現在の設定がターゲットとする具体的なブラウザとバージョンのリストを出力する。Browserslistのデフォルト(> 0.5%, last 2 versions, Firefox ESR, not dead)はnot deadによってIE11を既に除外している。実際のリスクは、引き継いだカスタムクエリ——> 0.2%のような設定や古いバージョンの下限指定——が古いターゲットを静かに引き込んでいることだ。コマンドを実行して、出力に実際のユーザーが使っていないブラウザが含まれていれば、それが不要な重荷だ。
ステップ2:バンドル内のcore-jsの重量を見つける
core-jsは@babel/preset-envがポリフィルを注入するポリフィルライブラリで、必要のないバンドルではかなりの割合を占めることがある。本番ビルドを調べてみよう:
npx source-map-explorer dist/assets/*.js
source-map-explorerは、ソースマップから各バンドルの内容をツリーマップで表示する。core-jsモジュール——es.array.flat、es.object.entries、es.promise.all-settled——を探そう。それぞれが上記の不要な重荷の表にある機能に対応している。(webpackプロジェクトでは、webpack-bundle-analyzerでも同じビューが得られる。)
ステップ3:Babelの設定を修正する
ほとんどのチームが引き継いだ標準的な設定は不完全だ。よくあるパターンはこのようなものだ:
{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "usage",
"corejs": 3
}]
]
}
この設定には2つの問題がある。まず、targetsフィールドがないため、設定はBrowserslistファイルにフォールバックする——それがステップ1で見つかった古いカスタムクエリかもしれない。次に、corejs: 3がピン留めされていない。core-jsのドキュメントによると、バージョンはマイナーバージョンまで指定すべきで、そうすることでpreset-envがインストールされているリリースに合ったポリフィルを注入する。2026年に適した設定はこうだ:
{
"presets": [
["@babel/preset-env", {
"targets": "> 1%, last 2 versions, not dead",
"useBuiltIns": "usage",
"corejs": "3.40"
}]
]
}
corejsは任意の数値をコピーするのではなく、実際にインストールされているマイナーバージョンにピン留めすること——preset-envはこれを使って注入するポリフィルを決定する。
useBuiltInsの値が最も重要な設定だ。@babel/preset-envのドキュメントによると:
'entry'は単一のimport 'core-js'を、targetsが必要とするポリフィルの完全なセットに置き換える——広範であり、引き継いだバンドル肥大化のほとんどの原因だ。'usage'はコードが実際に参照する機能のポリフィルのみをファイルごとに追加する。これはほぼ常に望ましい方法だ:ターゲットマトリクス全体ではなく、実際の使用状況にポリフィルの注入を絞り込む。
ステップ4:実際のユーザーデータで検証する
設定はユーザーに関する仮説であり、RUMデータがそれを確認または否定する。web.devはポリフィルするかどうかを決める前に実際の機能サポートを測定することを推奨しており、広範なデータソースとしてRUM Insightsを挙げている。そこでのパターン:Baseline Widely availableセットの機能は98%以上のユーザーにサポートされている。アナリティクスがある機能のサポートがその閾値に近いことを示しているなら、そのポリフィルはほぼ無視できるほど小さなユーザー層にしか機能していない。
いつポリフィルすべきか?Enhancement、Additive、Criticalのフレームワーク
実際のユーザーベースで機能が本当にサポートされていない場合、web.devのEnhancement / Additive / Criticalの分類がポリフィルするかどうかを決める最も有用なヒューリスティックだ:欠落した機能がユーザーに見えないなら、ポリフィルしない。優雅に劣化するなら、ポリフィルしない方向に傾く。不在がエクスペリエンスを壊す場合にのみ、ポリフィルはそのパフォーマンスコストに見合う。
web.devが定義する3つの階層:
- Enhancement(拡張) — 機能はエクスペリエンスを向上させるが、その不在は視覚的な変化や機能の喪失をもたらさない。
fetchpriorityのようなパフォーマンスヒントがその例だ。サポートしていないブラウザのユーザーは気づかない。ポリフィルしない。 - Additive(追加的) — 機能はページの見た目や動作に影響するかもしれないが、深刻な問題を引き起こすほどではない。ユーザーはブラウザを比較した場合にのみ気づくかもしれない。ポリフィルが存在する場合でも、特に他のものをすでにポリフィルしているなら、使わない方向に傾く。カラー関数やsubgridがその例だ。
- Critical(重要) — 不在が壊れたエクスペリエンスを引き起こす:ランタイムエラー、壊れたレイアウト、使用不能な機能。ここではポリフィル(または全く異なるアプローチ)が正当化される。
web.devの基本ルールは上記のサポート表と相性が良い:機能がWidely availableであれば、ポリフィルに手を伸ばすべきではない——ユーザーについて明示的に別のことを示すデータがある場合を除いて。
ポリフィルのバグが隠れる理由——そしてセッションリプレイがそれを明らかにする方法
ポリフィルのバグは、標準的なテストスイートが完全に見逃すクラスに属している:それらはポリフィルをトリガーしたブラウザの断片でのみ現れるが、そのブラウザはCIが実行するエバーグリーンブラウザではない。セッションリプレイは、ポリフィルパスを実行したブラウザの実際のインタラクションとミューテーションシーケンスを記録するため、それらのユーザーの実際のDOM状態をキャプチャできる数少ない可観測性技術の一つだ。
セッションリプレイは、ポリフィルされたコードパスとネイティブコードパスの間の3つの具体的な乖離パターンを明らかにする:
- コンテナクエリポリフィルにおけるレイアウトシフトのタイミング。 web.devが指摘するように、コンテナクエリポリフィルは
ResizeObserverコールバックからレイアウトを駆動するが、これはブラウザが新しいフレームをペイントする直前に発火し——プレゼンテーションの遅延を増加させ、Interaction to Next Paintに影響する。遅延した再ペイントのタイミングは、ポリフィルを必要としたブラウザでのみ観察できるレイアウトシフトを引き起こす可能性がある。 - Temporalのタイムゾーンの乖離。 Temporalのクロスブラウザ移行期間中、チームはブラウザ間での一貫した動作を確保するために、ネイティブとポリフィルされた
Temporalの両方の実装をテストする必要があるかもしれない。テストスイートは一方の実装パスに対してのみ実行されるかもしれないが、実際のユーザーは別のパスに遭遇する。ネイティブとポリフィルされた実装が共存するブラウザからのリプレイは、そのような差異を明らかにするのに役立つ。 - フォーカス管理のギャップ。 アクセシビリティに焦点を当てたポリフィルは、ネイティブサポートのないブラウザで微妙なキーボードナビゲーションとフォーカス管理の問題を引き起こす可能性がある——web.devがより一般的に強調する種類の失敗モードだ。キーボードイベントキャプチャを伴うリプレイは、ユーザーがモーダルの背景をタブで移動する様子を示すが、ポリフィルに対する自動テストの合格ではそれが明らかにならない。
いずれの場合も共通の要因は同じだ:バグは開発環境が再現できないユーザーの断片に存在する。これが、より少ないポリフィルを配信すべき構造的な理由だ——削除するポリフィルパスはそれぞれ、監視する必要がなくなる乖離パスでもある。
今週取るべき具体的なアクション
ポリフィルのフットプリントを削減することは、バンドルとユーザーに対して検証しながら行う、小さく可逆的な編集の連続だ。目標は、できる限りネイティブで配信し、本当のロングテールには条件付きで読み込み、それ以外はすべて削除することだ。
npx browserslistを実行し、実際のユーザーが使っていないブラウザをターゲットとする引き継いだカスタムクエリを削除する。より厳密で最新のターゲットにフォールバックすることが、最も高い効果をもたらす単一の変更だ。useBuiltIns: 'usage'を設定し、@babel/preset-envの設定に明示的なtargetsフィールドを追加し、corejsをインストールされているマイナーバージョンにピン留めする。source-map-explorerでバンドルの変更前後を比較し、core-jsの重量が実際に減ったことを確認してから、テストを実行して必要なものが消えていないことを確認する。cdn.polyfill.ioのスクリプトタグを完全に削除し、本当に必要なポリフィルは自分のバンドルに移す。- 本当の例外については条件付きで読み込む。 移行期のTemporalについては、全員に配信するのではなく、必要なブラウザにのみポリフィルを読み込む。Decoratorsについては、必要な場合はトランスパイルとランタイムヘルパーに依存する。限定的に利用可能な機能のポリフィルは条件付きで読み込むべきというweb.devの指摘は、ここに直接当てはまる。
- 変更前後にRUMデータで検証し、監査がグローバル平均ではなく自分のユーザーに基づいていることを確認する。
結論
2026年においてまだポリフィルを使っている人がいるかという問いへの正直な答えはイエスだ——しかし、擁護できるリストは短く具体的だ:Decorators、ブラウザ間のギャップを越えている間のTemporal、そして実際に測定したロックされたブラウザ環境。それ以外の設定が引き継いだものはすべて、ほぼゼロのブラウザシェアに費やされたバイトであり、polyfill.ioのインシデントは不注意に読み込むことが実際のリスクを伴うことを改めて示している。今日npx browserslistから始めよう。その出力と実際のユーザーが使っているブラウザとのギャップがポリフィルの予算だ——そしてほとんどのチームにとって、それは設定が想定しているよりもはるかに小さい。
よくある質問
ポリフィルとトランスパイラの違いは何ですか?
トランスパイラはビルド時にモダンな構文を古い同等のものに書き換えるのに対し、ポリフィルは欠落した関数やAPIの実装をランタイムに追加する。オプショナルチェーンやNullish合体演算子のような構文機能は言語演算子であり、呼び出し可能な関数ではないため、トランスパイラで処理される。Promise.allSettledやstructuredCloneのようなAPIは、ランタイムコードが提供できる欠落したメソッドであるため、ポリフィルで処理される。設定にNullish合体演算子の「ポリフィル」があれば、それは両者が混同されているサインだ。
babel-preset-envのuseBuiltInsの'usage'と'entry'の違いは何ですか?
useBuiltInsを'entry'に設定すると、Babelは単一のcore-jsのインポートをターゲットが必要とするポリフィルの完全なセットに置き換える——これが引き継いだバンドル肥大化のほとんどの原因だ。'usage'では、Babelはコードが実際に参照する機能のポリフィルのみをファイルごとに注入する。'usage'はほぼ常に望ましい選択だ。ターゲットマトリクス全体ではなく、実際の使用状況に対してポリフィルを配信するからだ。どちらもインストールされているマイナーリリースにピン留めしたcorejs バージョンが必要だ。
CloudflareまたはFastlyのミラーを通じてpolyfill.ioを使い続けることは安全ですか?
CloudflareとFastlyのミラーは既存のサイトを機能させ続けるが、リモートポリフィルサービスのパターン自体を正当化するものではない。2024年初頭にpolyfill.ioドメインが所有権を変更し、2024年6月25日にSansecがサービスがマルウェアを注入していたと報告した後、セキュリティを重視するチームにとってサードパーティCDNからブラウザ対応のポリフィルを読み込むことは擁護できなくなった。cdn.polyfill.ioのスクリプトタグを完全に削除し、本当に必要なポリフィルは自分のバンドルに移すべきだ。そうすれば管理とレビューを自分でコントロールできる。
エバーグリーンブラウザのみをターゲットとするアプリでもcore-jsは必要ですか?
2026年においてエバーグリーンをターゲットとするほとんどのアプリでは、Array.flat、Object.entries、Promise.allSettled、structuredClone、fetchのような機能はすでに広くサポートされているため、core-jsが配信する有用なポリフィルはほぼゼロに近い。明確な例外はDecorators(ネイティブブラウザ実装がない)と、クロスブラウザロールアウトが不均一なTemporal移行期間だ。本番ビルドに対してsource-map-explorerを実行してどのcore-jsモジュールが含まれているかを確認し、Browserslistのターゲットを絞り込み、useBuiltInsを'usage'に切り替えて不要な重荷を削除しよう。