Otros hooks del ciclo de vida
El resto del ciclo más allá de config:setup: astro:config:done, que entrega la configuración ya sellada y permite inyectar tipos; astro:server:setup, la única ventana al servidor de desarrollo de Vite; astro:build:start y astro:build:done, los dos extremos de la construcción de producción; y astro:build:ssr, donde el adapter recibe el manifiesto y los puntos de entrada del servidor. Cada hook con lo que recibe, lo que permite hacer y en qué comando corre.
Si astro:config:setup es donde una integración transforma, el resto de hooks son donde observa y reacciona: cada uno se asoma a un momento distinto de la vida del sitio con la configuración ya cuajada. Unos corren solo en desarrollo, otros solo en el build; unos te entregan el servidor de Vite en carne viva, otros el manifiesto del servidor o la carpeta final llena de ficheros. Recorrer estos hooks es aprender el mapa temporal completo de Astro: saber en qué instante existe cada cosa y, por tanto, en cuál puedes actuar sobre ella.
- Usar
astro:config:donepara leer la configuración final e inyectar tipos. - Asomarte al servidor de Vite con
astro:server:setupen modo desarrollo. - Enmarcar el build entre
astro:build:startyastro:build:done. - Entender qué entrega
astro:build:ssry por qué es el hook de los adapters.
astro:config:done: la configuración ya sellada
Cuando este hook corre, la ventana de mutación se ha cerrado: la configuración es definitiva y ninguna integración volverá a cambiarla. A cambio de perder updateConfig, ganas certeza —lo que lees en config es lo que de verdad regirá el sitio, con todos los parches de todas las integraciones ya fundidos—. Es el sitio para leer decisiones firmes y para dos acciones reservadas: fijar el adapter con setAdapter e inyectar tipos con injectTypes.
'astro:config:done': ({ config, injectTypes, logger }) => {
logger.info(`salida final: ${config.output}`);
injectTypes({
filename: 'tipos.d.ts',
content: `declare module 'virtual:mi-integracion' {
export const saludo: string;
}`,
});
},
injectTypes escribe un fichero de declaraciones dentro de la carpeta .astro y lo enlaza con los tipos generados del proyecto, de modo que el editor conozca los módulos virtuales o los ambientes que tu integración aporta. Devuelve la URL del fichero escrito. Este es también el hook donde buildOutput te dice si el build será static o server, un dato que en config:setup aún no estaba decidido del todo.
astro:server:setup: la ventana al servidor de desarrollo
Este hook corre únicamente bajo el comando dev, y te entrega algo que ningún otro te da: el server, la instancia viva del servidor de desarrollo de Vite. Con él puedes montar middlewares de Vite, escuchar eventos del observador de ficheros o inyectar comportamiento que solo tiene sentido mientras programas.
'astro:server:setup': ({ server, logger }) => {
server.middlewares.use((req, _res, next) => {
logger.info(`dev sirve ${req.url}`);
next();
});
},
La clave mental es que nada de lo que hagas aquí llega a producción: el servidor de Vite no existe en el build. Es el lugar de las herramientas de desarrollo —un endpoint de depuración, un proxy hacia un backend local, un aviso en consola cuando cambia un fichero—. Sus hermanos astro:server:start, que corre cuando el servidor empieza a escuchar y recibe la dirección, y astro:server:done, cuando se apaga, completan el ciclo de vida del modo dev.
astro:build:start y astro:build:done: los extremos del build
En el comando build, dos hooks marcan el principio y el final. astro:build:start corre justo antes de que empiece la construcción: es el sitio para preparar lo que el build necesitará —crear una carpeta temporal, arrancar un contador, validar una precondición—. No recibe gran cosa porque aún no hay nada construido; su valor es puramente temporal, ser el antes.
'astro:build:done': async ({ dir, pages, logger }) => {
logger.info(`generadas ${pages.length} paginas en ${dir.pathname}`);
// aqui es seguro escribir ficheros extra junto a la salida
},
astro:build:done es el más útil de los dos y uno de los más usados de toda la API. Corre cuando el sitio entero ya está en disco, y recibe dir —la URL de la carpeta de salida—, pages —la lista de páginas generadas— y datos de las rutas y los assets emitidos. Es el después: el momento en que un sitemap se escribe, un fichero de redirecciones se genera, un informe se emite o los artefactos se validan. Todo lo que necesita que el build ya exista vive aquí.
Entre esos dos extremos, el ciclo del build ofrece paradas intermedias más finas para casos especializados. astro:build:setup corre antes de cada pasada del bundler y te entrega la configuración de Vite de esa pasada junto a su target —client o server—, por si necesitas ajustar cómo se empaqueta cada mitad. astro:build:generated se dispara cuando las páginas estáticas ya se han escrito pero el build todavía no se ha cerrado, una rendija para tocar la salida antes de que se dé por terminada. Los usarás rara vez; conviene saber que existen para no forzar en build:done un trabajo que encaja mejor un paso antes.
config:done
La configuración final e inmutable. Se lee, no se cambia. Aquí se fija el adapter y se inyectan tipos.
server:setup
Solo en dev. Entrega el servidor de Vite para montar middlewares y herramientas que nunca llegan a producción.
build:start
El antes del build. Sin artefactos todavía; útil para preparar el terreno y arrancar cronómetros.
build:done
El después del build. Con todo en disco, el sitio de sitemaps, informes y ficheros extra junto a la salida.
astro:build:ssr: el manifiesto y los puntos de entrada
Este hook corre solo en builds con renderizado bajo demanda, y es el corazón de lo que hace un adapter. Recibe el manifest —una descripción serializable de las rutas, los renderers y los assets del sitio, todo lo que el servidor necesitará para responder—, un mapa entryPoints de cada ruta al fichero físico que la sirve, y middlewareEntryPoint, la URL del middleware si lo hay.
'astro:build:ssr': ({ manifest, entryPoints, middlewareEntryPoint, logger }) => {
logger.info(`rutas de servidor: ${entryPoints.size}`);
// un adapter usaria esto para generar su fichero de entrada del runtime
},
Con esas piezas, un adapter fabrica el punto de entrada que la plataforma de destino arrancará: envuelve el manifiesto, conecta los entryPoints y produce el handler que traduce la petición nativa en el Request estándar del motor. El middlewareEntryPoint merece atención aparte: es la URL del middleware ya empaquetado, y el adapter debe encadenarlo por delante del render para que la lógica transversal del usuario corra también en producción. Si un adapter lo ignorase, el middleware funcionaría en dev y desaparecería en el despliegue —un fallo clásico de adapters mal escritos—.
Rara vez tocarás este hook a menos que escribas un adapter, pero conocerlo cierra el mapa —es la costura por la que el build de servidor se enchufa a un runtime concreto—. Y explica por qué un adapter, aunque se enrole en la clave adapter y no en integrations, es una integración en todo lo demás: se distingue solo porque llama a setAdapter en astro:config:done y porque vive este astro:build:ssr para ensamblar el servidor.
flowchart TD SETUP[config setup] --> DONE[config done sella la config] DONE --> BR[bifurcacion por comando] BR --> DEV[server setup solo en dev] BR --> BS[build start el antes] BS --> SSR[build ssr manifiesto y entrypoints] SSR --> BD[build done el despues] style DONE fill:#89b4fa,color:#11111b style BD fill:#a6e3a1,color:#11111b style DEV fill:#f9e2af,color:#11111b
No todos los hooks se disparan siempre. astro:server:setup, astro:server:start y astro:server:done solo existen bajo dev; astro:build:start, astro:build:ssr y astro:build:done solo bajo build; y astro:build:ssr además solo si hay rutas bajo demanda. Diseña tu integración sabiendo que un hook puede no llegar a correr nunca en una ejecución concreta, y no pongas en uno lógica que otra fase necesita.
Cuando tu integración deba producir un fichero que acompañe al sitio —un sitemap.xml, un robots.txt, un manifiesto de PWA, un informe—, hazlo en astro:build:done y no antes. Solo ahí tienes garantía de que la carpeta de salida existe y está completa, y recibes su dir para escribir dentro. Generarlo en un hook anterior es escribir sobre una carpeta que aún se está llenando o que ni siquiera existe.
En astro:config:done ya no hay updateConfig, y no es un olvido de la API: la configuración está sellada a propósito. Si intentas cambiar el comportamiento del sitio desde aquí mutando config, no tendrá efecto, porque el resto del sistema ya leyó la configuración y siguió adelante. Todo lo que transforme la config debe ocurrir en config:setup; en config:done solo se lee, se fija el adapter y se inyectan tipos.
Vale la pena dejar de ver estos hooks como una lista de funciones opcionales y empezar a verlos como las horas de un reloj que da una sola vuelta por ejecución. Cada hook no es un permiso arbitrario que Astro reparte; es el nombre de un instante en el que el estado del mundo acaba de cambiar de forma irreversible. config:setup existe porque la configuración todavía es blanda; config:done, porque acaba de endurecerse; server:setup, porque un servidor de Vite acaba de existir y no existía un momento antes; build:start, porque la carpeta de salida está a punto de empezar a llenarse; build:ssr, porque el manifiesto del servidor acaba de quedar listo pero el runtime aún no se ha ensamblado; build:done, porque todo está por fin en disco. Ninguno de estos momentos es intercambiable con otro, y esa es justamente la lección: en un sistema con fases, el tiempo es una parte del tipo. Que una utilidad esté disponible en un hook y no en otro no es una restricción caprichosa que sortear, es información —te dice qué existe y qué no en ese instante—. El error del principiante es preguntarse cómo colar en un hook una capacidad de otro; el diseño maduro es preguntarse qué acaba de nacer en este hook que no había nacido en el anterior, y actuar sobre eso. Cuando internalizas que la API no está organizada por temas sino por momentos, dejas de buscar la función que quieres y empiezas a buscar el instante en que lo que quieres ya es cierto. Un adapter no vive en build:ssr por convención: vive ahí porque ese es el único punto del tiempo en que el manifiesto ya existe y el runtime todavía no, la única rendija donde su trabajo tiene sentido. Leer la Integration API es, en el fondo, aprender a leer un reloj.
- Añade
astro:build:startyastro:build:donea una integración que guardeDate.nowen el primero y registre en el segundo cuánto duró el build y cuántaspagesse generaron. - En
astro:config:done, imprimeconfig.outputybuildOutput, y compáralos con lo que declaraste en tu configuración. - En
astro:server:setup, monta un middleware de Vite que registre cada URL servida endevy confirma que ese log desaparece en el build. - Escribe un fichero
informe.txtdentro dedirdesdeastro:build:doney verifica que aparece junto a la salida al terminar la construcción.