Shimming è una tecnica per garantire la compatibilità di moduli che si aspettano determinate variabili globali o API. Nell'ecosistema Webpack, lo shimming viene implementato tramite ProvidePlugin, imports-loader ed exports-loader, consentendo di collegare librerie legacy senza modificarne il codice sorgente. Secondo la Webpack Documentation (2026), lo shimming rimane uno strumento chiave per l'integrazione di plugin jQuery e di altre dipendenze che non supportano il sistema modulare.
Punti chiave
Shimming è una tecnica software che incorpora un livello di compatibilità tra il codice e l'ambiente senza modificare il codice sorgente del modulo. Nel contesto di un build JavaScript, lo shimming risolve il problema quando un modulo accede a variabili globali (window.$, global.process) che sono assenti nell'ambiente modulare.
Polyfill implementa la funzionalità mancante da zero, aggiungendo nuove capacità all'ambiente. Ad esempio, core-js aggiunge Array.prototype.flatMap per i browser più vecchi. Shim, invece, reindirizza le chiamate esistenti verso implementazioni disponibili o sostituisce gli oggetti globali attesi. In Webpack, ProvidePlugin inserisce automaticamente import $ from 'jquery' ovunque venga trovato un riferimento alla variabile globale $, senza richiedere modifiche al codice.
La differenza principale sta nell'obiettivo. Polyfill aggiunge ciò che non esiste, mentre shim rende il codice esistente compatibile con l'ambiente in cui viene eseguito. La scelta tra loro dipende dal problema da risolvere: assenza di API o incompatibilità delle interfacce.
Webpack tratta ogni modulo come un'unità isolata con il proprio ambito. Se una libreria accede alla variabile globale jQuery come window.$, il build fallirà con un errore, poiché questa variabile non esiste nel contesto modulare. ProvidePlugin risolve il problema in fase di compilazione: quando rileva l'identificatore $ nel codice, il plugin inserisce automaticamente import $ from 'jquery' all'inizio del file.
// Codice sorgente (il modulo legacy accede a jQuery globale)
$('.element').hide();
// Dopo l'elaborazione di ProvidePlugin (Webpack inserisce l'import)
import $ from 'jquery';
$('.element').hide();
Inoltre, imports-loader consente di specificare esplicitamente quali dipendenze deve ricevere un modulo. Ciò è utile quando una libreria usa this a livello superiore, aspettandosi che this faccia riferimento a window e non a module.exports.
ProvidePlugin è un plugin integrato di Webpack che carica automaticamente i moduli quando rileva riferimenti a identificatori specificati. La configurazione è un oggetto in cui la chiave è il nome della variabile e il valore è il percorso del modulo e il campo esportato.
// webpack.config.js
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
_: 'lodash',
'window.$': 'jquery',
}),
],
};
ProvidePlugin supporta l'importazione parziale tramite la sintassi degli array. Ad esempio, [lodash, debounce] importa solo la funzione debounce da lodash, riducendo le dimensioni del bundle finale. Ciò è particolarmente importante per i progetti mobile, dove ogni kilobyte influisce sui tempi di caricamento.
imports-loader aggiunge gli import necessari all'inizio di un modulo, mentre exports-loader definisce i valori esportati per i moduli che non usano module.exports esplicitamente. Questi loader lavorano a livello di singoli file, non globalmente come ProvidePlugin.
// webpack.config.js — configurazione di imports-loader
module.exports = {
module: {
rules: [
{
test: /legacy-module\.js$/,
use: [
{
loader: 'imports-loader',
options: {
imports: [
'jquery',
'$',
],
},
},
],
},
],
},
};
exports-loader viene utilizzato quando una libreria assegna un valore a una variabile globale ma non lo esporta tramite il sistema di moduli. Il loader estrae il valore e lo trasforma in un export di modulo, consentendo ad altri moduli di importarlo tramite import.
Shimming viene configurato in webpack.config.js tramite una combinazione di plugin e loader. Uno scenario tipico include ProvidePlugin per le variabili globali e imports-loader per i moduli specifici che richiedono un cambio di ambito.
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
globalObject: 'this',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules\/(?!legacy-lib)/,
use: [
{
loader: 'imports-loader',
options: {
type: 'commonjs',
imports: ['jquery', '$'],
},
},
],
},
],
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
}),
],
};
Il campo globalObject in output definisce il contesto per i riferimenti a this a livello superiore. Per un ambiente browser, il valore 'this' fa riferimento a window, mentre per React Native o Node.js fa riferimento a global. Scegliere il valore corretto previene errori di esecuzione nell'ambiente di destinazione.
Shimming è uno strumento potente ma pericoloso. Una configurazione errata porta alla duplicazione del codice nel bundle, a conflitti di nomi e a errori di esecuzione imprevisti. Gli sviluppatori dimenticano spesso che ProvidePlugin lavora in fase di compilazione e non può gestire riferimenti dinamici alle variabili.
Se due plugin usano versioni diverse di jQuery, ProvidePlugin sostituirà solo una di esse, quella specificata per prima nella configurazione. La seconda libreria riceverà una versione incompatibile, causando errori difficili da debuggare. La soluzione è usare exports-loader per ogni libreria con una versione esplicita oppure applicare webpack.IgnorePlugin per escludere i moduli duplicati.
Un altro errore comune è tentare di shimare moduli che usano chiamate require sincrone di CommonJS in un contesto dinamico. ProvidePlugin elabora solo identificatori statici, quindi i riferimenti dinamici devono essere sostituiti manualmente o con NormalModuleReplacementPlugin.
Una configurazione errata dello shimming può portare a un aumento significativo delle dimensioni del bundle. Se ProvidePlugin è configurato per decine di variabili globali, Webpack inserirà gli import corrispondenti in tutti i file del progetto, indipendentemente dal fatto che quelle variabili siano usate in ogni singolo file. Questo crea codice ridondante, soprattutto in progetti di grandi dimensioni con migliaia di moduli.
Per diagnosticare i problemi con lo shimming, usa webpack-bundle-analyzer — uno strumento per visualizzare la composizione del bundle. Se jQuery o un'altra libreria appare più volte nel bundle, probabilmente versioni diverse sono in conflitto o ProvidePlugin è configurato per più identificatori che portano a versioni diverse del pacchetto. La soluzione è unificare le versioni delle dipendenze tramite resolve.alias e verificare che tutti gli identificatori shimmati puntino allo stesso modulo.
Prima di applicare lo shimming, valuta la possibilità di aggiornare la libreria a una versione che supporti il sistema modulare. Molti pacchetti legacy hanno alternative moderne che non richiedono shimming. Ad esempio, i plugin jQuery possono essere sostituiti con API native del browser: $.ajax → fetch, $.each → Array.forEach. Il refactoring offre un vantaggio a lungo termine nella manutenzione, mentre lo shimming è una soluzione temporanea che complica la configurazione.
Se l'aggiornamento non è possibile, considera NormalModuleReplacementPlugin, che consente di sostituire un modulo con un altro a livello di risoluzione senza modificare il codice sorgente. Questo plugin lavora nella fase di costruzione del grafo delle dipendenze, prima dell'applicazione dei loader, e gestisce tutti i riferimenti al modulo indipendentemente dal contesto. È una soluzione più pulita per sostituire intere librerie rispetto ai loader puntuali.
Con lo sviluppo dei moduli ES nativi nei browser e l'avvento degli import maps, alcuni scenari di shimming possono essere risolti senza Webpack. Gli import maps consentono di riassegnare i nomi dei moduli al volo a livello di browser, senza fase di build. Tuttavia, questo approccio non è supportato in React Native e in altri ambienti senza ESM del browser, quindi lo shimming tramite Webpack rimane rilevante per i build di produzione che richiedono il controllo completo sulle dipendenze e le loro versioni. La scelta tra import maps e shim di Webpack dipende dalla piattaforma di destinazione e dai requisiti di compatibilità con i browser più vecchi.
Domande frequenti
Shimming aggiunge codice per garantire la compatibilità, mentre tree shaking rimuove il codice inutilizzato. Queste tecniche hanno obiettivi opposti: lo shimming aumenta le dimensioni del bundle, il tree shaking le riduce. In un build di produzione, entrambe vengono applicate in sequenza.
Sì, lo shimming esiste come tecnica indipendente da Webpack — ad esempio, tramite script globali nell'HTML o tramite moduli ES con riesportazione. Tuttavia, Webpack fornisce gli strumenti di automazione più convenienti: ProvidePlugin e loader che non richiedono modifiche manuali al codice.
ProvidePlugin non influisce sulla velocità del build perché lavora nella fase di compilazione dell'AST. imports-loader ed exports-loader aggiungono un piccolo tempo di elaborazione per ogni file. Quando usati su centinaia di file, la differenza può essere del 5–15% del tempo totale del build.
Se tutte le dipendenze supportano i moduli ES e il sistema modulare, lo shimming è superfluo. Rinunciare allo shimming semplifica la configurazione, riduce le dimensioni del bundle e diminuisce il rischio di conflitti di nomi. Si consiglia di verificare le dipendenze su caniuse.com.
TypeScript richiede dichiarazioni di tipo aggiuntive per le variabili shimmate. È necessario aggiungere declare const $: any o installare i tipi tramite @types/jquery. ProvidePlugin inserisce gli import a livello JavaScript dopo la compilazione TypeScript, quindi i tipi vengono verificati separatamente.
Sintesi
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