wandres.dev
EL COMPILADOR EN RUST · el pipeline de Astro 7

Depurar y leer el output compilado

Cómo bajar al código que el compilador genera y entenderlo sin miedo: leer la función de render de un .astro, reconocer maybeRenderHead y las interpolaciones, y usar los source maps para que un error en el módulo generado apunte de vuelta a la línea exacta de tu componente. Las opciones de sourcemap del compilador y una metodología para depurar mirando la salida en vez de adivinar.

⏱ 18 min

Casi nunca hace falta leer el JavaScript que el compilador genera —hasta que hace falta—. Un error con una traza que no reconoces, un estilo que no aparece, una expresión que se pinta distinto de lo que esperabas: en esos momentos, saber bajar al módulo compilado y leerlo es la diferencia entre depurar y adivinar. Y para que ese descenso no sea un salto a ciegas, el compilador emite source maps, la correspondencia que devuelve cada línea generada a su origen en tu .astro. Esta última lección cierra el nivel enseñando a leer la salida y a usar el mapa que la conecta con tu código.

🎯 Al terminar esta lección sabrás
  • Leer la función de render de un .astro compilado sin intimidarse.
  • Reconocer maybeRenderHead, render y las interpolaciones en el módulo.
  • Activar y entender los source maps con la opción sourcemap.
  • Depurar un error mapeando la traza del módulo generado a tu componente.

Leer la función de render

El módulo que estudiamos en el pipeline se lee con calma si se sabe qué buscar. El corazón es la función que envuelve createComponent: su cuerpo es tu frontmatter, casi literal, y su return es tu plantilla convertida en una cadena etiquetada. Las expresiones que escribiste entre llaves reaparecen como interpolaciones dentro de esa cadena, y los componentes hijos se convierten en llamadas a renderComponent.

const $$Tarjeta = createComponent(async ($$result, $$props, $$slots) => {
  const { titulo } = $$props;               // tus props desestructuradas
  return render`${maybeRenderHead()}
    <article${addAttribute(titulo, 'data-t')}>
      <h2>${titulo}</h2>
    </article>`;
});

Tres piezas bastan para orientarse en cualquier módulo generado:

  • maybeRenderHead aparece al principio del marcado: es donde se inyectan los estilos y scripts que el render recolectó.
  • addAttribute envuelve cada atributo dinámico para serializarlo con seguridad, en vez de concatenar cadenas a ciegas.
  • Las ${...} de la plantilla etiquetada son tus expresiones, ahora escapadas por render antes de convertirse en HTML.

Los componentes hijos siguen una regla igual de reconocible: cada uno se convierte en una llamada a renderComponent, que recibe el $$result acumulador, el nombre, el componente importado y sus props. Verlo desarma otra aparente magia —la composición— y la muestra como lo que es, una llamada de función más:

// <Boton>Entrar</Boton> compilado
${renderComponent($$result, 'Boton', $$Boton, {}, {
  default: () => render`Entrar`
})}

El slot por defecto viaja como una función que produce HTML, y las props como un objeto. Nada de esto es opaco: es tu árbol de componentes traducido, nodo a nodo, a llamadas encadenadas sobre el mismo $$result que recorre toda la página. Leer este módulo una vez, despacio, desactiva para siempre la sensación de que el compilador hace cosas ocultas: no las hace, solo las hace verbosas.

📝
Lo verboso no es lo complejo

El código generado parece complejo porque es verboso: nombra explícitamente cada paso que tu .astro daba de forma implícita. Pero verbosidad no es complejidad. Cada addAttribute, cada maybeRenderHead, cada $$result corresponde a algo que tú ya expresabas en una línea limpia. Leer la salida es ver tu propio componente con todas las costuras a la vista, no descifrar un algoritmo nuevo.

Source maps: el hilo de vuelta a casa

