Expériences de navigation instantanées

Compléter les techniques de préchargement traditionnelles avec des services workers

Demián Renzulli
Demián Renzulli
Gilberto Cocchi
Gilberto Cocchi

Effectuer une tâche sur un site implique généralement plusieurs étapes. Par exemple, l'achat d'un produit sur un site d'e-commerce peut impliquer de rechercher un produit, de choisir un article dans la liste des résultats, de l'ajouter au panier et de finaliser l'opération en effectuant le paiement.

En termes techniques, parcourir différentes pages implique d'effectuer une demande de navigation. En règle générale, vous ne devez pas utiliser d'en-têtes Cache-Control persistants pour mettre en cache la réponse HTML d'une requête de navigation. Elles doivent normalement être satisfaites via le réseau, avec Cache-Control: no-cache, pour s'assurer que le code HTML, ainsi que la chaîne des requêtes réseau ultérieures, est (raisonnablement) à jour. Avoir recours au réseau chaque fois que l'utilisateur accède à une nouvelle page signifie malheureusement que chaque navigation peut être lente. Au moins, cela signifie qu'elle ne sera pas fiable.

Pour accélérer ces requêtes, si vous pouvez anticiper l'action de l'utilisateur, vous pouvez demander ces pages et composants à l'avance et les conserver dans le cache pendant une courte période jusqu'à ce que l'utilisateur clique sur ces liens. Cette technique, appelée préchargement, est généralement mise en œuvre en ajoutant des balises <link rel="prefetch"> aux pages, indiquant la ressource à précharger.

Dans ce guide, nous allons découvrir différentes façons d'utiliser les service workers en complément des techniques de préchargement traditionnelles.

Cas de production

MercadoLibre est le plus grand site d'e-commerce d'Amérique latine. Pour accélérer la navigation, ils injectent de manière dynamique des balises <link rel="prefetch"> dans certaines parties du flux. Par exemple, sur les pages de fiches, elles récupèrent la page de résultats suivante dès que l'utilisateur fait défiler la fiche jusqu'en bas :

Capture d&#39;écran des pages de fiche 1 et 2 de MercadoLibre, avec une balise de préchargement de lien les reliant.

Les fichiers pré-téléchargés sont demandés avec la priorité "Faible" et stockés dans le cache HTTP ou le cache de mémoire (selon que la ressource est enregistrable en cache ou non), pendant une durée qui varie selon les navigateurs. Par exemple, à partir de Chrome 85, cette valeur est de 5 minutes. Les ressources sont conservées pendant cinq minutes, après quoi les règles Cache-Control normales s'appliquent.

L'utilisation de la mise en cache du service worker peut vous aider à prolonger la durée de vie des ressources de préchargement au-delà de la période de cinq minutes.

Par exemple, le portail sportif italien Virgilio Sport utilise des service workers pour précharger les posts les plus populaires sur sa page d'accueil. Elles utilisent également l'API Network Information pour éviter le préchargement pour les utilisateurs connectés en 2G.

Logo Virgilio Sport.

Sur trois semaines d'observation, Virgilio Sport a ainsi constaté une amélioration des temps de chargement de la navigation vers ses articles de 78% et une augmentation de 45% du nombre d'impressions d'articles.

Capture d&#39;écran des pages d&#39;accueil et d&#39;article de Virgilio Sport, avec les métriques d&#39;impact après le préchargement.

Implémenter le préchargement avec Workbox

Dans la section suivante, nous utiliserons Workbox pour montrer comment implémenter différentes techniques de mise en cache dans le service worker. Celles-ci peuvent être utilisées en complément de <link rel="prefetch">, voire en remplacement, en déléguant l'intégralité de cette tâche au service worker.

1. Mettre en cache les pages statiques et les sous-ressources de page

Le préchargement permet au service worker d'enregistrer des fichiers dans le cache pendant son installation.

Dans les cas suivants, le préchargement est utilisé pour atteindre un objectif similaire à celui du préchargement : accélérer la navigation.

Mise en cache préalable des pages statiques

Pour les pages générées au moment de la compilation (par exemple, about.html, contact.html) ou sur des sites complètement statiques, il suffit d'ajouter les documents du site à la liste de préchargement afin qu'ils soient déjà disponibles dans le cache chaque fois que l'utilisateur y accède :

