wandres.dev
ESBUILD, SWC Y OXC · el toolchain en Rust/Go

Oxc: un toolchain entero bajo un solo AST

Oxc, el Oxidation Compiler, no es una herramienta sino una familia: parser, resolver, linter, formateador, transformador y minificador escritos en Rust y unidos por un único árbol de sintaxis. Parsear una vez y reutilizar esa representación es lo que le da a la vez velocidad y coherencia.

⏱ 16 min

esbuild y SWC atacaron el peaje de la interpretación pieza a pieza: uno como producto todo-en-uno, otro como motor incrustado. Oxc —el Oxidation Compiler— da el paso siguiente y más ambicioso: reunir todo el tooling de JavaScript bajo un mismo árbol de sintaxis en Rust. No es un parser, ni un linter, ni un bundler; es la base común de todos ellos. Esta lección explica qué contiene Oxc, por qué compartir un solo AST es la decisión que lo cambia todo, y cómo sobre esa base se levanta Rolldown.

🎯 Al terminar esta lección sabrás
  • Presentar Oxc como un toolchain completo, no como una herramienta suelta.
  • Enumerar sus piezas: parser, resolver, linter, formateador, transformador y minificador.
  • Explicar por qué un único AST compartido da velocidad y coherencia a la vez.
  • Situar a Oxc como la base sobre la que se construye Rolldown.

Una familia, no una herramienta

El error más común al oír hablar de Oxc es tratarlo como otro motor rápido, un competidor directo de esbuild o SWC. No lo es. Oxc es una colección de herramientas que comparten una base común: un parser, un resolver, un linter (oxlint), un formateador (oxfmt), un transformador y un minificador, todos escritos en Rust y —esto es lo decisivo— todos construidos sobre el mismo árbol de sintaxis abstracta. Lo desarrolla VoidZero, la misma empresa que impulsa Vite y Rolldown.

El propio nombre lo anticipa: Oxidation Compiler, donde oxidation es el guiño habitual a Rust —el metal que se oxida— y compiler delata la tesis de fondo, que todas estas tareas son variantes de una sola: leer código, entenderlo y reescribirlo. Un linter, un formateador y un bundler parecen oficios distintos, pero los tres empiezan por lo mismo, construir un modelo del programa, y difieren solo en qué hacen con él después. Oxc toma en serio esa observación y construye el modelo una vez, para prestarlo a todos.

Por eso agrupar tantas herramientas bajo un mismo techo no es acumulación de funciones, sino una consecuencia lógica. Si el trabajo caro y compartido es entender el código, tenerlo hecho una sola vez y reutilizarlo es la arquitectura correcta; repetirlo en cada herramienta, como hacía el mundo clásico, es el desperdicio que Oxc corrige. Donde antes había una herramienta por tarea —Babel para transformar, ESLint para lintar, Prettier para formatear, Terser para minificar—, Oxc propone una sola capa de utilidades de lenguaje sobre una única representación.

Esa diferencia de encuadre tiene una consecuencia inmediata para quien lo evalúa: no tiene sentido preguntar reemplazo mi linter con Oxc o reemplazo mi bundler con Oxc, porque Oxc no es ni un linter ni un bundler, sino la cantera de la que ambos salen. Lo que reemplazas son las piezas concretas —oxlint por ESLint, el transformador por Babel— y lo que ganas, además de velocidad, es que esas piezas por fin comparten cimiento.

Las piezas del toolchain

Conviene conocer cada componente por separado antes de entender lo que gana al compartir base:

  • Parser. El punto de entrada: convierte tu código en un AST. El de Oxc está entre los parsers de JavaScript y TypeScript más rápidos que existen, varias veces más veloz que el de SWC.
  • Resolver. Localiza cada módulo importado siguiendo el algoritmo de Node y el campo exports. Es la reescritura en Rust de la lógica de resolución que todo bundler necesita.
  • Linter (oxlint). Analiza el árbol en busca de errores y malos olores, a una velocidad que estudiarás en la próxima lección.
  • Formateador (oxfmt). Reimprime el código con un estilo consistente, compatible con Prettier.
  • Transformador. Sustituye a Babel: baja TypeScript y JSX a la sintaxis del target.
  • Minificador. Sustituye a Terser: comprime la salida final del bundle.
# Cada pieza de Oxc releva a una herramienta clasica
Babel             ->  transformador de Oxc
ESLint            ->  oxlint
Prettier          ->  oxfmt
Terser            ->  minificador de Oxc
enhanced-resolve  ->  resolver de Oxc

Leída como catálogo, la lista impresiona por su ambición: es, casi punto por punto, el reemplazo en Rust de toda la caja de herramientas que la web usó durante una década. Pero el catálogo engaña si lo lees como piezas sueltas, porque su valor real no está en cada una por separado —cada cual tiene alternativas— sino en lo que todas comparten por debajo. Cada pieza puede usarse sola, sí, pero fue diseñada para no trabajar sola.

