Polyfill è un codice che emula funzionalità mancanti (API, metodi, oggetti) in ambienti in cui non sono implementate nativamente. Polyfill consente di utilizzare funzionalità moderne di JavaScript, CSS o Web API in browser vecchi e runtime. Secondo MDN Web Docs, i polyfill sono uno strumento chiave per il miglioramento progressivo e la compatibilità tra browser.
Punti chiave
Polyfill è un frammento di codice (di solito JavaScript) che implementa funzionalità che l'ambiente di esecuzione non supporta nativamente. Il termine è stato coniato da Remy Sharp nel 2009 come un gioco di parole: Polyfill è analogo a Polyfilla, uno stucco che riempie le crepe in un muro. Polyfill colma le lacune tra lo standard e il suo supporto in un browser o runtime specifico.
Polyfill non modifica il codice esistente — estende l'ambiente di esecuzione. Se un browser non supporta Array.prototype.includes, il polyfill aggiunge questo metodo al prototipo Array prima dell'esecuzione del codice principale. I polyfill possono emulare nuovi oggetti globali (Promise, Map, Set, Symbol), metodi statici (Array.from, Object.assign) e metodi di prototipo.
Rilevamento delle funzionalità è un meccanismo obbligatorio prima di installare un polyfill. Invece di controllare lo user-agent (quale browser), si dovrebbe verificare l'esistenza del metodo: if (!Array.prototype.includes) { Array.prototype.includes = ... }. Questo garantisce che il polyfill non sovrascriva l'implementazione nativa se esiste già. Google Analytics e altri servizi raccolgono dati di supporto API per l'analisi.
I primi polyfill sono apparsi nell'era di Internet Explorer 6–8 (2005–2009), quando gli sviluppatori hanno scoperto un divario tra gli standard W3C e le implementazioni dei browser. Il termine è stato introdotto da Remy Sharp nel 2009 al BarCamp London. Il primo polyfill di massa è stato html5shiv (2009) — una libreria che aggiunge il supporto per i tag HTML5 (<section>, <article>, <nav>) in Internet Explorer.
Con l'avvento di ES6 (2015) e del ciclo annuale di aggiornamenti ECMAScript, il numero di polyfill necessari è cresciuto. Ogni anno lo standard aggiunge nuovi metodi (Array.includes, String.padStart, Object.fromEntries, Promise.allSettled) che non sono supportati dai browser vecchi. core-js, nato come es6-shim nel 2014, è diventato una soluzione universale. Nel 2026, core-js contiene oltre 5.000 moduli di polyfill per ES5–ES2025.
| Categoria | Può essere polyfillato | Non può essere polyfillato |
|---|---|---|
| Metodi di prototipo | Array.includes, String.startsWith | — |
| Oggetti globali | Promise, Map, Set, Symbol | — |
| Metodi statici | Object.assign, Array.from | — |
| Sintassi del linguaggio | — | Arrow functions, async/await, class |
| Web API | fetch, IntersectionObserver | Service Worker (richiede supporto nativo) |
Transpilazione converte la sintassi nuova in sintassi vecchia (const → var, () => {} → function() {}). Polyfill aggiunge metodi e oggetti mancanti (Promise, Array.includes). Questi due meccanismi si completano a vicenda: la transpilazione rende il codice sintatticamente compatibile, i polyfill garantiscono la completezza dell'API. Babel + core-js è la combinazione standard per il supporto completo.
Babel @babel/preset-env con l'opzione useBuiltIns determina quali polyfill sono necessari in base ai browser target. useBuiltIns: "usage" analizza quali API vengono utilizzate nel codice e importa solo i polyfill necessari da core-js. useBuiltIns: "entry" importa tutti i polyfill per i browser target tramite un singolo import core-js/stable.
// Verifica dell'esistenza e aggiunta del polyfill
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,
});
}
// Utilizzo — ora sicuro in qualsiasi browser
const arr = [1, 2, 3, 4, 5];
console.log(arr.includes(3)); // truePolyfill per Array.prototype.includes verifica se il metodo è definito sul prototipo Array. In caso contrario, crea la proprietà tramite Object.defineProperty con i flag writable: true, configurable: true. L'implementazione segue la specifica ES2016: controllo null/undefined, conversione in oggetto, gestione di fromIndex negativo. Dopo l'aggiunta del polyfill, la chiamata arr.includes(3) funziona in tutti i browser, incluso Internet Explorer 11.
core-js è la libreria di polyfill JavaScript più completa, che supporta tutte le proposte stage-4 di TC39 (standard ECMAScript). core-js include polyfill per Promise, Symbol, Map, Set, WeakMap, WeakSet, metodi Array, metodi String, metodi Object, metodi Number, metodi Math, Reflect, globalThis e tutte le proposte stage-4. La versione attuale core-js 3.38+ copre ES5–ES2025.
core-js si integra con Babel tramite @babel/preset-env e l'opzione useBuiltIns. Senza questa integrazione, gli sviluppatori dovrebbero importare manualmente ogni polyfill: import "core-js/stable/array/includes". @babel/preset-env aggiunge automaticamente le importazioni necessarie in base ai browser target da .browserslistrc. Questo riduce la dimensione del bundle — solo i polyfill necessari vengono inclusi.
Fetch API è una delle Web API più frequentemente polyfillate. L'implementazione nativa di fetch è disponibile in Chrome 42+ (2015), Safari 10.1+ (2017), Firefox 39+ (2015), ma è assente in Internet Explorer e WebView vecchi. Il polyfill whatwg-fetch emula fetch tramite XMLHttpRequest. Alternativa — utilizzare isomorphic-fetch (un polyfill per Node.js e browser) o la libreria universale axios, che non richiede polyfill.
// Caricare polyfill fetch solo per browser vecchi
if (typeof self.fetch !== "function") {
import("whatwg-fetch").then(module => {
self.fetch = module.fetch;
console.log("fetch polyfill loaded");
});
}
// Usare fetch (funziona sia con polyfill che con API nativa)
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 dinamico del polyfill fetch tramite import() garantisce che i browser moderni non carichino codice non necessario. Il polyfill viene caricato in modo asincrono e non blocca il thread principale. Dopo il caricamento, self.fetch sostituisce l'implementazione nativa o aggiunge quella mancante. Questa è una tecnica di miglioramento progressivo: i browser moderni ricevono solo codice nativo, quelli vecchi ricevono il polyfill aggiuntivo.
// 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 — browser target
> 0.5%
last 2 versions
not dead
not op_mini all
ie >= 11
not ios_saf < 12useBuiltIns: "usage" analizza il codice e aggiunge solo i polyfill effettivamente utilizzati. corejs.version specifica la versione di core-js nel progetto. targets.browsers definisce il livello minimo di browser — più i browser target sono vecchi, più polyfill verranno inclusi. .browserslistrc è utilizzato non solo da Babel ma anche da Autoprefixer, PostCSS e Stylelint per un targeting coerente.
Polyfill.io è un servizio (e una libreria omonima) che determina dinamicamente quali polyfill il browser dell'utente necessita e restituisce solo quelli. Polyfill.io utilizza l'intestazione User-Agent per determinare la versione del browser e fornisce un set minimo di polyfill. Questo riduce la quantità di dati trasferiti rispetto a un bundle universale di polyfill.
La connessione di Polyfill.io avviene tramite un tag <script> prima del codice principale dell'applicazione. Il servizio analizza lo User-Agent e restituisce un file JavaScript con polyfill solo per quel browser. Chrome non riceverà alcun polyfill, IE 11 riceverà il set completo. Questo è un approccio ottimale per le prestazioni: i browser moderni non caricano codice non necessario.
<!-- Polyfill.io: caricamento dinamico -->
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=Promise%2CArray.prototype.includes%2CObject.assign%2Cfetch"></script>
<!-- Versione locale di Polyfill.io -->
<script src="/js/polyfill.js"></script>
<script>
// feature detection for fetch
if (!self.fetch) {
loadScript("/js/fetch-polyfill.js");
}
</script>Il parametro features nell'URL di Polyfill.io specifica quali polyfill caricare. Valori possibili: nomi di metodi (Array.prototype.includes), oggetti globali (Promise) o flag (es6, es2016). Il flag "default" carica un set base per JavaScript moderno. Per i progetti di produzione, si consiglia di ospitare Polyfill.io sul proprio CDN o utilizzare una versione locale della libreria per il controllo della disponibilità.
WebView nelle applicazioni mobili (Android WebView, WKWebView su iOS) è un ambiente speciale per i polyfill. La versione di WebView dipende dalla versione del sistema operativo e dall'aggiornamento installato di Chrome System WebView (Android) o WKWebView di iOS Safari. Nelle versioni vecchie di Android (4.4, 5.0), WebView si basa su Chromium 30–37 — senza supporto per fetch, Promise, IntersectionObserver.
React Native utilizza JavaScriptCore (iOS) o Hermes (Android) — questi motori implementano ES6+ in modo diverso. JavaScriptCore su iOS supporta la maggior parte delle funzionalità ES6, ma potrebbe non avere alcune proposte stage-3. Hermes (utilizzato per impostazione predefinita in React Native 0.70+) supporta un set limitato dello standard ES — i polyfill sono obbligatori per esso.
// feature detection per WebView
const polyfills = [];
// Promise
if (typeof Promise === "undefined") {
polyfills.push("Promise");
}
// Fetch API
if (typeof self.fetch === "undefined") {
polyfills.push("fetch");
}
// IntersectionObserver (necessario per lazy loading)
if (typeof IntersectionObserver === "undefined") {
polyfills.push("IntersectionObserver");
}
// Caricamento dinamico di polyfill
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);
}Rilevamento delle funzionalità per WebView verifica la presenza di API critiche (Promise, fetch, IntersectionObserver) e carica dinamicamente polyfill solo per quelle mancanti. Questo garantisce che i WebView moderni (Chrome 100+ su Android 12) non carichino codice non necessario, mentre i WebView vecchi (Android 5.0) ottengano il supporto necessario.
Domande frequenti
React Native su Hermes richiede polyfill per alcuni metodi ES: Array.flat, Array.flatMap, globalThis, TextEncoder. Si consiglia di includere core-js o react-native-polyfill-globals per le build di produzione. JavaScriptCore su iOS supporta più funzionalità, ma potrebbe anche richiedere polyfill per proposte stage-3.
I polyfill riducono le prestazioni dell'1–5%, poiché l'implementazione JavaScript è più lenta dell'implementazione nativa in C++ nel motore. Ad esempio, un polyfill di Promise in JS puro è più lento di un Promise nativo in V8. Tuttavia, per la maggior parte delle applicazioni la differenza è trascurabile. Per il codice critico, si consiglia di verificare l'implementazione nativa tramite rilevamento delle funzionalità.
Transpilazione converte la sintassi: const → var, funzioni freccia → function. Polyfill aggiunge nuovi oggetti/metodi: Promise, Array.includes, fetch. La transpilazione funziona al momento della build, il polyfill viene caricato in fase di esecuzione. Entrambi i meccanismi sono necessari per il supporto completo del codice moderno in ambienti vecchi.
Sì, se il tuo pubblico di destinazione utilizza solo browser moderni (Chrome 90+, Safari 15+, Firefox 90+). Per i progetti che supportano dispositivi vecchi o utenti aziendali (Internet Explorer 11 è ancora utilizzato nel settore pubblico), i polyfill sono obbligatori. Analizza le statistiche dei browser del tuo pubblico tramite Google Analytics.
core-js in una build completa pesa circa 85 KB (gzip). Utilizzando useBuiltIns: "usage" in Babel, vengono inclusi solo i polyfill necessari, riducendo la dimensione a 5–30 KB a seconda dei browser target. Per i browser moderni (Chrome 100+), potrebbe non essere necessario alcun polyfill.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche