Lección 1 de 312 min
Bundlers y compiladores
Qué hace un bundler y en qué se diferencian Vite, webpack, esbuild y Babel.
Tu proyecto tiene doscientos archivos que se importan unos a otros, está escrito en TypeScript, usa JSX y carga CSS e imágenes con import. El navegador no entiende TypeScript ni JSX, y descargar doscientos archivos sueltos sería lentísimo. Alguien tiene que convertir todo eso en unos pocos archivos de JavaScript y CSS optimizados.
Ese «alguien» es un bundler (empaquetador), a menudo ayudado por un transpilador que traduce código moderno a código que entiende cualquier navegador. En esta lección verás qué hacen y en qué se diferencian las herramientas que más vas a encontrar: webpack, Vite, esbuild y Babel.
Qué hace un bundler
Todas las herramientas de esta lección resuelven el mismo par de problemas: preparar el código para producción y darte un entorno de desarrollo cómodo. Entender esas dos tareas te permite comparar cualquier herramienta, incluidas las que salgan el año que viene.
Grafo de módulos, transformación y empaquetado
Del árbol de imports de tu proyecto a unos pocos archivos listos para publicar.
- Entrada:
- Tu código fuente
- Salida:
- HTML, JS y CSS optimizados
El bundler empieza por un punto de entrada (por ejemplo, main.ts) y sigue cada import para construir el grafo de módulos: el mapa de qué archivo depende de cuál. Por el camino transforma cada archivo: quita los tipos de TypeScript, convierte el JSX en llamadas a funciones y procesa el CSS o las imágenes.
Después empaqueta: junta los módulos en uno o varios archivos (los «bundles»). Con el tree shaking descarta las funciones que exportas pero nadie usa, y con el code splitting separa en otro archivo el código que solo hace falta en ciertas páginas, para cargarlo cuando se necesite.
Por último minifica: elimina espacios y comentarios y acorta los nombres de variables. Al nombre de cada archivo le añade un hash de su contenido (index-B3x9k2.js), así el navegador puede guardarlo en caché para siempre y descargar uno nuevo solo cuando cambia.
Úsalo cuando
En cualquier aplicación de frontend que vaya a producción. Hoy casi nunca lo configuras desde cero: Angular, Next.js o la plantilla de Vite ya traen uno preparado.
Ten en cuenta
El tree shaking solo funciona bien con módulos ES (import/export). Si importas una librería antigua escrita en CommonJS, es probable que acabe entera en tu bundle aunque uses una sola función.
main.ts (punto de entrada)
├── carrito.ts
│ ├── precio.ts
│ └── lodash-es (solo se queda debounce)
├── estilos.css
└── logo.svg
▼ transformar · empaquetar · minificar
dist/index.html
dist/assets/index-B3x9k2.js (todo el JS, minificado)
dist/assets/index-D81fa0.css
dist/assets/logo-4c2e7a.svgServidor de desarrollo y HMR
Ver tus cambios en el navegador al instante, sin recargar ni perder el estado.
- Sigla:
- HMR
Mientras programas no necesitas el código minificado, sino rapidez. Por eso los bundlers incluyen un servidor de desarrollo: sirve tu app en localhost, vigila los archivos y, cuando guardas uno, actualiza el navegador.
La versión más útil es el HMR (Hot Module Replacement, «sustitución de módulos en caliente»): en lugar de recargar la página entera, sustituye solo el módulo que cambiaste. Si estabas rellenando un formulario y cambias el color de un botón, el texto que escribiste sigue ahí.
Úsalo cuando
Siempre que desarrolles una interfaz. Con frameworks como React, Vue o Angular el HMR funciona solo; no necesitas escribir nada.
Ten en cuenta
El servidor de desarrollo no es tu build de producción: puede funcionar en local y fallar al compilar para publicar. Prueba el build de producción (vite build y vite preview, por ejemplo) antes de desplegar.
export let cuenta = 0;
export function incrementar() {
cuenta++;
}
// API de HMR de Vite: acepta la nueva versión de este módulo
// sin recargar la página
if (import.meta.hot) {
import.meta.hot.accept((nuevoModulo) => {
console.log("Módulo actualizado en caliente", nuevoModulo);
});
}Nota
Un bundler y un transpilador no son lo mismo. El transpilador convierte un archivo de JavaScript en otro (de TypeScript a JavaScript, o de JavaScript moderno a antiguo). El bundler se ocupa del proyecto entero: sigue los imports, decide qué va en cada archivo y optimiza el resultado. Muchos bundlers llevan un transpilador dentro.
Las herramientas
webpack dominó durante años; Vite es hoy la opción más habitual en los proyectos nuevos que no traen su propia herramienta; esbuild es la pieza rápida que usan otras herramientas por debajo, y Babel es el transpilador clásico que poco a poco se necesita menos.
webpack
El bundler veterano: configurable hasta el último detalle y todavía muy extendido.
- Desde:
- 2012
- Escrito en:
- JavaScript
webpack trata todo como un módulo: JavaScript, CSS, imágenes o fuentes. Para entender cada tipo de archivo usa loaders, que transforman un archivo cada vez (ts-loader para TypeScript, css-loader para CSS). Para tareas sobre el resultado completo usa plugins, como generar el index.html o extraer el CSS a su propio archivo.
Fue el estándar durante casi una década, así que lo encontrarás en muchísimos proyectos existentes, en Create React App (ya abandonado) y en versiones anteriores de Angular y Next.js. Su punto fuerte es que se puede adaptar a casi cualquier necesidad; su punto débil, que es más lento y su configuración se complica rápido.
Úsalo cuando
Cuando mantienes un proyecto que ya lo usa, o necesitas algo muy a medida que solo resuelve un loader o plugin concreto, como Module Federation para micro-frontends.
Ten en cuenta
En proyectos grandes, arrancar el servidor de desarrollo puede tardar bastante. Y ojo con el orden de los loaders: en use: ["style-loader", "css-loader"] se aplican de derecha a izquierda.
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: "production",
entry: "./src/index.ts",
output: { filename: "[name].[contenthash].js", clean: true },
module: {
rules: [
// Los loaders transforman cada archivo según su tipo
{ test: /\.tsx?$/, use: "ts-loader" },
{ test: /\.css$/, use: ["style-loader", "css-loader"] },
],
},
resolve: { extensions: [".ts", ".tsx", ".js"] },
// Los plugins actúan sobre el resultado completo
plugins: [new HtmlWebpackPlugin({ template: "./src/index.html" })],
};Vite
Arranque casi instantáneo en desarrollo y un build de producción optimizado.
- Creado por:
- Evan You
- Desde:
- 2020
- Producción:
- Rollup → Rolldown
Vite (en francés, «rápido») cambió el enfoque del desarrollo: en lugar de empaquetar toda la app antes de mostrarla, sirve tus archivos como módulos ES nativos y deja que el navegador pida cada uno. Solo transforma el archivo que se solicita, en el momento, así que el arranque apenas depende del tamaño del proyecto. Las dependencias de node_modules, que no cambian, las preempaqueta una sola vez.
Para producción sí empaqueta, porque muchos archivos sueltos cargarían despacio. Históricamente lo ha hecho con Rollup; en las versiones recientes está pasando a Rolldown, un sustituto compatible escrito en Rust y mucho más rápido.
Lo creó Evan You, el autor de Vue, pero sirve para React, Svelte, Solid o JavaScript sin framework, y es la base de herramientas como Vitest, Astro o SvelteKit. El CLI de Angular también lo usa como servidor de desarrollo.
Úsalo cuando
Para casi cualquier proyecto de frontend nuevo que no traiga ya su propia herramienta: npm create vite@latest te da un proyecto listo en segundos.
Ten en cuenta
Como desarrollo y producción no usan exactamente el mismo proceso, de vez en cuando algo funciona en vite dev y no en vite build. Y algunas librerías antiguas en CommonJS dan guerra al servirse como módulos ES.
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
server: { port: 3000 },
build: { outDir: "dist", sourcemap: true },
});
// En la terminal:
// pnpm vite → servidor de desarrollo con HMR
// pnpm vite build → build de producción en dist/
// pnpm vite preview → sirve dist/ para probarloesbuild
Un bundler y transpilador escrito en Go, muchísimo más rápido que los clásicos.
- Escrito en:
- Go
- Creado por:
- Evan Wallace
esbuild demostró que las herramientas de JavaScript no tenían por qué estar escritas en JavaScript. Al estar en Go, un lenguaje compilado, y aprovechar todos los núcleos del procesador, empaqueta y minifica proyectos enteros en una fracción del tiempo que tardaba webpack.
Además de usarse directamente, es una pieza dentro de otras herramientas: Vite lo ha usado para preempaquetar dependencias y transformar TypeScript en desarrollo, y el CLI de Angular compila con esbuild en los proyectos recientes.
Úsalo cuando
Para empaquetar una librería, un script de Node o una función serverless en un solo archivo, o cuando quieres un build muy rápido y no necesitas un ecosistema de plugins grande.
Ten en cuenta
Quita los tipos de TypeScript, pero no los comprueba: un error de tipos no detiene el build. Ejecuta tsc --noEmit aparte, por ejemplo en CI. Su sistema de plugins es más limitado que el de webpack o Vite.
import * as esbuild from "esbuild";
await esbuild.build({
entryPoints: ["src/app.ts"],
bundle: true, // sigue los imports y lo junta todo
minify: true,
sourcemap: true,
platform: "node", // o "browser"
outfile: "dist/app.js",
});
// Lo mismo desde la terminal:
// npx esbuild src/app.ts --bundle --minify --sourcemap --platform=node --outfile=dist/app.jsBabel
El transpilador de JavaScript a JavaScript: código moderno que entiende cualquier navegador.
- Desde:
- 2014, como 6to5
- Tipo:
- Transpilador
Babel lee JavaScript y escribe JavaScript. Convierte la sintaxis nueva (?., ??, clases, JSX) en una equivalente que entienden navegadores más antiguos. Se configura con presets, paquetes de transformaciones: @babel/preset-env decide qué transformar según los navegadores que indiques, y otros presets añaden JSX o TypeScript.
La sintaxis se puede traducir, pero las funciones que faltan, como Array.prototype.at en un navegador viejo, hay que añadirlas con polyfills. Babel puede insertar automáticamente los de la librería core-js que tu código necesita.
Hoy se necesita menos: los navegadores modernos entienden casi todo y herramientas más rápidas, como esbuild o SWC, se encargan de TypeScript y JSX. Sigue siendo útil cuando quieres una transformación a medida, porque escribir un plugin de Babel es relativamente sencillo.
Úsalo cuando
Cuando debes dar soporte a navegadores antiguos con polyfills precisos, o necesitas un plugin de transformación concreto que solo existe para Babel.
Ten en cuenta
Babel no empaqueta: transforma archivo por archivo y necesita un bundler alrededor. Es más lento que las alternativas en Go o Rust, así que en un proyecto nuevo pregúntate si de verdad lo necesitas.
module.exports = {
presets: [
// Transforma solo lo que no entienden los navegadores objetivo
// (los lee de .browserslistrc) e inserta los polyfills necesarios
["@babel/preset-env", { useBuiltIns: "usage", corejs: 3 }],
// Convierte <Boton /> en llamadas a funciones
"@babel/preset-react",
// Quita los tipos (sin comprobarlos)
"@babel/preset-typescript",
],
};
// Entrada:
// const total = pedido?.lineas ?? [];
// Salida (simplificada):
// var _a = pedido == null ? void 0 : pedido.lineas;
// var total = _a != null ? _a : [];¿Y esta app?
Programer está hecha con Next.js, que no usa ninguna de las cuatro: en sus versiones recientes empaqueta con Turbopack y transforma el código con SWC, dos herramientas escritas en Rust. La tendencia general es esa: reescribir las herramientas de JavaScript en lenguajes compilados para que sean mucho más rápidas.
Interactivo
webpack, Vite, esbuild y Babel
No compiten exactamente en lo mismo: Babel ni siquiera empaqueta.
| Característica | webpack | Vite | esbuild |
|---|---|---|---|
| Qué es | Bundler completo | Herramienta de build con servidor de desarrollo | Bundler y transpilador |
| Escrito en | JavaScript | TypeScript, apoyado en herramientas nativas | Go |
| Velocidad | La más lenta en proyectos grandes | Arranque casi instantáneo | Muy rápida |
| Configuración | Muy flexible: loaders y plugins | Mínima, con plugins | Pocas opciones, por API o terminal |
| Servidor de desarrollo | Sí, con HMR | Sí, sobre módulos ES nativos y con HMR | Básico, con --serve |
| Úsalo para | Proyectos existentes y casos muy a medida | Proyectos de frontend nuevos | Librerías, scripts y como pieza de otras herramientas |
Ponlo en práctica
Saber qué es cada cosa es la mitad del trabajo. La otra mitad es reconocer cuándo usarla.
Interactivo
¿Qué usarías?
Lee cada situación y elige la opción que mejor la resuelve. Fallar aquí no cuenta: es para practicar.
Empiezas una app de React desde cero, sin framework de servidor. Quieres que el servidor de desarrollo arranque al momento y no pelearte con la configuración.
Para recordar
- Un bundler sigue los imports desde un punto de entrada, transforma cada archivo, lo empaqueta en pocos archivos y lo minifica.
- Un transpilador como Babel convierte JavaScript en JavaScript; no empaqueta.
- Vite es la opción por defecto para proyectos nuevos: módulos ES nativos en desarrollo y un build optimizado para producción.
- esbuild, SWC y Turbopack muestran la tendencia: herramientas escritas en Go o Rust, mucho más rápidas.
- Que el servidor de desarrollo funcione no garantiza que el build de producción también: pruébalo antes de desplegar.
Comprueba lo aprendido
Cuestionario
Responde las 5 preguntas para completar la lección.
1.¿Por qué el servidor de desarrollo de Vite arranca tan rápido aunque el proyecto sea grande?
2.Pasas
const total = pedido?.lineas ?? [];por Babel con@babel/preset-envpara navegadores antiguos. ¿Qué obtienes?3.Importas
debouncede una librería que exporta 300 funciones como módulos ES. ¿Qué hará un bundler moderno en el build de producción?4.En webpack, ¿qué diferencia hay entre un loader y un plugin?
5.Compilas tu proyecto TypeScript con esbuild sin errores, pero en producción falla porque una función recibe un texto en lugar de un número. ¿Qué ha pasado?