¿Qué es Webpack?
Webpack es un module bundler. Partiendo de uno o más puntos de entrada, sigue cada importación y construye un grafo de los módulos y assets de tu aplicación. Luego, los transforma y los combina en un número reducido de bundles que el navegador puede cargar de manera eficiente.
Lanzado en 2012, Webpack se convirtió en la columna vertebral del build front-end moderno. Actualmente, Vite es la opción predeterminada para proyectos nuevos porque es más rápido y sencillo, pero Webpack sigue impulsando una cantidad enorme de aplicaciones en producción, y sus conceptos —el grafo de dependencias, loaders, plugins y code splitting— son el vocabulario de cualquier bundler que haya surgido después.
Entrada y salida
Las dos piezas de configuración obligatorias son el punto de inicio del grafo y el destino de los bundles.
// webpack.config.js
import path from "node:path";
export default {
entry: "./src/index.js",
output: {
path: path.resolve(import.meta.dirname, "dist"),
filename: "[name].[contenthash].js",
clean: true,
},
};
entry es el módulo de inicio. output.filename utiliza un hash de contenido para que los navegadores puedan cachear los bundles indefinidamente y solo vuelvan a descargar aquellos que hayan cambiado. clean: true elimina los archivos obsoletos antes de cada build.
Loaders
Por defecto, Webpack solo entiende JavaScript. Los Loaders transforman otros archivos en módulos a medida que entran en el grafo.
// loaders.js
export default {
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: "ts-loader",
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.(png|svg|woff2)$/,
type: "asset",
},
],
},
};
Una regla tiene un test para definir con qué archivos coincide y un use para el loader o loaders que debe aplicar. Los loaders se ejecutan de derecha a izquierda, por lo que ["style-loader", "css-loader"] primero analiza el CSS y luego lo inyecta en la página. Webpack 5 también incluye asset modules, que sustituyen a los antiguos file-loader y url-loader para imágenes y fuentes.
Plugins
Los plugins extienden el proceso de construcción en sí. Mientras que un loader transforma un archivo, un plugin se engancha al ciclo de vida de la compilación.
// plugins.js
import HtmlWebpackPlugin from "html-webpack-plugin";
import { DefinePlugin } from "webpack";
export default {
plugins: [
new HtmlWebpackPlugin({ template: "./src/index.html" }),
new DefinePlugin({
"process.env.NODE_ENV": JSON.stringify("production"),
}),
],
};
Los plugins comunes generan el archivo HTML, definen variables de entorno, copian assets estáticos, analizan el tamaño del bundle y limpian la salida. Aquí es donde reside la mayor parte de la potencia —y de la complejidad— de Webpack.
Resolve y aliases
Las opciones de resolve controlan cómo se encuentran las importaciones.
// resolve.js
export default {
resolve: {
extensions: [".ts", ".tsx", ".js"],
alias: {
"@": path.resolve(import.meta.dirname, "src"),
},
},
};
extensions te permite importar sin especificar la extensión del archivo, y alias crea accesos directos para que las importaciones no estén llenas de rutas ../../... Normalmente, el mismo alias se refleja en la configuración de TypeScript para que el editor esté sincronizado con el bundler.
Code splitting y tree shaking
Hay dos optimizaciones que dominan el rendimiento en producción.
El code splitting divide el bundle en chunks que se cargan bajo demanda. El import() dinámico es la herramienta principal, y splitChunks extrae automáticamente las dependencias compartidas.
// split.js
export default {
optimization: {
splitChunks: { chunks: "all" },
},
};
El tree shaking elimina las exportaciones que no se utilizan, pero solo cuando puede analizar las importaciones de forma estática. Esto implica usar ES modules (import/export) en lugar de CommonJS, y módulos que no tengan side effects. Marcar los paquetes como sideEffects: false en su package.json permite que Webpack realice la poda de código de forma agresiva.
El servidor de desarrollo
webpack-dev-server sirve la compilación en desarrollo con hot module replacement.
// devServer.js
export default {
devServer: {
port: 3000,
hot: true,
historyApiFallback: true,
proxy: [{ context: ["/api"], target: "http://localhost:8787" }],
},
};
historyApiFallback hace que el enrutamiento del lado del cliente funcione sirviendo index.html para rutas desconocidas, y proxy redirige las solicitudes de la API a tu backend. El servidor de desarrollo mantiene la compilación en memoria, por lo que las reconstrucciones son rápidas.
Cuándo usar Webpack
Webpack sigue siendo una opción sólida cuando mantienes una aplicación ya existente, dependes de un loader o plugin específico, o necesitas funcionalidades avanzadas como module federation para micro-frontends. Su configuración es verbosa, pero también es extremadamente potente y predecible una vez que se comprende.
Para proyectos nuevos, Vite suele ser la mejor opción por defecto: inicio más rápido, configuración más sencilla y una API de plugins moderna. Aun así, aprender Webpack sigue valiendo la pena porque sus conceptos se transfieren directamente: la interfaz de plugins de Vite es compatible con Rollup y las mismas ideas de grafo, transformaciones y splitting se aplican en todas partes.
Mejores prácticas
- Mantén la configuración dividida en archivos o funciones de
common,devyprod. - Utiliza hashes de contenido en los nombres de archivo para el almacenamiento en caché a largo plazo.
- Prioriza los ES modules para que el tree shaking funcione correctamente.
- Divide las funcionalidades pesadas mediante importaciones dinámicas.
- Marca los paquetes sin efectos secundarios (side-effect-free) para que se elimine el código no utilizado.
- Refleja
resolve.aliasen la configuración de TypeScript. - Analiza el bundle con un visualizador cuando crezca inesperadamente.
Errores comunes
- Enviar todo en un solo bundle y nunca aplicar code splitting.
- Usar CommonJS y preguntarse por qué el tree shaking no hace nada.
- Colocar un loader en el orden incorrecto y recibir errores confusos.
- Duplicar la configuración entre entornos en lugar de componerla.
- Configurar alias en Webpack pero no en TypeScript, provocando que el editor marque errores.
- Añadir un plugin que duplica una funcionalidad integrada de Webpack 5.
Próximos pasos
Webpack es la base histórica de las herramientas de construcción modernas y sigue siendo una opción fiable para aplicaciones existentes. Compáralo con Vite para proyectos nuevos, comprende los paquetes de npm que proporcionan loaders y plugins, y observa cómo estas mismas ideas se aplican en Turborepo para builds de monorepos. Después, lee la configuración de Webpack de tu proyecto y rastrea el flujo de un archivo desde el entry hasta el output.