Leer el módulo generado sirve de poco si un error te da un número de línea de ese módulo y no de tu .astro. Para eso existe el source map: un archivo de correspondencias que asocia cada posición del código generado con la posición original de la que salió. Con él, las herramientas —el navegador, Node, tu editor— pueden mostrarte el error en tu componente aunque lo que se ejecute sea el módulo compilado. El compilador de Astro lo produce, y la opción sourcemap de transform decide en qué forma.

const { code, map } = await transform(fuente, {
  filename: 'src/components/Tarjeta.astro',
  sourcemap: 'external', // 'inline' | 'external' | 'both' | false
});
// 'map' es un JSON con la correspondencia posicion-generada -> posicion-original
flowchart LR
ERR[error en el modulo generado] --> MAP[source map]
MAP --> ORIG[linea y columna en tu punto astro]
ORIG --> FIX[depuras sobre tu codigo real]
style MAP fill:#89b4fa,color:#11111b
style FIX fill:#a6e3a1,color:#11111b

Las cuatro variantes de sourcemap cubren cada escenario:

  • inline: el mapa viaja incrustado al final del propio code como un comentario en base64. Cómodo para desarrollo, pesa más.
  • external: el mapa se devuelve aparte en map y no ensucia el código. Lo normal en producción.
  • both: incrusta el mapa y además lo devuelve suelto, cuando quieres las dos cosas.
  • false: ningún mapa, cuando de verdad no lo necesitas.

El mapa en sí es un JSON con una forma estándar, la misma que produce cualquier compilador de la web. Sus campos dicen de qué archivo salió el código y cómo se corresponden las posiciones:

{
  "version": 3,
  "sources": ["src/components/Tarjeta.astro"],
  "names": ["titulo"],
  "mappings": "AAAA,SAAS,GAAG,CAAC..."
}

El campo mappings es una cadena codificada en VLQ base64 que asocia, segmento a segmento, cada posición del code generado con su línea y columna en sources. No hace falta descifrarla a mano: las herramientas la leen por ti. Con inline, ese mismo JSON viaja incrustado al final del code como un comentario reconocible, el que usa toda la web para anclar un mapa a su código:

// ...modulo generado...
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjoz...

En el flujo normal de Astro no tocas esta opción a mano —el framework la gestiona por ti—, pero conocerla es lo que te deja invocar el compilador tú mismo y conservar el hilo de vuelta a tu fuente. Un source map no es un lujo de depuración: es lo que hace que el código generado, por transformado que esté, siga siendo tu código a ojos de las herramientas.

💡
Si la traza apunta al módulo, falta el mapa

Cuando un error de una página Astro te muestra una línea de un archivo con nombres $$ y prefijos raros, no estás ante un bug del framework: estás viendo el módulo generado sin su source map aplicado. La solución no es descifrar esa línea, sino asegurarte de que los source maps están activos para que la herramienta reescriba la traza hacia tu .astro. El mapa existe justo para que nunca tengas que leer coordenadas del código generado.

Una metodología para depurar mirando

Antes de la metodología, una nota práctica sobre cómo llegar al código generado, porque no siempre hay que invocar transform a mano. En desarrollo, las herramientas del navegador con los source maps activos ya te llevan del error a tu .astro. Cuando de verdad quieras leer el módulo emitido de un componente concreto, la vía más directa es llamar tú mismo a transform sobre ese archivo en un script aparte, exactamente como en el pipeline: así obtienes el code sin bucear en artefactos intermedios del build.

Con esa vía a mano, depurar deja de ser adivinar y pasa a ser observar. La regla es bajar al artefacto correcto según el síntoma, y no antes. Si el problema es de estructura del HTML —un nodo que falta, un atributo mal puesto— se lee el HTML emitido. Si es de comportamiento de servidor —una expresión que calcula mal— se lee la función de render del módulo. Si es de hidratación —una isla que no revive— se lee el <astro-island> y sus atributos. Cada síntoma tiene su artefacto, y el source map garantiza que, una vez localizado, puedas volver a tu código para corregirlo.