workbox.precaching.precacheAndRoute([
  {url: '/about.html', revision: 'abcd1234'},
  // ... other entries ...
]);

Précharger les sous-ressources de la page

Il est généralement recommandé de précharger les éléments statiques que les différentes sections du site peuvent utiliser (JavaScript, CSS, etc.). Cela peut accélérer les scénarios de préchargement.

Pour accélérer la navigation sur un site d'e-commerce, vous pouvez utiliser des balises <link rel="prefetch"> sur les pages de fiches pour précharger les pages d'informations détaillées sur les premiers produits d'une page de fiches. Si vous avez déjà préchargé les sous-ressources de la page produit, la navigation peut être encore plus rapide.

Pour ce faire :

  • Ajoutez une balise <link rel="prefetch"> à la page :
 <link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
  • Ajoutez les sous-ressources de la page à la liste de préchargement dans le service worker :
workbox.precaching.precacheAndRoute([
  '/styles/product-page.ac29.css',
  // ... other entries ...
]);

2. Prolonger la durée de vie des ressources de préchargement

Comme indiqué précédemment, <link rel="prefetch"> extrait et conserve les ressources dans le cache HTTP pendant une durée limitée, après quoi les règles Cache-Control d'une ressource s'appliquent. À partir de Chrome 85, cette valeur est de 5 minutes.

Les services workers vous permettent de prolonger la durée de vie des pages préchargées, tout en offrant l'avantage supplémentaire de rendre ces ressources disponibles pour une utilisation hors connexion.

Dans l'exemple précédent, vous pouvez compléter l'<link rel="prefetch"> utilisé pour précharger une page produit avec une stratégie de mise en cache d'exécution Workbox.

Pour ce faire :

  • Ajoutez une balise <link rel="prefetch"> à la page:
 <link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
  • Implémentez une stratégie de mise en cache de l'environnement d'exécution dans le service worker pour les types de requêtes suivants:
new workbox.strategies.StaleWhileRevalidate({
  cacheName: 'document-cache',
  plugins: [
    new workbox.expiration.Plugin({
      maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
    }),
  ],
});

Dans ce cas, nous avons choisi d'utiliser une stratégie de mise à jour. Avec cette stratégie, les pages peuvent être demandées en parallèle à partir du cache et du réseau. La réponse provient du cache si celui-ci est disponible, sinon du réseau. Le cache est toujours mis à jour avec la réponse du réseau à chaque requête réussie.

3. Déléguer le préchargement au service worker

Dans la plupart des cas, la meilleure approche consiste à utiliser <link rel="prefetch">. La balise est un indice de ressource conçu pour rendre le préchargement aussi efficace que possible.

Toutefois, dans certains cas, il peut être préférable de déléguer complètement cette tâche au service worker. Par exemple, pour précharger les premiers produits d'une page de liste de produits affichée côté client, vous devrez peut-être injecter plusieurs balises <link rel="prefetch"> de manière dynamique sur la page, en fonction d'une réponse d'API. Cela peut consommer temporairement du temps sur le thread principal de la page et rendre l'implémentation plus difficile.

Dans ce cas, utilisez une "stratégie de communication de page vers service worker" pour déléguer complètement la tâche de préchargement au service worker. Pour ce faire, utilisez worker.postMessage() :

Icône d&#39;une page effectuant une communication bidirectionnelle avec un service worker.

Le package de fenêtre Workbox simplifie ce type de communication en exploitant de nombreux détails de l'appel sous-jacent.

Le préchargement avec la fenêtre de boîte de travail peut être implémenté comme suit:

  • Sur la page: appelez le service worker en lui transmettant le type de message et la liste des URL à précharger:
const wb = new Workbox('/sw.js');
wb.register();

const prefetchResponse = await wb.messageSW({type: 'PREFETCH_URLS', urls: []});
  • Dans le service worker : implémentez un gestionnaire de messages pour envoyer une requête fetch() pour chaque URL à précharger :
addEventListener('message', (event) => {
  if (event.data.type === 'PREFETCH_URLS') {
    // Fetch URLs and store them in the cache
  }
});