# Las piezas de Oxc se distribuyen como binarios y crates independientes
npx oxlint@latest         # el linter, listo sin configuracion
npx oxfmt@latest          # el formateador, compatible con Prettier
# parser, resolver, transformer y minifier viven como bibliotecas en Rust

De todas las piezas, el parser merece una mención aparte, porque es el que fija el techo de velocidad de las demás. Al ser, según sus propias mediciones, varias veces más rápido que el de SWC —que ya era rapidísimo—, cada herramienta construida encima arranca desde una base que ninguna cadena en JavaScript puede igualar. Un linter nunca es más rápido que el parser que lo alimenta; Oxc lo entendió y empezó por ahí.

Así, cada pieza hereda tres cosas de la base común:

  • La velocidad del parser más rápido, sin tener que reimplementarlo.
  • La misma lectura del código que hacen las demás herramientas.
  • Las mejoras del núcleo, que llegan a todas a la vez y sin duplicarse.
🌳

Parser y resolver

Convierten tu código en un AST y localizan cada módulo. La base sobre la que todo lo demás lee.

🔧

Transformer y minifier

El relevo de Babel y Terser: bajan TypeScript y JSX al target y comprimen la salida.

🦀

Un mismo Rust

Todas las piezas comparten lenguaje y árbol. Ninguna vuelve a parsear lo que otra ya parseó.

Un solo AST lo cambia todo

Aquí está el corazón conceptual de Oxc, y por qué no es otra herramienta rápida más. En el ecosistema fragmentado, tu código se parsea muchas veces: Babel lo parsea con su parser para transformarlo, ESLint lo vuelve a parsear con el suyo para analizarlo, Prettier lo parsea con otro más para formatearlo, y el bundler lo parsea de nuevo para empaquetarlo. Cuatro o cinco lecturas del mismo archivo, cada una con reglas ligeramente distintas.

Esa multiplicidad tiene dos costes, y Oxc los ataca de un solo golpe. El primero es de velocidad: parsear es caro, y hacerlo cinco veces es cinco veces caro. El segundo, más sutil y más grave, es de coherencia: cuando cada herramienta tiene su propio parser, discrepan en los casos límite, y de esas discrepancias nacen los bugs que solo aparecen en la juntura entre herramientas. Oxc parsea una sola vez y hace que cada pieza lea ese mismo árbol. De esa única decisión brotan a la vez la velocidad —parsear una vez, no cinco— y la coherencia —una sola semántica, no cinco que casi coinciden—.

El beneficio de coherencia es el que más cuesta apreciar y el que más importa. Cuando tu linter y tu bundler tienen parsers distintos, pueden diferir en qué consideran sintaxis válida, en cómo interpretan una característica reciente del lenguaje o en cómo tratan un caso raro. Esas discrepancias no son teóricas: son la fuente del aviso que un linter da y el bundler ignora, o de la sintaxis que una herramienta acepta y otra rechaza. Con un AST único, esa clase de contradicción desaparece por construcción, porque no existen dos interpretaciones capaces de divergir.

Piensa en un caso concreto. Aparece una característica nueva de sintaxis en el lenguaje; en el mundo fragmentado, tu bundler la soporta antes que tu linter, así que el build pasa pero el linter escupe un error de parseo sobre código perfectamente válido, y pierdes una tarde averiguando por qué. Con Oxc, el parser es uno solo: en cuanto lo entiende, lo entienden a la vez el linter, el formateador, el transformador y el bundler. La compatibilidad con el lenguaje deja de ser una carrera desacompasada entre herramientas y pasa a ser una propiedad de la base.

Compartir el árbol elimina, de una sola vez, toda una familia de problemas:

  • El coste de parsear el mismo archivo cuatro o cinco veces, una por herramienta.
  • Las discrepancias de sintaxis entre el linter, el formateador y el bundler.
  • La deriva de versiones cuando cada parser soporta el lenguaje a su ritmo.
  • El trabajo de mantener y sincronizar varias gramáticas casi idénticas.
flowchart TB
code[Tu codigo fuente] --> parser[Parser en Rust]
parser --> ast[Un solo AST compartido]
ast --> resolver[Resolver]
ast --> linter[oxlint]
ast --> fmt[oxfmt]
ast --> trans[Transformer]
ast --> min[Minifier]
style parser fill:#89b4fa,color:#11111b
style ast fill:#a6e3a1,color:#11111b

Compara ese diagrama con la realidad clásica: cinco herramientas, cinco flechas que salen del código fuente hacia cinco parsers distintos. Oxc colapsa ese abanico en una sola raíz de la que todo cuelga, y esa figura —un tronco, muchas ramas— es la imagen mental que debes quedarte de toda esta materia.

La base de Rolldown

Oxc no es un ejercicio académico: es el cimiento sobre el que se construye Rolldown, el bundler que motoriza Vite 8. Rolldown toma el parser, el resolver y el transformador de Oxc, y comparte con ellos el mismo AST, de modo que empaquetar tu proyecto no obliga a reparsearlo en cada fase. Ese es el motivo técnico por el que Vite 8 es a la vez más rápido y más coherente que las versiones que cosían esbuild y Rollup: por debajo, un único árbol recorre todo el pipeline.