🧱

Sintoma de estructura

Falta un nodo o sobra un atributo. Lee el HTML generado y compara con tu plantilla.

⚙️

Sintoma de servidor

Una expresion calcula mal. Lee la funcion de render y sigue la interpolacion.

🏝️

Sintoma de isla

Un componente no reacciona. Lee el astro-island y revisa la directiva y sus props.

🧭

Siempre el mapa

Localizado el fallo en la salida, el source map te devuelve a la linea exacta del punto astro.

Esta disciplina —síntoma, artefacto, mapa, corrección— convierte el compilador de una caja negra temida en un colaborador transparente. No hay comportamiento de Astro que no puedas ver si sabes qué salida mirar, y no hay salida que no puedas devolver a tu fuente si conservas el source map. El nivel entero desemboca aquí: en la capacidad de tratar el output compilado no como un misterio, sino como evidencia.

⚠️
Leer el output es diagnóstico, nunca edición

El módulo generado se lee para entender y depurar, jamás para modificarlo a mano. Es un artefacto derivado: el compilador lo reescribe entero en cada build, así que cualquier cambio que hagas en él se pierde al instante siguiente. Si al leer la salida descubres qué falla, la corrección va siempre en el .astro de origen —al que el source map te devuelve—, no en el JavaScript emitido. Confundir el artefacto con la fuente es el único modo de que esta lección se vuelva contra ti.

La legibilidad del output es una decisión moral del compilador

Merece cerrar este nivel con una reflexión sobre por qué el código generado de Astro es legible, porque no tenía por qué serlo. Un compilador podría emitir un amasijo minificado, óptimo para la máquina e ilegible para ti, y sería igual de correcto: al motor de render le da igual que la variable se llame $$result o x7. Que el output conserve la forma de tu componente —tu frontmatter reconocible arriba, tu plantilla como una cadena donde se adivinan tus etiquetas, tus expresiones en su sitio— es una elección deliberada, y una elección con contenido ético además de técnico. Dice que el compilador no aspira a ser un oráculo cuyas decisiones debas aceptar por fe, sino una herramienta cuyas decisiones puedas auditar. Y los source maps son la otra mitad de ese pacto: son la promesa de que, por muy transformado que esté tu código al ejecutarse, nunca pierdes el derecho a volver a lo que escribiste. Juntos —salida legible y mapa fiel— componen una postura sobre qué debe una herramienta a quien la usa: transparencia sobre lo que hace y trazabilidad de vuelta al origen. Esto es lo contrario de la magia, y por eso es lo contrario de la dependencia. La magia deslumbra y encadena, porque lo que no entiendes no lo puedes arreglar ni cuestionar; solo puedes rezar para que funcione. Un compilador que te deja leer su salida y te da el hilo para volver a tu fuente hace la apuesta inversa: prefiere un programador que entiende a uno que confía. Cuando termines este nivel y mires un .astro sabiendo exactamente en qué se convierte, cómo se distribuye el motor que lo convierte y cómo volver del resultado a tu línea, habrás dejado de usar el compilador de Astro para empezar a comprenderlo. Y comprender la herramienta con la que construyes es, al final, la única forma de ser dueño de lo que construyes.

⚔️ Depura desde la salida, no desde la suposición
  1. Compila un .astro con transform y lee su módulo: señala la función de render, maybeRenderHead, un addAttribute y una interpolación tuya.
  2. Vuelve a compilar con sourcemap: 'inline' y localiza el comentario en base64 al final del code; luego con 'external' y comprueba que el mapa sale en map.
  3. Provoca un error de ejecución en el frontmatter, observa la traza con los source maps activos y confirma que apunta a la línea de tu .astro, no del módulo.
  4. Aplica la metodología síntoma-artefacto-mapa a un fallo real: decide qué salida leer, localízalo y explica cómo el mapa te devolvió a tu código.