Shimming es una técnica para garantizar la compatibilidad de módulos que esperan ciertas variables globales o APIs. En el ecosistema de Webpack, el shimming se implementa mediante ProvidePlugin, imports-loader y exports-loader, lo que permite conectar librerías legacy sin modificar su código fuente. Según Webpack Documentation (2026), el shimming sigue siendo una herramienta clave para integrar plugins de jQuery y otras dependencias que no admiten un sistema modular.
Lo esencial
Shimming es una técnica de software que inserta una capa de compatibilidad entre el código y el entorno sin modificar el código fuente del módulo. En el contexto del build de JavaScript, el shimming resuelve el problema cuando un módulo hace referencia a variables globales (window.$, global.process) que no existen en el entorno modular.
Polyfill implementa desde cero la funcionalidad faltante, añadiendo nuevas capacidades al entorno. Por ejemplo, core-js añade Array.prototype.flatMap para navegadores antiguos. Shim, en cambio, redirige las llamadas existentes a implementaciones disponibles o sustituye los objetos globales esperados. En Webpack, ProvidePlugin inserta automáticamente import $ from 'jquery' en todos los lugares donde se encuentra una referencia a la variable global $, sin requerir cambios en el código.
La diferencia principal radica en el objetivo. Polyfill añade lo que no existe, mientras que shim hace que el código existente sea compatible con el entorno en el que se ejecuta. La elección entre ellos depende del problema que se resuelva: falta de API o incompatibilidad de interfaces.
Webpack trata cada módulo como una unidad aislada con su propio ámbito. Si una librería hace referencia a la variable global jQuery como window.$, el build fallará con un error porque esa variable no existe en el contexto modular. ProvidePlugin resuelve el problema en la etapa de compilación: al detectar el identificador $ en el código, el plugin inserta automáticamente import $ from 'jquery' al inicio del archivo.
// Código original (el módulo legacy accede a la jQuery global)
$('.element').hide();
// Después del procesamiento de ProvidePlugin (Webpack inserta el import)
import $ from 'jquery';
$('.element').hide();
Además, imports-loader permite especificar explícitamente qué dependencias debe recibir un módulo. Esto es útil cuando una librería usa this en el nivel superior, esperando que this se refiera a window y no a module.exports.
ProvidePlugin es un plugin integrado de Webpack que carga automáticamente módulos cuando detecta referencias a identificadores especificados. La configuración es un objeto donde la clave es el nombre de la variable y el valor es la ruta al módulo y el campo exportado.
// webpack.config.js
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
_: 'lodash',
'window.$': 'jquery',
}),
],
};
ProvidePlugin admite importación parcial mediante la sintaxis de arrays. Por ejemplo, [lodash, debounce] importa solo la función debounce de lodash, lo que reduce el tamaño del bundle final. Esto es especialmente importante en proyectos móviles, donde cada kilobyte afecta al tiempo de carga.
imports-loader añade las importaciones necesarias al inicio de un módulo, mientras que exports-loader define los valores exportados para módulos que no usan module.exports explícitamente. Estos loaders trabajan a nivel de archivos individuales, no globalmente como ProvidePlugin.
// webpack.config.js — configuración de imports-loader
module.exports = {
module: {
rules: [
{
test: /legacy-module\.js$/,
use: [
{
loader: 'imports-loader',
options: {
imports: [
'jquery',
'$',
],
},
},
],
},
],
},
};
exports-loader se usa cuando una librería asigna un valor a una variable global pero no lo exporta a través del sistema de módulos. El loader extrae el valor y lo convierte en una exportación de módulo, permitiendo que otros módulos lo importen mediante import.
Shimming se configura en webpack.config.js mediante una combinación de plugins y loaders. Un escenario típico incluye ProvidePlugin para variables globales e imports-loader para módulos concretos que requieren cambios de ámbito.
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',
}),
],
};
El campo globalObject en output establece el contexto para las referencias a this en el nivel superior. Para un entorno de navegador, el valor 'this' se refiere a window, mientras que para React Native o Node.js se refiere a global. Elegir el valor correcto evita errores de ejecución en el entorno objetivo.
Shimming es una herramienta potente pero peligrosa. Una configuración incorrecta provoca duplicación de código en el bundle, conflictos de nombres y errores de ejecución inesperados. Los desarrolladores suelen olvidar que ProvidePlugin funciona en la etapa de compilación y no puede manejar referencias dinámicas a variables.
Si dos plugins usan versiones distintas de jQuery, ProvidePlugin sustituirá solo una de ellas, la especificada primero en la configuración. La segunda librería recibirá una versión incompatible, lo que provocará errores difíciles de depurar. La solución es usar exports-loader para cada librería con una versión explícita o aplicar webpack.IgnorePlugin para excluir módulos duplicados.
Otro error común es intentar hacer shimming a módulos que usan llamadas require síncronas de CommonJS en un contexto dinámico. ProvidePlugin procesa solo identificadores estáticos, por lo que las referencias dinámicas deben reemplazarse manualmente o con NormalModuleReplacementPlugin.
Una configuración incorrecta de shimming puede provocar un aumento significativo del tamaño del bundle. Si ProvidePlugin está configurado para decenas de variables globales, Webpack insertará las importaciones correspondientes en todos los archivos del proyecto, independientemente de si esas variables se usan en cada archivo concreto. Esto crea código redundante, especialmente en proyectos grandes con miles de módulos.
Para diagnosticar problemas con el shimming, use webpack-bundle-analyzer — una herramienta para visualizar la composición del bundle. Si jQuery u otra librería aparece en el bundle varias veces, probablemente entran en conflicto versiones distintas o ProvidePlugin está configurado para varios identificadores que apuntan a versiones diferentes del paquete. La solución es unificar las versiones de las dependencias mediante resolve.alias y comprobar que todos los identificadores con shim apunten al mismo módulo.
Antes de aplicar shimming, evalúe la posibilidad de actualizar la librería a una versión que admita el sistema modular. Muchos paquetes legacy tienen alternativas modernas que no requieren shimming. Por ejemplo, los plugins de jQuery se pueden reemplazar por APIs nativas del navegador: $.ajax → fetch, $.each → Array.forEach. La refactorización aporta un beneficio a largo plazo en el mantenimiento, mientras que el shimming es una solución temporal que complica la configuración.
Si la actualización no es posible, considere NormalModuleReplacementPlugin, que permite reemplazar un módulo por otro a nivel de resolución sin cambiar el código fuente. Este plugin funciona en la etapa de construcción del grafo de dependencias, antes de aplicar los loaders, y procesa todas las referencias al módulo independientemente del contexto. Es una solución más limpia para reemplazar librerías completas que los loaders puntuales.
Con el desarrollo de los ES modules nativos en los navegadores y la aparición de import maps, algunos escenarios de shimming pueden resolverse sin Webpack. Import maps permiten reasignar nombres de módulos sobre la marcha a nivel del navegador, sin etapa de build. Sin embargo, este enfoque no se admite en React Native ni en otros entornos sin ESM de navegador, por lo que el shimming mediante Webpack sigue siendo relevante para los builds de producción que requieren control total sobre las dependencias y sus versiones. La elección entre import maps y shims de Webpack depende de la plataforma objetivo y de los requisitos de compatibilidad con navegadores antiguos.
Preguntas frecuentes
Shimming añade código para garantizar la compatibilidad, mientras que tree shaking elimina el código no utilizado. Estas técnicas son opuestas en su propósito: el shimming aumenta el tamaño del bundle, el tree shaking lo reduce. En un build de producción, ambas se aplican secuencialmente.
Sí, shimming existe como técnica independientemente de Webpack — por ejemplo, mediante scripts globales en HTML o mediante ES modules con reexportación. Sin embargo, Webpack proporciona las herramientas de automatización más cómodas: ProvidePlugin y loaders que no requieren cambios manuales en el código.
ProvidePlugin no afecta a la velocidad del build porque funciona en la etapa de compilación del AST. imports-loader y exports-loader añaden un pequeño tiempo de procesamiento por cada archivo. Cuando se usan en cientos de archivos, la diferencia puede ser del 5–15% del tiempo total del build.
Si todas las dependencias admiten ES modules y el sistema modular, el shimming es redundante. Renunciar al shimming simplifica la configuración, reduce el tamaño del bundle y disminuye el riesgo de conflictos de nombres. Se recomienda comprobar las dependencias en caniuse.com.
TypeScript requiere declaraciones de tipos adicionales para las variables con shim. Es necesario añadir declare const $: any o instalar los tipos mediante @types/jquery. ProvidePlugin inserta las importaciones a nivel de JavaScript después de la compilación de TypeScript, por lo que los tipos se verifican por separado.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también