Module Bundler

Webpack

Webpack es el module bundler probado en batalla. Convierte un grafo de módulos, assets y dependencias en bundles optimizados; entenderlo hace que cualquier otra herramienta de build sea más clara.

advanced14 min readUpdated 15 sept 2026
webpack.config.js
js
// 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,
  },
  module: {
    rules: [
      { test: /\.css$/, use: ["style-loader", "css-loader"] },
    ],
  },
  optimization: { splitChunks: { chunks: "all" } },
};
Primera versión
2012
Modelo
Grafo de dependencias
Transformaciones
Loaders
Extensiones
Plugins
Dev server
webpack-dev-server
Aún usado por
Muchas apps empresariales

Por que importa

Por qué Webpack sigue siendo relevante

Gestiona todo

JavaScript, CSS, imágenes, fuentes y más fluyen a través de un único pipeline, logrando que el grafo sea completo y explícito.

Altamente configurable

Los loaders, plugins y opciones de optimización permiten moldear el build con precisión cuando los valores por defecto no son suficientes.

Optimización potente

Code splitting, tree shaking, caching y minificación están disponibles con un control granular.

La imagen completa

Las tres ideas detrás de Webpack

Un grafo de dependencias, loaders que transforman archivos y plugins que extienden el build.

El grafo

Descubrir

Partiendo de los entry points, Webpack sigue los imports para construir un grafo de cada módulo y asset.

Loaders

Transformar

Funciones que convierten un archivo en un módulo, como compilar TypeScript o procesar CSS.

Plugins

Extender

Se integran en el ciclo de vida del build para tareas que van más allá de la transformación de archivos individuales.

Webpack de un vistazo

El núcleo de Webpack

Entry

Los módulos iniciales a partir de los cuales Webpack construye el grafo de dependencias.

Output

Dónde se escriben los bundles y cómo se nombran, incluyendo hashes de contenido.

Loaders

Transforman archivos antes de que entren al grafo, como babel-loader o css-loader.

Plugins

Extienden el build con generación de HTML, variables de entorno y más.

Code splitting

El import dinámico y splitChunks crean bundles separados que se cargan bajo demanda.

Tree shaking

Elimina los exports no utilizados, lo cual requiere ES modules y código libre de side-effects.

Una breve historia

El bundler que construyó la web moderna

  1. 2012

    Lanzamiento de Webpack

    Tobias Koppers introduce un bundler que trata cada asset como un módulo.

    12
  2. 2014

    Webpack 1

    El bundler se vuelve popular con el auge de React y las single-page apps.

    14
  3. 2016

    Webpack 2

    Llegan los ES modules nativos y el tree shaking.

    16
  4. 2020

    Webpack 5

    Se lanzan el persistent caching, module federation y asset modules.

    20
  5. Hoy

    Sigue en producción

    Vite es el estándar moderno, pero Webpack sigue estando muy extendido en aplicaciones existentes.

    Hoy

La guia completa

Webpack: Todo lo que necesitas saber

¿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, dev y prod.
  • 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.alias en 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.

Habilitando tree shaking

El tree shaking necesita la sintaxis de ES modules. Las llamadas require de CommonJS son lo suficientemente dinámicas como para que los exports no utilizados no puedan eliminarse de forma segura.

Preferir
// math.js
export function add(a, b) {
  return a + b;
}
export function unused() {}

// only add is bundled
Evitar
// math.js
module.exports = {
  add: (a, b) => a + b,
  unused: () => {},
};
// both shipped to the browser

Dividiendo el código

El import dinámico crea un chunk separado que se carga solo cuando es necesario. Los imports estáticos ponen todo en el bundle inicial.

Preferir
async function openEditor() {
  const { Editor } = await import(
    "./Editor"
  );
  return Editor;
}
Evitar
import { Editor } from "./Editor";
// heavy editor in the
// initial bundle for everyone

Preguntas frecuentes

Preguntas frecuentes

Keep learning

Related topics from the roadmap.

$ comienza a aprender

Listo para aprender Webpack?

Nuestro tutorial interactivo te guia a traves de Webpack paso a paso — con quizzes y codigo real que puedes ejecutar en el navegador.