Expériences de navigation instantanées

Complément des techniques de préchargement traditionnelles avec des service workers

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

L'exécution d'une tâche sur un site implique généralement plusieurs étapes. Par exemple, l'achat d'un produit sur un site de commerce électronique peut impliquer de rechercher un produit, de le sélectionner dans la liste des résultats, de l'ajouter au panier et de finaliser l'opération en passant au paiement.

D'un point de vue technique, passer d'une page à l'autre implique d'envoyer une demande de navigation. En règle générale, il est déconseillé d'utiliser des en-têtes Cache-Control de longue durée pour mettre en cache la réponse HTML à 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 de requêtes réseau suivantes, sont (raisonnablement) à jour. Le fait de devoir passer par le réseau chaque fois que l'utilisateur accède à une nouvelle page signifie malheureusement que chaque navigation peut être lente, au minimum, cela signifie qu'elle ne sera pas fiable rapidement.

Pour accélérer ces demandes, si vous pouvez anticiper l'action de l'utilisateur, vous pouvez demander ces pages et éléments à 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 implémentée en ajoutant des balises <link rel="prefetch"> aux pages, indiquant la ressource à précharger.

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

Scénarios de production

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

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

Les fichiers préchargés sont demandés avec la priorité la plus basse et stockés dans le cache HTTP ou dans le cache de la mémoire (selon que la ressource peut être mise en cache ou non), pendant une durée qui varie selon les navigateurs. Par exemple, depuis Chrome 85, cette valeur est de 5 minutes. Les ressources sont conservées pendant cinq minutes, au terme desquelles les règles Cache-Control normales s'appliquent.

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 fenêtre de cinq minutes.

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

Logo Virgilio Sport.

Ainsi, après trois semaines d'observation, Virgilio Sport a constaté une augmentation de 78% des temps de chargement de la navigation vers les articles et une augmentation de 45% du nombre d'impressions d'articles.

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

Implémenter la mise en cache préalable avec Workbox

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

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

La mise en cache désigne la capacité du service worker à enregistrer des fichiers dans le cache pendant l'installation.

Dans les cas suivants, la mise en cache préalable permet d'atteindre un objectif semblable à celui du préchargement: accélérer la navigation.

Mettre en cache les pages statiques

Pour les pages générées au moment de la compilation (par exemple, about.html ou contact.html) ou sur des sites entièrement statiques, il suffit d'ajouter les documents du site à la liste de pré-cache 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 ...
]);

Mettre en cache les sous-ressources de la page

La mise en cache préalable d'éléments statiques pouvant être utilisés par les différentes sections du site (JavaScript, CSS, etc.) est une bonne pratique générale et peut renforcer 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 afin de précharger les pages d'informations détaillées sur les produits pour les premiers produits d'une page. Si vous avez déjà mis en cache 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 page à la liste de pré-cache 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. Depuis Chrome 85, cette valeur est de 5 minutes.

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

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

Pour implémenter cela:

  • 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 type "obsolète" pendant la revalidation. Avec cette stratégie, il est possible de demander simultanément des pages à partir du cache et du réseau. La réponse provient du cache (si disponible) et 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">. Le tag est une indication de ressource conçue pour optimiser l'efficacité du préchargement.

Toutefois, dans certains cas, il peut être préférable de déléguer entièrement cette tâche au service worker. Par exemple, pour précharger les premiers produits d'une page de fiche produit affichée côté client, il peut être nécessaire d'injecter plusieurs balises <link rel="prefetch"> de manière dynamique dans la page, en fonction d'une réponse de l'API. Cela peut momentanément prendre du temps sur le thread principal de la page et compliquer l'implémentation.

Dans de tels cas, utilisez une "stratégie de communication entre la page vers le service worker" pour déléguer la tâche de préchargement complète au service worker. Ce type de communication peut être réalisé en utilisant worker.postMessage():

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

Le package Workbox Window simplifie ce type de communication en éliminant de nombreux détails de l'appel sous-jacent en cours.

Le préchargement avec la fenêtre de la boîte de travail peut être implémenté de la manière suivante:

  • Sur la page: appelez le service worker en 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 émettre 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
  }
});