Optimizar assets: CSS crítico, preload y caché
Más allá de las imágenes, el resto de la cadena de assets decide si los bytes llegan pronto y se quedan cacheados: alinear e inyectar el CSS crítico con inlineStylesheets, precargar recursos clave con preload y anticipar navegaciones con prefetch, y cachear con Cache-Control e immutable los assets con hash. Cómo las cabeceras dependen del adaptador y el host.
Las imágenes ya las trabajaste: formatos modernos, tamaño justo, dimensiones que evitan el salto. Pero una imagen optimizada sirve de poco si el CSS que la rodea bloquea la pintura, si el navegador descubre tarde la fuente del titular, o si cada visita vuelve a descargar lo que no cambió. La cadena de assets es una coreografía de latencia: hay que decidir qué se inyecta en el HTML, qué se precarga, qué se anticipa y qué se cachea. Astro trae piezas para casi todo; el oficio está en orquestarlas.
- Alinear e inyectar el CSS crítico con
inlineStylesheets. - Precargar recursos clave con
preloady anticipar rutas conprefetch. - Cachear con
Cache-Controleimmutablelos assets con hash. - Entender cómo las cabeceras dependen del adaptador y del host.
CSS crítico e inlineStylesheets
Una hoja de estilos enlazada con la etiqueta link bloquea la pintura: el navegador no dibuja hasta descargarla y aplicarla. Para hojas pequeñas, ese ida y vuelta cuesta más que el propio CSS, y conviene inyectarlo directamente en el HTML —en línea— para que llegue con el documento y no exija una petición aparte. Astro automatiza esta decisión con build.inlineStylesheets.
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
build: {
// 'auto' inyecta las hojas pequenas y enlaza las grandes
inlineStylesheets: 'auto',
},
});
El valor auto —el predeterminado sensato— inyecta las hojas por debajo de un umbral y deja enlazadas las grandes, porque inyectar un CSS voluminoso hincharía el HTML y sabotearía su caché. always fuerza la inyección de todo y never la desactiva. En la mayoría de sitios, auto acierta: los estilos scoped de los componentes, que suelen ser diminutos, viajan con el HTML y pintan sin bloqueo.
Pistas al navegador: preload y prefetch
El navegador descubre los recursos leyendo el HTML de arriba abajo, y a veces eso es tarde. Una pista de recurso le adelanta trabajo. preload le ordena descargar ya un recurso que necesitará pronto pero que descubriría tarde —una fuente, la imagen del LCP—, subiéndolo en la cola de prioridades.
---
// En el head del layout
---
<link
rel="preload"
href="/fuentes/inter.woff2"
as="font"
type="font/woff2"
crossorigin
/>
prefetch juega en otro tiempo: anticipa la siguiente navegación descargando en segundo plano, con baja prioridad, una página que el visitante probablemente visitará. Astro trae una integración dedicada que lo hace por ti según una estrategia.
// astro.config.mjs
export default defineConfig({
prefetch: {
prefetchAll: true,
defaultStrategy: 'viewport',
},
});
Con eso, los enlaces se precargan según la estrategia elegida —hover, tap, viewport o load— y puedes afinar enlace a enlace con el atributo data-astro-prefetch. Cuando el visitante hace clic, la página siguiente ya está en su caché y la navegación se siente instantánea.
Las dos pistas se confunden porque ambas descargan antes de tiempo, pero operan en planos distintos. preload es para esta página: trae con alta prioridad algo que ya vas a usar en la carga actual y que el navegador encontraría tarde. prefetch es para la próxima página: trae con baja prioridad algo que quizá uses después, sin competir con lo urgente de ahora. Usar preload para lo que no es crítico roba ancho de banda a lo que sí lo es; usar prefetch para todo desperdicia datos del visitante. Cada pista, en su tiempo.
Caché HTTP: hash inmutable y cabeceras
El mayor ahorro no es enviar menos, sino no volver a enviar lo que no cambió. Los assets que Astro emite en _astro/ llevan un hash de contenido en el nombre: si el archivo cambia, cambia su nombre. Esa propiedad permite la caché más agresiva posible —immutable con un año de vida— sin riesgo de servir algo viejo, porque una versión nueva es literalmente otra URL.
# Assets con hash: cachear para siempre, son inmutables
Cache-Control: public, max-age=31536000, immutable
# HTML: revalidar, porque su URL no cambia con el contenido
Cache-Control: public, max-age=0, must-revalidate
La asimetría es la clave. El HTML conserva su URL aunque su contenido cambie, así que debe revalidarse para no servir una página caduca. Los assets con hash, en cambio, son inmutables por construcción y se cachean sin fecha de vuelta. Dónde se declaran esas cabeceras depende de tu despliegue: en un sitio estático, un archivo de configuración del host; en SSR, el adaptador o el propio middleware.
// En SSR: fijar la cabecera desde un endpoint o middleware
context.response.headers.set(
'Cache-Control',
'public, max-age=31536000, immutable',
);
Astro no sirve tu sitio en producción; lo hace tu host o tu adaptador, y ahí es donde se aplican las cabeceras de caché. Un host estático usa su propio mecanismo —un archivo de reglas—, mientras que un adaptador de servidor te deja fijarlas en código. No asumas que una configuración de caché funciona igual en todas partes: comprueba en la pestaña de red qué Cache-Control recibe de verdad cada tipo de recurso en tu despliegue concreto, porque lo que no verifiques, no está.
Las fuentes web: un caso aparte
Las fuentes merecen atención propia porque combinan dos problemas: bloquean la pintura del texto y pueden provocar CLS al cambiar el alto de las líneas cuando cargan. La primera defensa es font-display, que decide qué hace el navegador mientras la fuente llega: swap muestra ya el texto con una fuente de sistema y lo cambia al cargar la web, evitando el texto invisible.
@font-face {
font-family: 'Inter';
src: url('/fuentes/inter.woff2') format('woff2');
font-display: swap;
}
A eso se suman dos técnicas que ya conoces aplicadas a fuentes: preload para adelantar su descarga y servir solo el subconjunto de caracteres que usas para recortar el peso. Astro 7 incluye además una API de fuentes que automatiza buena parte de esto —descarga, optimización y precarga— para que dejes de orquestarlo a mano. El objetivo es que el titular aparezca pronto, con su tipografía, y sin empujar al resto del contenido cuando llegue.
CSS crítico
inlineStylesheets ‘auto’ inyecta las hojas pequeñas y pinta sin el bloqueo de una petición aparte.
preload
Sube en prioridad un recurso de esta página que el navegador descubriría tarde: fuente o imagen LCP.
prefetch
Anticipa la siguiente navegación en segundo plano para que el próximo clic se sienta instantáneo.
immutable
Los assets con hash se cachean un año sin riesgo: un cambio es otra URL, nunca contenido caduco.
flowchart LR HTML[HTML llega al navegador] --> CSSC[CSS critico inline pinta ya] HTML --> PRE[preload fuente e imagen LCP] HTML --> PF[prefetch de rutas probables] CSSC --> FAST[primera pintura sin bloqueo] PRE --> FAST PF --> NAV[navegacion siguiente instantanea] FAST --> CACHE[assets con hash cacheados un ano] style FAST fill:#a6e3a1,color:#11111b style NAV fill:#89b4fa,color:#11111b style CACHE fill:#cba6f7,color:#11111b
Es tentador pensar la optimización de assets como una lista de trucos sueltos —inyecta esto, precarga aquello, cachea lo otro—, pero todos son variaciones de una sola idea, y verla convierte la lista en un principio. El navegador es un gestor de recursos escasos: un número limitado de conexiones, un hilo principal que no se clona, un ancho de banda que se reparte, una caché que se llena. Cada asset compite por esa atención, y la latencia percibida es el resultado de cómo se resuelva esa competencia. Todo lo que este capítulo enseña es, en el fondo, decirle al navegador cómo priorizar. Inyectar el CSS crítico es negarse a gastar una conexión y una espera en algo minúsculo que cabía en el propio documento. preload es reordenar la cola para que lo que de verdad importa no espere detrás de lo accesorio. prefetch es aprovechar los momentos ociosos —cuando la red no hace nada útil— para adelantar la siguiente visita sin robar a la actual. Y la caché inmutable es la forma más pura de optimización, la que consiste en no repetir un trabajo ya hecho: un asset que no cambia no tiene por qué viajar dos veces. Ninguna de estas técnicas hace el recurso más pequeño; todas hacen que el recurso llegue en mejor momento, que es una dimensión del rendimiento que el peso por sí solo no captura. Por eso un sitio de bytes idénticos puede sentirse rápido o lento según cómo orqueste su llegada. El desarrollador que interioriza esto deja de preguntarse solo cuánto pesa cada cosa y empieza a preguntarse cuándo debe llegar, con qué prioridad y por cuánto tiempo debe quedarse. Optimizar assets es, al final, dirigir una coreografía: repartir la atención finita del navegador entre lo urgente, lo probable y lo ya conocido, de modo que cada byte aparezca justo cuando se le espera y ni un instante después.
- Comprueba en el HTML generado qué hojas de estilo aparecen en línea y cuáles enlazadas, y ajusta
inlineStylesheetspara observar el cambio. - Añade un
preloadpara la fuente del titular y confirma en la pestaña de red que su prioridad sube y su llegada se adelanta. - Activa la integración de
prefetchcon estrategiaviewporty verifica que las páginas enlazadas se descargan antes del clic. - Inspecciona el
Cache-Controlque tu host aplica a un asset de_astro/y a una página HTML; corrige si el asset con hash no llega comoimmutable.