Saltar al contenido

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.

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.

JS
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:

JS
// <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.

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.

TypeScript
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

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:

JSON
{  "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:

JS
// ...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.

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.

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.