La API prefetch() y el ClientRouter
Precargar por código con la función prefetch() del módulo astro:prefetch cuando la navegación no es un enlace, controlar su avidez con eagerness y la Speculation Rules API, saber cuándo usar la API y cuándo el atributo, y combinarla con el ClientRouter de las View Transitions para lograr navegación instantánea: red ya resuelta antes del clic y cambio de página sin recarga completa.
El atributo data-astro-prefetch cubre el caso común —un enlace visible que el visitante va a pulsar—, pero no toda navegación es un <a>. A veces la ruta siguiente se decide por código: un botón que dispara un salto, un formulario que redirige, un paso que se anticipa según lo que el usuario acaba de hacer. Para esos casos Astro expone prefetch(), la versión programática de la misma maquinaria, invocable desde cualquier script de cliente. Y cuando la combinas con el <ClientRouter /> de las View Transitions, las dos mitades de la latencia —traer la página y pintarla— caen a la vez.
- Precargar por código con
prefetch()del móduloastro:prefetch. - Ajustar la avidez con
eagernessy la Speculation Rules API. - Decidir cuándo usar la API programática y cuándo el atributo.
- Componer precarga y
<ClientRouter />para un salto casi instantáneo.
prefetch(): precargar cuando no hay un ancla
La función vive en el módulo virtual astro:prefetch y solo puede usarse en scripts que corren en el navegador, porque se apoya en APIs del cliente. Se importa dentro de un <script> y se llama con la ruta que quieres anticipar.
<button id="ir">Empezar</button>
<script>
import { prefetch } from 'astro:prefetch';
const boton = document.getElementById('ir');
boton?.addEventListener('pointerenter', () => {
prefetch('/onboarding/paso-1');
});
</script>
Aquí el disparador no es un enlace sino la intención de pulsar un botón: al asomar el puntero, precargamos el primer paso del asistente, y cuando el clic llega y el código navega, el documento ya está en caché.
prefetch() es la herramienta para toda navegación que no nace de un <a> —botones, gestos, redirecciones tras una acción— y para primar destinos según lógica propia que ningún atributo estático podría expresar.
Hereda, además, la misma prudencia que las estrategias declarativas: prefetch() detecta el modo de ahorro de datos y las conexiones lentas, y en esos casos no precarga. Si tienes una razón de peso para forzarla —un destino crítico que justifica el gasto incluso en red pobre— existe la vía de escape explícita.
// Precargar incluso en ahorro de datos o conexion lenta
prefetch('/checkout', { ignoreSlowConnection: true });
Usa ignoreSlowConnection con cuentagotas: cada vez que lo activas estás decidiendo por el visitante que su cuota de datos vale menos que tu milisegundo ahorrado, y esa decisión rara vez es tuya.
eagerness: sugerir al navegador cuánto anticipar
En navegadores que soportan la Speculation Rules API, prefetch() acepta un segundo grado de control: eagerness, una pista sobre con cuánta avidez debe el navegador especular con el destino. Sus valores, de más a menos agresivo, son immediate, eager, moderate y conservative, y el defecto es immediate.
Esta capacidad se apoya en el experimento clientPrerender, que eleva la precarga a prerenderizado: el navegador no solo descarga el HTML, sino que llega a construir la página en segundo plano.
<script>
import { prefetch } from 'astro:prefetch';
// Ruta critica en el recorrido: maxima avidez
prefetch('/getting-started');
// Ruta pesada en recursos: que el navegador modere
prefetch('/panel-con-datos', { eagerness: 'conservative' });
// Ruta que quiza no se visite: deja decidir al navegador
prefetch('/terminos', { eagerness: 'moderate' });
</script>
La gracia de eagerness es que delega la decisión fina en el navegador, que conoce cosas que tu código ignora: memoria disponible, presión de CPU, cuántas especulaciones ya hay en vuelo.
Con moderate sobre un conjunto grande de enlaces, el navegador aplica una cola de tipo primero en entrar, primero en salir y sus propias heurísticas para decidir el orden y el momento, en lugar de dispararlas todas de golpe. Es la forma correcta de precargar muchos destinos sin abrumar: le das una lista y una avidez, y él la administra. Los navegadores basados en Chromium, además, imponen límites internos contra la sobreespeculación, otra red de seguridad que conviene tener presente pero no sustituye tu criterio.
Cuándo la API y cuándo el atributo
La regla para elegir entre la precarga declarativa y la programática es simple: usa el atributo siempre que puedas y la API solo cuando debas. data-astro-prefetch es estático, legible en el marcado y no cuesta un solo byte de JavaScript propio; cúbrelo todo con él mientras el destino sea un <a> visible.
Reserva prefetch() para lo que el atributo no alcanza: navegaciones que no nacen de un enlace, decisiones que dependen del contexto de red o de sesión, o el primado de un destino según una señal que solo existe en tiempo de ejecución. Y recuerda que, bajo el <ClientRouter />, buena parte de esa precarga ya ocurre sola; la API es el bisturí, no el martillo.
Componer con el ClientRouter: la latencia en dos mitades
La latencia percibida de una navegación tiene dos componentes: el tiempo de traer el documento por la red y el tiempo de pintarlo —descartar la página vieja, construir la nueva—. La precarga ataca la primera mitad.
El <ClientRouter /> de las View Transitions ataca la segunda: intercepta el clic, evita la recarga completa del navegador y sustituye el contenido con una transición suave, conservando el hilo y dando sensación de aplicación de una sola página sin serlo.
---
// src/layouts/Base.astro
import { ClientRouter } from 'astro:transitions';
---
<head>
<ClientRouter />
</head>
Lo notable es que ambas mitades se refuerzan, y Astro las une por defecto: en cuanto colocas el <ClientRouter />, la precarga se enciende sola con prefetchAll: true, tratando todos los enlaces de la página como candidatos.
La razón es de pura coherencia: si vas a navegar sin recargar, tiene todo el sentido que el documento ya esté en caché cuando el clic ocurra, para que la transición no tenga que esperar a la red. Puedes ajustar o desactivar ese comportamiento desde la configuración si prefieres un control más fino.
// astro.config.mjs — mantener el ClientRouter pero precargar solo lo marcado
export default defineConfig({
prefetch: {
prefetchAll: false,
},
});
El resultado combinado es lo más cerca que un sitio multipágina llega de sentirse como una SPA sin pagar su precio: prefetch() —o la precarga automática— borra la espera de red antes del clic, y el <ClientRouter /> borra el parpadeo de la recarga en el clic. Dos técnicas independientes que, juntas, hacen desaparecer casi toda la latencia visible de moverse por tu sitio.
sequenceDiagram participant U as Visitante participant P as prefetch participant C as Cache del navegador participant R as ClientRouter U->>P: intencion antes del clic P->>C: descarga el documento destino U->>R: clic en el enlace R->>C: pide el documento C-->>R: ya esta en cache sin red R->>U: transicion sin recarga completa
No es un ancla
Botones, gestos o redirecciones por codigo: prefetch invocado a mano cubre lo que el atributo no ve.
eagerness
Con clientPrerender, sugiere cuanto especular: de immediate a conservative segun el coste del destino.
ClientRouter
Enciende la precarga por defecto y cambia la pagina sin recarga, con una transicion suave.
Dos mitades
La precarga borra la espera de red; el router borra el parpadeo del recargado. Juntas, casi cero latencia.
prefetch() depende de APIs del navegador, así que impórtala únicamente dentro de un <script> de cliente; usarla en el frontmatter del servidor no tiene sentido y fallará. Como sus hermanas declarativas, solo actúa sobre rutas internas de tu sitio. Y cuando el <ClientRouter /> ya precarga todo por defecto, muchas veces no necesitarás llamar a prefetch() a mano: resérvala para las navegaciones que no son enlaces o para primar destinos con una lógica que el marcado no puede capturar.
El defecto immediate es la avidez máxima: el navegador intenta especular con el destino cuanto antes. Sobre una o dos rutas críticas es justo lo que quieres; sobre una lista de veinte enlaces es una tormenta de descargas y, con clientPrerender, de páginas construidas en segundo plano que consumen memoria y CPU. Para conjuntos grandes, baja a moderate y deja que el navegador administre la cola. La avidez máxima es un recurso escaso: gástalo en lo que de verdad decide el recorrido del visitante.
Conviene desmitificar la palabra instantáneo, porque no hay nada gratis en ella. Traer un documento por la red cuesta lo que cuesta; pintar una página cuesta lo que cuesta. La combinación de prefetch() y <ClientRouter /> no elimina esos costes: los mueve en el tiempo para que caigan fuera del camino crítico de la interacción. La descarga sigue ocurriendo, pero antes del clic, durante esa pausa muerta en la que el visitante lee y apunta; el trabajo de construir la vista sigue ocurriendo, pero como un intercambio de nodos en el documento vivo en vez de una recarga desde cero. Toda la ingeniería del rendimiento percibido es, en el fondo, esta reubicación temporal: hacer el trabajo caro cuando nadie lo está esperando, para que en el instante en que sí lo esperan ya esté hecho. Es la misma idea que gobierna la caché, la especulación en un procesador o el precocinado en una cocina: adelantar el esfuerzo a los huecos ociosos para que el momento crítico llegue vacío de espera. Verlo así tiene una consecuencia liberadora y una advertencia. La consecuencia: dejas de perseguir la quimera de hacer todo más rápido y empiezas a preguntarte qué puedo adelantar y a qué hueco. La advertencia: adelantar trabajo solo es gratis si el hueco existe y si el trabajo se aprovecha. Precargar en una conexión saturada no encuentra hueco, y precargar lo que nadie visita no aprovecha nada; en ambos casos la latencia no se ha movido, se ha duplicado. La navegación instantánea, bien entendida, no es velocidad mágica: es el arte de colocar cada coste en el momento en que menos duele.
- Añade un
<script>que llame aprefetch()sobre una ruta cuando el puntero entra en un botón y confirma en la pestaña de red que la descarga ocurre antes del clic. - Coloca el
<ClientRouter />en tu layout base y comprueba que la navegación entre páginas deja de recargar el documento completo. - Verifica que, con el
<ClientRouter />puesto, los enlaces se precargan solos aunque no lleves ningúndata-astro-prefetch. - Prueba
prefetch()coneagerness: 'moderate'sobre una lista de enlaces y observa que el navegador espacia las descargas en vez de dispararlas todas a la vez.