En concreto, Rolldown toma de Oxc:

  • El parser, para leer cada módulo una sola vez.
  • El resolver, para localizar los imports siguiendo Node y el campo exports.
  • El transformador, para bajar TypeScript y JSX antes de empaquetar.
// En Vite 8, Rolldown se apoya en Oxc por debajo, sin que lo configures
export default defineConfig({
  // tu configuracion no cambia: Oxc y Rolldown trabajan bajo el capo
  build: { target: "es2022" },
});

Este es el pago concreto de la teoría del árbol único. En Vite 8, el mismo árbol que Oxc produjo para transpilar un archivo en dev es el que Rolldown reutiliza para empaquetarlo en producción. No hay dos lecturas del archivo que puedan discrepar, y por eso el viejo bug de funcionaba en dev pero no en build pierde su causa material. La coherencia no es una promesa de marketing: es lo que ocurre, sin más, cuando solo existe un árbol.

Dicho de otro modo, Oxc es la razón por la que la unificación de Vite 8 no es solo más rápida, sino más coherente. La brecha entre desarrollo y producción que arrastraron las versiones con dos motores tenía una raíz material —dos parsers, dos semánticas— y Oxc la corta al ofrecer un único árbol para todo el recorrido. En la última lección de este nivel veremos que Oxc es el cimiento sobre el que se apoya el resto de la torre de VoidZero.

La relación conviene grabarla: Oxc no es el bundler, sino lo que el bundler usa. Rolldown aporta la lógica de empaquetado —cómo trocear, cómo ordenar los módulos, cómo aplicar los plugins— y delega en Oxc todo lo que es entender el código. Esa división limpia de responsabilidades es la que permite que las mismas utilidades sirvan a la vez al bundler, al linter y al editor sin duplicarse en ninguno.

ℹ️
Oxc es la base, Rolldown es el bundler que la coordina

Es fácil confundir Oxc con Rolldown, pero ocupan capas distintas. Oxc es la capa de utilidades de lenguaje: parsear, resolver, lintar, formatear, transformar y minificar. Rolldown es el bundler que orquesta varias de esas piezas para producir un artefacto. Uno es el conjunto de herramientas; el otro, la máquina que las coordina. Puedes usar oxlint y oxfmt sin usar Rolldown, pero no puedes tener Rolldown sin Oxc debajo.

Compartir un AST no es una optimización, es una tesis sobre cómo debe entenderse el código

La idea de un único árbol de sintaxis compartido parece un detalle de implementación, pero es la afirmación más profunda de toda esta materia, y merece que la interiorices. Durante quince años, construir para la web significó ensamblar herramientas que entendían tu código cada una a su manera: Babel tenía su idea de qué es una expresión válida, ESLint la suya, Prettier otra, el bundler una cuarta. No era solo que fueran lentas por parsear cinco veces; era que ninguna de las cinco estaba obligada a coincidir con las demás, y en las grietas entre sus interpretaciones anidaban clases enteras de errores imposibles de reproducir. Oxc parte de una premisa opuesta: tu código tiene un significado, y por tanto debe existir un árbol que lo represente, leído por todas las herramientas por igual. La velocidad que tanto se celebra —parsear una vez en vez de cinco— es en realidad un efecto secundario de esa premisa; el premio de fondo es la coherencia, la garantía de que el linter, el formateador, el transformador y el bundler nunca discreparán sobre qué es tu código, porque literalmente miran el mismo objeto en memoria. Esto reencuadra qué significa toolchain. Deja de ser una colección de programas independientes que se pasan texto y pasa a ser una sola base con una sola verdad sobre tu código, ofrecida en varias formas. Cuando entiendas que la unificación del AST es lo que hace posible que Vite, Rolldown, oxlint y oxfmt sean piezas de un mismo organismo y no vecinos que se toleran, habrás captado la idea que ordena todo el tooling de esta década. La fragmentación no era mala solo por lenta; era incoherente en su raíz, y Oxc es el intento más serio de curarla.

⚔️ Explora el toolchain bajo un solo árbol
  1. Ejecuta npx oxlint@latest en un proyecto real y anota cuánto tarda: estás usando una pieza de Oxc sin instalar nada permanente.
  2. Enumera las herramientas que hoy parsean tu código —Babel o SWC, ESLint, Prettier, tu bundler— y cuenta cuántos parsers distintos leen el mismo archivo.
  3. Dibuja en papel el abanico clásico —código hacia cinco parsers— y al lado el árbol único de Oxc, y describe qué desaparece.
  4. En un proyecto con Vite 8, confirma que Rolldown está por debajo y razona por qué compartir el AST de Oxc lo hace veloz.
  5. Explica en dos frases por qué la coherencia, y no solo la velocidad, es el premio de un AST compartido.