Por qué Vite usó Rollup en build y el salto a Rolldown
Vite delegó en Rollup el bundle de producción pero no el desarrollo, y esa asimetría no fue capricho: en dev sirve ESM nativo sin empaquetar, así que un bundler de calidad pero lento como Rollup solo tenía sentido en el build de un solo tiro. Por qué Rollup ganó la fase de build por calidad de salida y ecosistema de plugins, qué limitaciones —su velocidad en JavaScript y la costura de dos motores— se fueron acumulando, y cómo Rolldown, en Rust sobre Oxc, unifica ambas fases sin romper el contrato de Rollup.
Vite tomó una decisión reveladora: usar Rollup para el build de producción y no para el desarrollo. No fue una inconsistencia, sino la lectura precisa de para qué sirve cada fase. En dev, Vite sirve módulos de ES nativos sin empaquetar, y meter ahí un bundler que optimiza la calidad de salida a costa de la velocidad sería absurdo. En build, en cambio, hay que empaquetar de verdad, una sola vez, y ahí la calidad del artefacto de Rollup y su ecosistema de plugins no tenían rival. Entender esa asimetría —y el techo que acabó revelando— es entender por qué existe Rolldown.
- Explicar por qué Vite empaquetaba con Rollup en build pero no en dev.
- Ver por qué Rollup ganó la fase de build: calidad de salida y ecosistema de plugins.
- Identificar sus limitaciones: la velocidad en JavaScript y la costura de dos motores.
- Comprender cómo Rolldown, en Rust sobre Oxc, unifica ambas fases sin romper el contrato.
Por qué Rollup en build y no en dev
La clave está en qué hace cada fase. En desarrollo, Vite no empaqueta: sirve tu código como módulos de ES nativos, y es el navegador quien los carga a demanda siguiendo los import. Vite solo transforma cada módulo al vuelo cuando el navegador lo pide, y pre-empaqueta las dependencias de node_modules con esbuild para no servir miles de archivos diminutos. Meter aquí a Rollup —que recorre el grafo entero para producir el mejor artefacto posible— sería pagar el coste de un bundle completo en cada guardado, justo lo que la arquitectura de dev existe para evitar.
En producción la ecuación se invierte. Ahí sí hay que empaquetar: reducir el número de peticiones, aplicar tree shaking, minificar, trocear en chunks con las fronteras de caché adecuadas. Y esas son exactamente las virtudes de Rollup que estudiaste en las lecciones anteriores. El build es un proceso de un solo tiro, no un bucle interactivo, así que su relativa lentitud se tolera a cambio de un artefacto excelente. Vite delegó el bundle de producción entero en Rollup y expuso una API de plugins que era un superconjunto de la suya, de modo que todo el ecosistema ya escrito servía sin cambios.
El reparto entre las dos fases era nítido, y cada tarea caía en el motor que mejor la resolvía:
- Dev, con esbuild: pre-empaquetaba
node_modulesy transpilaba TypeScript y JSX al vuelo, elegido por latencia. - Dev, sin bundle: el resto de tu código se servía como ESM nativo, módulo a módulo, sin recorrer el grafo entero.
- Build, con Rollup: resolvía el grafo completo, aplicaba el tree shaking y decidía el troceado en chunks.
- Build, con plugins: ejecutaba la cadena de plugins estándar que daba forma final al artefacto de producción.
La razón profunda de que dev no empaquete es que ya no hace falta: los navegadores modernos cargan ESM de forma nativa con <script type="module">, así que Vite puede servir cada archivo tal cual y dejar que el navegador teja el grafo pidiendo un módulo tras otro. El único empaquetado en dev es el pre-bundling de dependencias, que existe por un motivo de latencia —evitar cientos de peticiones a paquetes de node_modules— y no de calidad de salida. Por eso ese trabajo lo hacía esbuild, elegido por velocidad bruta, y no Rollup.
Las limitaciones que se acumularon
La estrategia de usar cada motor donde brillaba fue acertada, pero cobró un peaje que creció con el tiempo. La primera limitación era la velocidad de Rollup: escrito en JavaScript y esencialmente de un solo hilo, hacía que vite build se volviera notablemente lento en proyectos grandes. El contraste era incómodo: un dev instantáneo gracias a esbuild, y un build que se arrastraba a medida que el proyecto crecía. La calidad del artefacto seguía siendo la mejor, pero el tiempo de obtenerla escalaba mal.
La segunda limitación era estructural: tener dos motores significa dos parsers leyendo tu código, con dos representaciones internas y dos conjuntos de reglas que no coinciden al cien por cien. esbuild transpilaba en dev; Rollup empaquetaba en build. Y en la frontera entre ambos anidaba una clase entera de bugs del tipo funcionaba en dev y falla en build: un plugin que se comportaba distinto según la fase, una sintaxis que un motor leía y el otro todavía no, un helper inyectado con forma diferente. La divergencia entre las dos naturalezas de Vite no era solo conceptual; era también material, Go frente a JavaScript, un AST frente a otro.
Esas divergencias tenían firmas reconocibles, y quien mantenía un plugin las conocía de memoria:
- Un hook que transformaba distinto según lo corriera Vite sobre esbuild o Rollup de verdad.
- Sintaxis reciente que un motor sabía leer y el otro todavía no soportaba.
- Helpers de transpilación inyectados con una forma en dev y otra en build.
- Optimizaciones que Rollup aplicaba al empaquetar y que esbuild no replicaba al servir.
Ninguno de los dos motores podía, por sí solo, hacer bien los dos trabajos. esbuild era rapidísimo pero su tree shaking y su control de salida eran más limitados, y su modelo de plugins no era el estándar. Rollup tenía la salida y el ecosistema, pero era demasiado lento para el bucle de dev. Unificar bajo uno cualquiera de los dos significaba renunciar a algo esencial. Hacía falta un motor nuevo.
El dilema era simétrico y sin salida con las piezas de entonces:
- esbuild: rapidísimo en Go, pero con tree shaking y control de salida más limitados y un modelo de plugins ajeno al estándar.
- Rollup: la mejor salida y el ecosistema de plugins de referencia, pero atado a la velocidad de JavaScript de un solo hilo.
- Unificar en esbuild: habría sacrificado la calidad del artefacto y el ecosistema de plugins.
- Unificar en Rollup: habría hecho inviable el bucle instantáneo que define el dev de Vite.
flowchart TD D[dev sirve ESM nativo sin empaquetar] --> DP[esbuild solo pre-empaqueta dependencias] B[build empaqueta para produccion] --> BR[Rollup por calidad de salida y plugins] BR --> LIM[limite la velocidad de Rollup en JavaScript] DP --> SEAM[dos motores con dos semanticas] BR --> SEAM LIM --> RD[Rolldown en Rust unifica dev y build] SEAM --> RD
El salto a Rolldown
Rolldown es la respuesta a esas dos limitaciones a la vez. Es un bundler escrito en Rust, construido sobre Oxc —el Oxidation Compiler—, y deliberadamente compatible con la API de plugins de Rollup. La jugada es la que ya reconoces del final de este nivel: conservar el contrato que el ecosistema conoce, y sustituir el motor por debajo por uno nativo, más rápido y capaz de servir las dos fases.
En Vite 8, Rolldown reemplaza a la vez a esbuild en el pre-empaquetado y a Rollup en el build de producción. Por primera vez, dev y build recorren el mismo motor, con el mismo parser y la misma semántica: la costura material desaparece, y con ella la clase de divergencias que nacía de tener dos AST distintos leyendo el mismo archivo. Y como el motor es Rust, el build hereda su velocidad y deja atrás el vite build lento sobre Rollup, con mejoras que en proyectos grandes se cuentan por múltiplos.
Lo decisivo es lo que no cambia. Rolldown reimplementa el modelo de Rollup que estudiaste —el grafo estático de ESM, los output formats, los hooks en dos fases, la configuración de input y output—, así que tu vite.config, tus plugins y tu forma de pensar el build siguen intactos. Se probó primero con un paquete puente, rolldown-vite, en proyectos reales, precisamente para verificar que la compatibilidad aguantaba el peso del ecosistema antes de volverla el camino por defecto.
# El puente se probo primero como paquete aparte
npm install rolldown-vite # Vite con Rolldown como motor unico
# En Vite 8 es el camino por defecto: un solo motor en dev y en build
La clave técnica que lo hace posible es Oxc. Al compartir un único AST entre el parser, el resolver, el transformador y el bundler, Rolldown parsea tu código una vez y reutiliza esa representación en cada fase, en lugar de reparsearlo con reglas ligeramente distintas en cada herramienta. De ahí salen a la vez la velocidad —parsear una vez es más barato que parsear varias— y la coherencia —una sola semántica, no dos que casi coinciden—. Lo que Vite 8 gana al unificar el motor se resume en tres frentes:
- Coherencia: dev y build parsean con las mismas reglas, y la clase de bugs por divergencia de motor se extingue.
- Velocidad: el build hereda el rendimiento de Rust y acaba con el
vite buildlento sobre Rollup. - Simplicidad: una sola pieza que mantener y razonar, en vez de coordinar dos motores en su frontera.
// Tu vite.config no cambia: la interfaz de Rollup se conserva
export default defineConfig({
plugins: [/* los plugins de Rollup existentes siguen funcionando */],
build: { target: "es2022" },
});
Que un mismo motor sirva las dos fases es más que una mejora de rendimiento: es la desaparición de la frontera donde vivían las divergencias. Rolldown no acelera a Rollup ni a esbuild por separado; sustituye a ambos por una sola pieza, y con ella funde el pre-empaquetado de dev y el bundle de build en un único recorrido con una única semántica. La brecha entre las dos naturalezas de Vite, que en el nivel anterior era conceptual, se cierra aquí también en lo material.
Dev sin bundle
Sirve ESM nativo; el navegador teje el grafo. Solo esbuild pre-empaquetaba dependencias, por latencia, no por calidad.
Build con Rollup
Empaqueta de un solo tiro con la mejor salida y el ecosistema de plugins estándar. Su lentitud se toleraba a cambio de calidad.
El techo
Rollup en JavaScript y de un hilo escalaba mal, y convivir con esbuild abría la brecha dev/build por dos semánticas distintas.
Rolldown
En Rust sobre Oxc, compatible con la API de Rollup. Un solo motor para dev y build: rápido y coherente a la vez.
Que la inmensa mayoría de los plugins de Rollup funcionara sobre Rolldown sin tocar una línea no fue suerte: fue la validación de una apuesta hecha años antes. Cuando diseñas la extensibilidad como un contrato pequeño y estable en vez de como una API atada a tu implementación, puedes cambiar el lenguaje entero del motor y que el ecosistema no se entere. El puente rolldown-vite existió justo para demostrarlo en proyectos reales antes de comprometer a todo Vite 8 con el cambio.
Este nivel entero se resuelve en una sola frase, y esta lección es donde por fin la ves operar: se estabilizan interfaces y se reemplazan motores. Rollup nunca fue el bundler más rápido; su aportación imperecedera fue el modelo —el grafo estático de ESM como fuente de verdad— y el contrato de plugins que ese modelo hizo posible. Vite entendió esto y no reinventó la interfaz: la adoptó, y por eso pudo delegar el build en Rollup por calidad mientras usaba esbuild en dev por velocidad, cada motor donde brillaba. El precio fue una costura, dos motores con dos semánticas, y un techo de rendimiento en el lado de Rollup. Rolldown no derriba el modelo: lo ejecuta por fin lo bastante rápido como para servir también el dev, reimplementando la interfaz de Rollup en Rust sobre Oxc y fundiendo las dos fases en un motor único. Fíjate en la moraleja estratégica, porque vale para todo el toolchain y para tu carrera: no apuestes por el motor de moda —esbuild, Rollup, Rolldown, el que venga después—, apuesta por la interfaz que persiste. Quien aprendió la API de Rollup en 2020 sigue plenamente vigente en 2026 con Rolldown sin reaprender nada, porque aprendió el cimiento y no el andamio. Y con eso cierras el nivel de Rollup exactamente donde se abre el siguiente: Rolldown, el bundler en Rust que ejecuta este modelo, es el protagonista del nivel que viene.
- Explica con tus palabras por qué empaquetar con Rollup tenía sentido en build pero no en el bucle de dev de Vite.
- Localiza en un proyecto Vite qué motor pre-empaquetaba las dependencias en dev y cuál producía el bundle de producción antes de Vite 8.
- Reproduce un bug de la clase funcionaba en dev y razona cómo dos parsers distintos podían provocarlo.
- Instala
rolldown-viteo crea un proyecto con Vite 8 y cronometra el build frente a un proyecto antiguo sobre Rollup. - Anticipa el siguiente nivel: enumera qué tres cosas de Rollup —modelo, formatos, plugins— esperas que Rolldown conserve intactas.