Polyfill (поліфілл) — код, який емулює відсутню функціональність (API, методи, об'єкти) у середовищах, де вона не реалізована нативно. Polyfill дозволяє використовувати сучасні можливості JavaScript, CSS або Web API в старих браузерах і рантаймах. За даними MDN Web Docs, поліфілли є ключовим інструментом прогресивного покращення та забезпечення крос-браузерної сумісності.
Головне
Polyfill — фрагмент коду (зазвичай JavaScript), який реалізує функціональність, яку середовище виконання не підтримує нативно. Термін запропонував Ремі Шарп у 2009 році як гру слів: Polyfill — аналог шпаклівки (Polyfilla), яка заповнює тріщини в стіні. Polyfill заповнює прогалини між стандартом та підтримкою в конкретному браузері або рантаймі.
Polyfill не змінює існуючий код — він розширює середовище виконання. Якщо браузер не підтримує Array.prototype.includes, поліфілл додає цей метод у прототип Array до виконання основного коду. Поліфілли можуть емулювати нові глобальні об'єкти (Promise, Map, Set, Symbol), статичні методи (Array.from, Object.assign) та методи прототипів.
Feature detection — обов'язковий механізм перед встановленням поліфілла. Замість перевірки user-agent (який браузер), слід перевіряти наявність методу: if (!Array.prototype.includes) { Array.prototype.includes = ... }. Це гарантує, що поліфілл не перезапише нативну реалізацію, якщо вона вже існує. Google Analytics та інші сервіси збирають дані про підтримку API для аналізу.
Перші поліфілли з'явилися в епоху Internet Explorer 6–8 (2005–2009), коли розробники виявили розрив між стандартами W3C та реалізацією в браузерах. Термін ввів Ремі Шарп у 2009 році на конференції BarCamp London. Першим масовим поліфіллом став html5shiv (2009) — бібліотека, яка додає підтримку HTML5-тегів (<section>, <article>, <nav>) в Internet Explorer.
З появою ES6 (2015) та річного циклу оновлень ECMAScript кількість необхідних поліфіллів зросла. Щороку стандарт додає нові методи (Array.includes, String.padStart, Object.fromEntries, Promise.allSettled), які не підтримуються старими браузерами. core-js, розпочатий як es6-shim у 2014, став універсальним рішенням. На 2026 рік core-js містить понад 5000 модулів поліфіллів для ES5–ES2025.
| Категорія | Можна поліфіллити | Не можна поліфіллити |
|---|---|---|
| Методи прототипів | Array.includes, String.startsWith | — |
| Глобальні об'єкти | Promise, Map, Set, Symbol | — |
| Статичні методи | Object.assign, Array.from | — |
| Синтаксис мови | — | Arrow functions, async/await, class |
| Web API | fetch, IntersectionObserver | Service Worker (вимагає нативної підтримки) |
Транспіляція перетворює новий синтаксис на старий (const → var, () => {} → function() {}). Polyfill додає відсутні методи та об'єкти (Promise, Array.includes). Ці два механізми доповнюють один одного: транспіляція робить код синтаксично сумісним, поліфілли забезпечують повноту API. Babel + core-js — стандартна комбінація для повної підтримки.
Babel @babel/preset-env з опцією useBuiltIns визначає, які поліфілли потрібні на основі target-браузерів. useBuiltIns: "usage" аналізує, які API використовуються в коді, та підключає тільки потрібні поліфілли з core-js. useBuiltIns: "entry" підключає всі поліфілли для target-браузерів через єдиний імпорт core-js/stable.
// Перевірка наявності та додавання поліфілла
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,
});
}
// Використання — тепер безпечно в будь-якому браузері
const arr = [1, 2, 3, 4, 5];
console.log(arr.includes(3)); // trueПоліфілл для Array.prototype.includes перевіряє, чи визначено метод у прототипі Array. Якщо ні — створює властивість через Object.defineProperty з прапорами writable: true, configurable: true. Реалізація слідує специфікації ES2016: перевірка null/undefined, перетворення в об'єкт, робота з від'ємним fromIndex. Після додавання поліфілла виклик arr.includes(3) працює у всіх браузерах, включаючи Internet Explorer 11.
core-js — найповніша бібліотека поліфіллів JavaScript, яка підтримує всі stage-4 пропозиції TC39 (ECMAScript стандарт). core-js містить поліфілли для Promise, Symbol, Map, Set, WeakMap, WeakSet, методи Array, методи String, методи Object, методи Number, методи Math, Reflect, globalThis та всіх stage-4 proposals. Актуальна версія core-js 3.38+ покриває ES5–ES2025.
core-js інтегрується з Babel через @babel/preset-env та опцію useBuiltIns. Без цієї інтеграції розробнику довелося б вручну імпортувати кожен поліфілл: import "core-js/stable/array/includes". @babel/preset-env автоматично додає необхідні імпорти на основі target-браузерів з .browserslistrc. Це зменшує розмір бандла — підключаються тільки потрібні поліфілли.
Fetch API — один із найчастіше поліфіллимих Web API. Нативна реалізація fetch доступна в Chrome 42+ (2015), Safari 10.1+ (2017), Firefox 39+ (2015), але відсутня в Internet Explorer та старих WebView. Поліфілл whatwg-fetch емулює fetch через XMLHttpRequest. Альтернатива — використовуємо isomorphic-fetch (поліфілл для Node.js та браузера) або універсальну бібліотеку axios, яка не потребує поліфіллів.
// Завантаження поліфілла fetch тільки для старих браузерів
if (typeof self.fetch !== "function") {
import("whatwg-fetch").then(module => {
self.fetch = module.fetch;
console.log("fetch polyfill loaded");
});
}
// Використання fetch (працює і з поліфіллом, і з нативним 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);
}
}Динамічний import поліфілла fetch через import() гарантує, що сучасні браузери не завантажать зайвий код. Поліфілл завантажується асинхронно і не блокує основний потік. Після завантаження self.fetch замінює нативну реалізацію або додає відсутню. Це техніка прогресивного enhancement: сучасні браузери отримують тільки нативний код, старі — додатковий поліфілл.
// 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 — цільові браузери
> 0.5%
last 2 versions
not dead
not op_mini all
ie >= 11
not ios_saf < 12useBuiltIns: "usage" аналізує код та додає тільки ті поліфілли, які реально використовуються. corejs.version вказує версію core-js в проєкті. targets.browsers визначає мінімальний рівень браузерів — чим древніші браузери, тим більше поліфіллів буде підключено. .browserslistrc використовується не тільки Babel, але й Autoprefixer, PostCSS та Stylelint для узгодженого таргетингу.
Polyfill.io — сервіс (та однойменна бібліотека), який динамічно визначає, які поліфілли потрібні браузеру користувача, та повертає тільки їх. Polyfill.io використовує заголовок User-Agent для визначення версії браузера та підставляє мінімальний набір поліфіллів. Це зменшує розмір переданих даних порівняно з універсальним бандлом поліфіллів.
Підключення Polyfill.io виконується через <script>-тег перед основним кодом додатку. Сервіс аналізує User-Agent та повертає JavaScript-файл з поліфіллами тільки для цього браузера. Chrome не отримає жодного поліфілла, IE 11 отримає повний набір. Це оптимальний підхід для продуктивності: сучасні браузери не завантажують зайвий код.
<!-- Polyfill.io: динамічне завантаження -->
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=Promise%2CArray.prototype.includes%2CObject.assign%2Cfetch"></script>
<!-- Локальна версія Polyfill.io -->
<script src="/js/polyfill.js"></script>
<script>
// feature detection for fetch
if (!self.fetch) {
loadScript("/js/fetch-polyfill.js");
}
</script>Параметр features в URL Polyfill.io вказує, які поліфілли завантажувати. Можливі значення: назви методів (Array.prototype.includes), глобальних об'єктів (Promise) або прапори (es6, es2016). Прапор "default" підключає базовий набір для сучасного JavaScript. Для production-проєктів рекомендується розміщувати Polyfill.io на власному CDN або використовувати локальну версію бібліотеки для контролю над доступністю.
WebView в мобільних додатках (Android WebView, WKWebView на iOS) — особливе середовище для поліфіллів. Версія WebView залежить від версії ОС та встановленого оновлення Chrome System WebView (Android) або WKWebView від iOS Safari. У старих версіях Android (4.4, 5.0) WebView заснований на Chromium 30–37 — без підтримки fetch, Promise, IntersectionObserver.
React Native використовує JavaScriptCore (iOS) або Hermes (Android) — ці рушії реалізують ES6+ по-різному. JavaScriptCore на iOS підтримує більшість ES6-фіч, але може не мати деяких stage-3 пропозицій. Hermes (використовуваний за замовчуванням в React Native 0.70+) підтримує обмежений набір ES-стандарту — для нього поліфілли обов'язкові.
// feature detection для WebView
const polyfills = [];
// Promise
if (typeof Promise === "undefined") {
polyfills.push("Promise");
}
// Fetch API
if (typeof self.fetch === "undefined") {
polyfills.push("fetch");
}
// IntersectionObserver (потрібен для лінивого завантаження)
if (typeof IntersectionObserver === "undefined") {
polyfills.push("IntersectionObserver");
}
// Динамічне завантаження поліфіллів
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 для WebView перевіряє наявність критичних API (Promise, fetch, IntersectionObserver) та динамічно завантажує поліфілли тільки для відсутніх. Це гарантує, що сучасні WebView (Chrome 100+ на Android 12) не завантажують зайвий код, а старі WebView (Android 5.0) отримують необхідну підтримку.
Часті запитання
React Native на Hermes вимагає поліфілли для деяких ES-методів: Array.flat, Array.flatMap, globalThis, TextEncoder. Рекомендується підключати core-js або react-native-polyfill-globals для продакшен-збірок. JavaScriptCore на iOS підтримує більше фіч, але також може вимагати поліфілли для stage-3 пропозицій.
Поліфілли знижують продуктивність на 1–5%, оскільки JavaScript-реалізація повільніша за нативну C++ реалізацію в рушії. Наприклад, поліфілл Promise на чистому JS повільніший за нативний Promise у V8. Однак для більшості додатків різниця непомітна. Для критичного коду рекомендується перевіряти наявність нативної реалізації через feature detection.
Транспіляція перетворює синтаксис: const → var, стрілкові функції → function. Поліфілл додає нові об'єкти/методи: Promise, Array.includes, fetch. Транспіляція працює на етапі збірки, поліфілл завантажується в runtime. Обидва механізми необхідні для повної підтримки сучасного коду в старих середовищах.
Можна, якщо target-аудиторія використовує тільки сучасні браузери (Chrome 90+, Safari 15+, Firefox 90+). Для проєктів з підтримкою старих пристроїв або корпоративних користувачів (Internet Explorer 11 досі використовується в держсекторі) поліфілли обов'язкові. Аналізуйте статистику браузерів вашої аудиторії через Google Analytics.
core-js в повній збірці важить ~85 КБ (gzip). При використанні useBuiltIns: "usage" в Babel підключаються тільки потрібні поліфілли, що зменшує розмір до 5–30 КБ залежно від target-браузерів. Для сучасних браузерів (Chrome 100+) може не знадобитися жодного поліфілла.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також