Cómo controlar las solicitudes de navegación

Responder a las solicitudes de navegación sin esperar a la red mediante un service worker

Las solicitudes de navegación son solicitudes de documentos HTML que realiza tu navegador cada vez que ingresas una URL nueva en la barra de navegación o sigues un vínculo en una página que te lleva a una URL nueva. Aquí es donde los service workers tienen su mayor impacto en el rendimiento: si usas un service worker para responder a las solicitudes de navegación sin esperar a la red, puedes asegurarte de que la navegación sea rápida y confiable, además de ser resiliente cuando la red no esté disponible. Esta es la mayor ganancia de rendimiento que proviene de un service worker, en comparación con lo que es posible con el almacenamiento en caché HTTP.

Como se detalla en la guía Cómo identificar recursos cargados desde la red, una solicitud de navegación es la primera de posiblemente muchas solicitudes realizadas en la “cascada” del tráfico de red. El código HTML que cargas a través de una solicitud de navegación inicia el flujo de todas las demás solicitudes de subrecursos, como imágenes, secuencias de comandos y estilos.

Dentro del controlador de eventos fetch de un service worker, puedes verificar la propiedad request.mode en FetchEvent para determinar si una solicitud es una navegación. Si está configurado en 'navigate', entonces es una solicitud de navegación.

Como regla general, no uses Cache-Control headers de larga duración para almacenar en caché la respuesta HTML para una solicitud de navegación. Por lo general, deben cumplirse a través de la red, con Cache-Control: no-cache, para garantizar que el HTML, junto con la cadena de solicitudes de red posteriores, estén actualizados (de manera razonable). Desafortunadamente, ir contra la red cada vez que un usuario navega a una página nueva significa que cada navegación podría ser lenta. Como mínimo, significa que no será confiable rápida.

Diferentes enfoques para arquitecturas

Averiguar cómo responder a las solicitudes de navegación y evitar la red puede ser complicado. El enfoque correcto depende en gran medida de la arquitectura de tu sitio web y de la cantidad de URLs únicas a las que pueden navegar los usuarios.

Si bien no existe una solución única que se adapte a todas las situaciones, los siguientes lineamientos generales deberían ayudarte a decidir qué enfoque es el más viable.

Sitios estáticos pequeños

Si tu app web consta de una cantidad relativamente pequeña (como unas docenas) de URLs únicas y cada una de ellas corresponde a un archivo HTML estático diferente, un enfoque viable es simplemente almacenar en caché todos esos archivos HTML y responder a las solicitudes de navegación con el HTML almacenado en caché adecuado.

Con el almacenamiento previo en caché, puedes almacenar en caché el HTML con anticipación, tan pronto como se instale el service worker, y actualizar el HTML almacenado en caché cada vez que vuelvas a compilar el sitio y a implementar el service worker.

Como alternativa, si prefieres evitar almacenar previamente en caché todo el código HTML, tal vez porque los usuarios tienden a navegar solo a un subconjunto de URLs de tu sitio, puedes usar una estrategia de almacenamiento en caché en tiempo de ejecución inactiva mientras se vuelve a validar. Sin embargo, ten cuidado con este enfoque, ya que cada documento HTML individual se almacena en caché y se actualiza por separado. El uso del almacenamiento en caché en tiempo de ejecución para HTML es más adecuado si tienes una pequeña cantidad de URLs que el mismo conjunto de usuarios vuelve a visitar con frecuencia, y si te sientes cómodo con el hecho de que esas URLs se vuelvan a validar de forma independiente entre sí.

Apps de una sola página

Las aplicaciones web modernas usan con frecuencia una arquitectura de una sola página. En él, el código JavaScript del cliente modifica el código HTML en respuesta a las acciones del usuario. Este modelo usa la API de History para modificar la URL actual a medida que el usuario interactúa con la app web, lo que conduce a lo que es, en efecto, una navegación "simulada". Si bien las navegaciones posteriores pueden ser "falsas", la navegación inicial es real y, de todos modos, es importante asegurarse de que no esté bloqueada en la red.

Por suerte, si usas la arquitectura de una sola página, hay un patrón directo que debes seguir para entregar la navegación inicial desde la caché: el shell de la aplicación. En este modelo, tu service worker responde a las solicitudes de navegación y muestra el mismo archivo HTML único que ya se almacenó en caché previamente, independientemente de la URL que se solicite. Este código HTML debe ser básico y contener, quizás, un indicador de carga genérico o un contenido esqueleto. Una vez que el navegador carga este HTML desde la caché, el JavaScript del cliente existente toma el control y renderiza el contenido HTML correcto para la URL de la solicitud de navegación original.

Workbox proporciona las herramientas que necesitas para implementar este enfoque. navigateFallback option te permite especificar qué documento HTML usar como shell de la app, junto con una lista opcional de entidades permitidas y bloqueadas para limitar este comportamiento a un subconjunto de tus URLs.

Apps de varias páginas

Si tu servidor web genera el HTML de tu sitio de forma dinámica, o si tienes más de unas decenas de páginas únicas, es mucho más difícil evitar la red cuando se manejan solicitudes de navegación. Es probable que las sugerencias de Todo lo demás se apliquen a tu caso.

Sin embargo, para un subconjunto determinado de apps de varias páginas, es posible que puedas implementar un service worker que replique por completo la lógica que se usa en tu servidor web para generar HTML. Esto funciona mejor si puedes compartir información de enrutamiento y plantillas entre los entornos de servidor y service worker y, en particular, si tu servidor web usa JavaScript (sin depender de funciones específicas de Node.js, como el acceso al sistema de archivos).

Si tu servidor web entra en esa categoría y quieres explorar un enfoque para trasladar la generación de HTML de la red a tu service worker, puedes comenzar con la guía de Más allá de los SPA: arquitecturas alternativas para tu AWP.

Todas las demás

Si no puedes responder a las solicitudes de navegación con HTML almacenado en caché, debes tomar medidas para asegurarte de que agregar un service worker a tu sitio (para controlar otras solicitudes que no sean HTML) retrase la navegación. Iniciar el service worker sin usarlo para responder a una solicitud de navegación introducirá una pequeña cantidad de latencia (como se explica en Cómo compilar apps más rápidas y resilientes con Service Worker). Puedes mitigar esta sobrecarga habilitando una función llamada precarga de navegación y, luego, usando la respuesta de red precargada dentro del controlador de eventos fetch.

Workbox proporciona una biblioteca de ayuda que detecta la función para detectar si se admite la precarga de navegación y, de ser así, simplifica el proceso para indicarle a tu service worker que use la respuesta de red.

Foto de Aaron Burden en Unsplash