Shimming est une technique permettant d'assurer la compatibilité de modules qui attendent certaines variables globales ou certaines APIs. Dans l'écosystème Webpack, le shimming est implémenté via ProvidePlugin, imports-loader et exports-loader, permettant de connecter des bibliothèques legacy sans modifier leur code source. Selon la Webpack Documentation (2026), le shimming reste un outil clé pour l'intégration de plugins jQuery et d'autres dépendances qui ne prennent pas en charge le système modulaire.
L'essentiel
Shimming est une technique logicielle qui intègre une couche de compatibilité entre le code et l'environnement sans modifier le code source du module. Dans le contexte d'un build JavaScript, le shimming résout le problème lorsqu'un module accède à des variables globales (window.$, global.process) qui sont absentes de l'environnement modulaire.
Polyfill implémente la fonctionnalité manquante à partir de zéro, en ajoutant de nouvelles capacités à l'environnement. Par exemple, core-js ajoute Array.prototype.flatMap pour les anciens navigateurs. Shim, quant à lui, redirige les appels existants vers des implémentations disponibles ou remplace les objets globaux attendus. Dans Webpack, ProvidePlugin insère automatiquement import $ from 'jquery' partout où une référence à la variable globale $ est rencontrée, sans exiger de modifications du code.
La différence principale réside dans l'objectif. Polyfill ajoute ce qui n'existe pas, tandis que shim rend le code existant compatible avec l'environnement dans lequel il s'exécute. Le choix entre eux dépend du problème à résoudre : absence d'API ou incompatibilité des interfaces.
Webpack traite chaque module comme une unité isolée avec sa propre portée. Si une bibliothèque accède à la variable globale jQuery comme window.$, le build échouera avec une erreur, car cette variable n'existe pas dans le contexte modulaire. ProvidePlugin résout le problème à l'étape de compilation : lorsqu'il détecte l'identifiant $ dans le code, le plugin insère automatiquement import $ from 'jquery' au début du fichier.
// Code source (le module legacy accède à jQuery global)
$('.element').hide();
// Après le traitement de ProvidePlugin (Webpack insère l'import)
import $ from 'jquery';
$('.element').hide();
En outre, imports-loader permet de spécifier explicitement quelles dépendances un module doit recevoir. Cela est utile lorsqu'une bibliothèque utilise this au niveau supérieur, en s'attendant à ce que this fasse référence à window plutôt qu'à module.exports.
ProvidePlugin est un plugin intégré de Webpack qui charge automatiquement les modules lorsqu'il détecte des références à des identifiants spécifiés. La configuration est un objet où la clé est le nom de la variable et la valeur est le chemin vers le module et le champ exporté.
// webpack.config.js
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
_: 'lodash',
'window.$': 'jquery',
}),
],
};
ProvidePlugin prend en charge l'importation partielle via la syntaxe de tableau. Par exemple, [lodash, debounce] importe uniquement la fonction debounce de lodash, ce qui réduit la taille du bundle final. C'est particulièrement important pour les projets mobiles, où chaque kilo-octet affecte le temps de chargement.
imports-loader ajoute les imports nécessaires au début d'un module, tandis que exports-loader définit les valeurs exportées pour les modules qui n'utilisent pas module.exports explicitement. Ces loaders travaillent au niveau de fichiers individuels, et non globalement comme ProvidePlugin.
// webpack.config.js — configuration d'imports-loader
module.exports = {
module: {
rules: [
{
test: /legacy-module\.js$/,
use: [
{
loader: 'imports-loader',
options: {
imports: [
'jquery',
'$',
],
},
},
],
},
],
},
};
exports-loader est utilisé lorsqu'une bibliothèque assigne une valeur à une variable globale mais ne l'exporte pas via le système de modules. Le loader extrait la valeur et la transforme en export de module, permettant à d'autres modules de l'importer via import.
Shimming est configuré dans webpack.config.js via une combinaison de plugins et de loaders. Un scénario typique inclut ProvidePlugin pour les variables globales et imports-loader pour les modules spécifiques qui nécessitent un changement de portée.
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',
}),
],
};
Le champ globalObject dans output définit le contexte pour les références à this au niveau supérieur. Pour un environnement navigateur, la valeur 'this' fait référence à window, tandis que pour React Native ou Node.js, elle fait référence à global. Choisir la bonne valeur prévient les erreurs d'exécution dans l'environnement cible.
Shimming est un outil puissant mais dangereux. Une configuration incorrecte entraîne la duplication du code dans le bundle, des conflits de noms et des erreurs d'exécution inattendues. Les développeurs oublient souvent que ProvidePlugin travaille à l'étape de compilation et ne peut pas traiter les références dynamiques aux variables.
Si deux plugins utilisent des versions différentes de jQuery, ProvidePlugin ne remplacera que l'une d'elles, celle spécifiée en premier dans la configuration. La deuxième bibliothèque recevra une version incompatible, ce qui provoquera des erreurs difficiles à déboguer. La solution consiste à utiliser exports-loader pour chaque bibliothèque avec une version explicite ou à appliquer webpack.IgnorePlugin pour exclure les modules en double.
Une autre erreur courante consiste à tenter de shim des modules qui utilisent des appels require synchrones de CommonJS dans un contexte dynamique. ProvidePlugin ne traite que les identifiants statiques, donc les références dynamiques doivent être remplacées manuellement ou avec NormalModuleReplacementPlugin.
Une configuration incorrecte du shimming peut entraîner une augmentation significative de la taille du bundle. Si ProvidePlugin est configuré pour des dizaines de variables globales, Webpack insérera les imports correspondants dans tous les fichiers du projet, indépendamment de l'utilisation de ces variables dans chaque fichier particulier. Cela crée du code redondant, surtout dans les grands projets avec des milliers de modules.
Pour diagnostiquer les problèmes de shimming, utilisez webpack-bundle-analyzer — un outil de visualisation de la composition du bundle. Si jQuery ou une autre bibliothèque apparaît plusieurs fois dans le bundle, des versions différentes entrent probablement en conflit ou ProvidePlugin est configuré pour plusieurs identifiants menant à des versions différentes du paquet. La solution consiste à unifier les versions des dépendances via resolve.alias et à vérifier que tous les identifiants shimmés pointent vers le même module.
Avant d'appliquer le shimming, évaluez la possibilité de mettre à jour la bibliothèque vers une version prenant en charge le système modulaire. De nombreux paquets legacy ont des alternatives modernes qui ne nécessitent pas de shimming. Par exemple, les plugins jQuery peuvent être remplacés par des APIs natives du navigateur : $.ajax → fetch, $.each → Array.forEach. La refactorisation apporte un bénéfice à long terme en matière de maintenance, tandis que le shimming est une solution temporaire qui complique la configuration.
Si la mise à jour n'est pas possible, envisagez NormalModuleReplacementPlugin, qui permet de remplacer un module par un autre au niveau de la résolution sans modifier le code source. Ce plugin fonctionne à l'étape de construction du graphe des dépendances, avant l'application des loaders, et traite toutes les références au module indépendamment du contexte. C'est une solution plus propre pour remplacer des bibliothèques entières que des loaders ponctuels.
Avec le développement des ES modules natifs dans les navigateurs et l'apparition des import maps, certains scénarios de shimming peuvent être résolus sans Webpack. Les import maps permettent de réaffecter les noms de modules à la volée au niveau du navigateur, sans étape de build. Cependant, cette approche n'est pas prise en charge dans React Native et dans d'autres environnements sans ESM navigateur, donc le shimming via Webpack reste pertinent pour les builds de production qui exigent un contrôle total sur les dépendances et leurs versions. Le choix entre les import maps et les shims Webpack dépend de la plateforme cible et des exigences de compatibilité avec les anciens navigateurs.
Questions fréquentes
Shimming ajoute du code pour assurer la compatibilité, tandis que tree shaking supprime le code inutilisé. Ces techniques ont des objectifs opposés : le shimming augmente la taille du bundle, le tree shaking la réduit. Dans un build de production, les deux sont appliquées successivement.
Oui, le shimming existe comme technique indépendante de Webpack — par exemple, via des scripts globaux dans le HTML ou via des ES modules avec réexportation. Cependant, Webpack fournit les outils d'automatisation les plus pratiques : ProvidePlugin et des loaders qui ne nécessitent pas de modification manuelle du code.
ProvidePlugin n'affecte pas la vitesse du build car il travaille à l'étape de compilation de l'AST. imports-loader et exports-loader ajoutent un léger temps de traitement pour chaque fichier. Utilisés sur des centaines de fichiers, la différence peut représenter 5 à 15 % du temps total du build.
Si toutes les dépendances prennent en charge les ES modules et le système modulaire, le shimming est superflu. Renoncer au shimming simplifie la configuration, réduit la taille du bundle et diminue le risque de conflits de noms. Il est recommandé de vérifier les dépendances sur caniuse.com.
TypeScript exige des déclarations de types supplémentaires pour les variables shimmées. Il est nécessaire d'ajouter declare const $: any ou d'installer les types via @types/jquery. ProvidePlugin insère les imports au niveau JavaScript après la compilation TypeScript, donc les types sont vérifiés séparément.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi