Polyfill (polifill) — kod emulujący brakującą funkcjonalność (API, metody, obiekty) w środowiskach, gdzie nie jest ona zaimplementowana natywnie. Polyfill umożliwia korzystanie z nowoczesnych możliwości JavaScript, CSS lub Web API w starszych przeglądarkach i środowiskach uruchomieniowych. Według MDN Web Docs, polifille są kluczowym narzędziem progresywnego ulepszania i zapewniania kompatybilności międzyprzeglądarkowej.
Najważniejsze
Polyfill — fragment kodu (zwykle JavaScript) implementujący funkcjonalność, której środowisko wykonawcze nie obsługuje natywnie. Termin został zaproponowany przez Remy Sharp w 2009 roku jako gra słów: Polyfill — analogia szpachli (Polyfilla), wypełniającej pęknięcia w ścianie. Polyfill wypełnia luki między standardem a wsparciem w konkretnej przeglądarce lub środowisku wykonawczym.
Polyfill nie zmienia istniejącego kodu — rozszerza środowisko wykonawcze. Jeśli przeglądarka nie obsługuje Array.prototype.includes, polifill dodaje tę metodę do prototypu Array przed wykonaniem głównego kodu. Polifile mogą emulować nowe globalne obiekty (Promise, Map, Set, Symbol), statyczne metody (Array.from, Object.assign) i metody prototypów.
Feature detection — obowiązkowy mechanizm przed instalacją polifilla. Zamiast sprawdzania user-agent (jaka przeglądarka), należy sprawdzić obecność metody: if (!Array.prototype.includes) { Array.prototype.includes = ... }. Gwarantuje to, że polifill nie nadpisze natywnej implementacji, jeśli już istnieje. Google Analytics i inne usługi zbierają dane o wsparciu API do analizy.
Pierwsze polifile pojawiły się w erze Internet Explorer 6–8 (2005–2009), gdy programiści odkryli rozbieżność między standardami W3C a implementacją w przeglądarkach. Termin wprowadził Remy Sharp w 2009 roku na konferencji BarCamp London. Pierwszym masowym polifillem był html5shiv (2009) — biblioteka dodająca obsługę tagów HTML5 (<section>, <article>, <nav>) w Internet Explorer.
Wraz z pojawieniem się ES6 (2015) i rocznym cyklem aktualizacji ECMAScript liczba niezbędnych polifili wzrosła. Każdego roku standard dodaje nowe metody (Array.includes, String.padStart, Object.fromEntries, Promise.allSettled), które nie są obsługiwane przez starsze przeglądarki. core-js, rozpoczęty jako es6-shim w 2014, stał się uniwersalnym rozwiązaniem. Na 2026 rok core-js zawiera ponad 5000 modułów polifili dla ES5–ES2025.
| Kategoria | Można polifillować | Nie można polifillować |
|---|---|---|
| Metody prototypów | Array.includes, String.startsWith | — |
| Globalne obiekty | Promise, Map, Set, Symbol | — |
| Statyczne metody | Object.assign, Array.from | — |
| Składnia języka | — | Arrow functions, async/await, class |
| Web API | fetch, IntersectionObserver | Service Worker (wymaga natywnego wsparcia) |
Transpilacja przekształca nową składnię w starą (const → var, () => {} → function() {}). Polyfill dodaje brakujące metody i obiekty (Promise, Array.includes). Te dwa mechanizmy uzupełniają się: transpilacja zapewnia zgodność składniową, polifile zapewniają kompletność API. Babel + core-js — standardowa kombinacja dla pełnego wsparcia.
Babel @babel/preset-env z opcją useBuiltIns określa, które polifile są potrzebne na podstawie target-przeglądarek. useBuiltIns: „usage” analizuje, które API są używane w kodzie i podłącza tylko potrzebne polifile z core-js. useBuiltIns: „entry” podłącza wszystkie polifile dla target-przeglądarek przez pojedynczy import core-js/stable.
// Sprawdzenie obecności i dodanie polifilla
if (typeof Array.prototype.includes !== "function") {
Object.defineProperty(Array.prototype, "includes", {
value: function(searchElement, fromIndex) {
if (this == null) {
throw new TypeError("Array.prototype.includes called on null or undefined");
}
var arr = Object(this);
var len = arr.length >>> 0;
if (len === 0) { return false; }
var start = fromIndex | 0;
var k = Math.max(start >= 0 ? start : len + start, 0);
while (k < len) {
if (arr[k] === searchElement) { return true; }
k++;
}
return false;
},
writable: true,
configurable: true,
});
}
// Użycie — teraz bezpieczne w każdej przeglądarce
const arr = [1, 2, 3, 4, 5];
console.log(arr.includes(3)); // truePolifill dla Array.prototype.includes sprawdza, czy metoda jest zdefiniowana w prototypie Array. Jeśli nie — tworzy właściwość przez Object.defineProperty z flagami writable: true, configurable: true. Implementacja jest zgodna ze specyfikacją ES2016: sprawdzanie null/undefined, konwersja na obiekt, działanie z ujemnym fromIndex. Po dodaniu polifilla wywołanie arr.includes(3) działa we wszystkich przeglądarkach, w tym Internet Explorer 11.
core-js — najpełniejsza biblioteka polifili JavaScript, obsługująca wszystkie propozycje stage-4 TC39 (standard ECMAScript). core-js zawiera polifile dla Promise, Symbol, Map, Set, WeakMap, WeakSet, metod Array, metod String, metod Object, metod Number, metod Math, Reflect, globalThis oraz wszystkich stage-4 proposals. Aktualna wersja core-js 3.38+ pokrywa ES5–ES2025.
core-js integruje się z Babel przez @babel/preset-env i opcję useBuiltIns. Bez tej integracji programista musiałby ręcznie importować każdy polifill: import „core-js/stable/array/includes”. @babel/preset-env automatycznie dodaje niezbędne importy na podstawie target-przeglądarek z .browserslistrc. Zmniejsza to rozmiar bundle — podłączane są tylko potrzebne polifile.
Fetch API — jedno z najczęściej polifillowanych Web API. Natywna implementacja fetch jest dostępna w Chrome 42+ (2015), Safari 10.1+ (2017), Firefox 39+ (2015), ale brakuje jej w Internet Explorer i starych WebView. Polifill whatwg-fetch emuluje fetch przez XMLHttpRequest. Alternatywa — używamy isomorphic-fetch (polifill dla Node.js i przeglądarki) lub uniwersalnej biblioteki axios, która nie wymaga polifili.
// Ładowanie polifilla fetch tylko dla starszych przeglądarek
if (typeof self.fetch !== "function") {
import("whatwg-fetch").then(module => {
self.fetch = module.fetch;
console.log("fetch polyfill loaded");
});
}
// Użycie fetch (działa zarówno z polifillem, jak i z natywnym API)
async function loadData() {
try {
const response = await fetch("https://api.example.com/data");
const json = await response.json();
return json;
} catch (error) {
console.error("Failed to load:", error);
}
}Dynamiczny import polifilla fetch przez import() gwarantuje, że nowoczesne przeglądarki nie załadują zbędnego kodu. Polifill jest ładowany asynchronicznie i nie blokuje głównego wątku. Po załadowaniu self.fetch zastępuje natywną implementację lub dodaje brakującą. To technika progresywnego enhancement: nowoczesne przeglądarki otrzymują tylko natywny kod, starsze — dodatkowy polifill.
// babel.config.js — core-js + preset-env
module.exports = {
presets: [
["@babel/preset-env", {
useBuiltIns: "usage",
corejs: {
version: "3.38",
proposals: true,
},
targets: {
browsers: ["> 0.5%", "not dead", "not op_mini all"],
},
}],
],
};# .browserslistrc — docelowe przeglądarki
> 0.5%
last 2 versions
not dead
not op_mini all
ie >= 11
not ios_saf < 12useBuiltIns: „usage” analizuje kod i dodaje tylko te polifile, które są rzeczywiście używane. corejs.version wskazuje wersję core-js w projekcie. targets.browsers określa minimalny poziom przeglądarek — im starsze przeglądarki, tym więcej polifili zostanie podłączonych. .browserslistrc jest używany nie tylko przez Babel, ale także przez Autoprefixer, PostCSS i Stylelint dla spójnego targetowania.
Polyfill.io — usługa (i biblioteka o tej samej nazwie), dynamicznie określająca, które polifile są potrzebne przeglądarce użytkownika i zwracająca tylko je. Polyfill.io używa nagłówka User-Agent do określenia wersji przeglądarki i dostarcza minimalny zestaw polifili. Zmniejsza to rozmiar przesyłanych danych w porównaniu z uniwersalnym bundle’em polifili.
Podłączenie Polyfill.io wykonuje się przez <script>-tag przed głównym kodem aplikacji. Usługa analizuje User-Agent i zwraca plik JavaScript z polifilami tylko dla tej przeglądarki. Chrome nie otrzyma żadnego polifilla, IE 11 otrzyma pełny zestaw. To optymalne podejście dla wydajności: nowoczesne przeglądarki nie ładują zbędnego kodu.
<!-- Polyfill.io: dynamiczne ładowanie -->
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=Promise%2CArray.prototype.includes%2CObject.assign%2Cfetch"></script>
<!-- Lokalna wersja Polyfill.io -->
<script src="/js/polyfill.js"></script>
<script>
// feature detection dla fetch
if (!self.fetch) {
loadScript("/js/fetch-polyfill.js");
}
</script>Parametr features w URL Polyfill.io określa, które polifile mają być ładowane. Możliwe wartości: nazwy metod (Array.prototype.includes), globalnych obiektów (Promise), lub flagi (es6, es2016). Flaga „default” podłącza podstawowy zestaw dla nowoczesnego JavaScript. Dla projektów produkcyjnych zaleca się umieszczenie Polyfill.io na własnym CDN lub użycie lokalnej wersji biblioteki w celu kontroli nad dostępnością.
WebView w aplikacjach mobilnych (Android WebView, WKWebView na iOS) — szczególne środowisko dla polifili. Wersja WebView zależy od wersji systemu operacyjnego i zainstalowanej aktualizacji Chrome System WebView (Android) lub WKWebView z iOS Safari. W starszych wersjach Android (4.4, 5.0) WebView bazuje na Chromium 30–37 — bez obsługi fetch, Promise, IntersectionObserver.
React Native używa JavaScriptCore (iOS) lub Hermes (Android) — te silniki implementują ES6+ w różny sposób. JavaScriptCore na iOS obsługuje większość funkcji ES6, ale może nie mieć niektórych propozycji stage-3. Hermes (używany domyślnie w React Native 0.70+) obsługuje ograniczony zestaw standardu ES — dla niego polifile są obowiązkowe.
// feature detection dla WebView
const polyfills = [];
// Promise
if (typeof Promise === "undefined") {
polyfills.push("Promise");
}
// Fetch API
if (typeof self.fetch === "undefined") {
polyfills.push("fetch");
}
// IntersectionObserver (potrzebny do leniwego ładowania)
if (typeof IntersectionObserver === "undefined") {
polyfills.push("IntersectionObserver");
}
// Dynamiczne ładowanie polifili
if (polyfills.length > 0) {
const script = document.createElement("script");
script.src = "https://cdn.polyfill.io/v3/polyfill.min.js"
+ "?features=" + polyfills.join(",");
document.head.appendChild(script);
}Feature detection dla WebView sprawdza obecność krytycznych API (Promise, fetch, IntersectionObserver) i dynamicznie ładuje polifile tylko dla brakujących. Gwarantuje to, że nowoczesne WebView (Chrome 100+ na Android 12) nie ładują zbędnego kodu, a stare WebView (Android 5.0) otrzymują niezbędne wsparcie.
Często zadawane pytania
React Native na Hermes wymaga polifili dla niektórych metod ES: Array.flat, Array.flatMap, globalThis, TextEncoder. Zaleca się podłączenie core-js lub react-native-polyfill-globals dla wersji produkcyjnych. JavaScriptCore na iOS obsługuje więcej funkcji, ale również może wymagać polifili dla propozycji stage-3.
Polifile obniżają wydajność o 1–5%, ponieważ implementacja w JavaScript jest wolniejsza od natywnej implementacji w C++ w silniku. Na przykład polifill Promise w czystym JS jest wolniejszy od natywnego Promise w V8. Jednak dla większości aplikacji różnica jest niezauważalna. Dla krytycznego kodu zaleca się sprawdzanie obecności natywnej implementacji przez feature detection.
Transpilacja przekształca składnię: const → var, funkcje strzałkowe → function. Polifill dodaje nowe obiekty/metody: Promise, Array.includes, fetch. Transpilacja działa na etapie budowania, polifill jest ładowany w runtime. Oba mechanizmy są niezbędne do pełnego wsparcia nowoczesnego kodu w starszych środowiskach.
Można, jeśli target-grupa odbiorców używa tylko nowoczesnych przeglądarek (Chrome 90+, Safari 15+, Firefox 90+). Dla projektów obsługujących starsze urządzenia lub użytkowników korporacyjnych (Internet Explorer 11 wciąż używany w sektorze rządowym) polifile są obowiązkowe. Analizuj statystyki przeglądarek swojej grupy odbiorców przez Google Analytics.
core-js w pełnej kompilacji waży ~85 KB (gzip). Przy użyciu useBuiltIns: „usage” w Babel podłączane są tylko potrzebne polifile, co zmniejsza rozmiar do 5–30 KB w zależności od target-przeglądarek. Dla nowoczesnych przeglądarek (Chrome 100+) może nie być wymagany żaden polifill.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również