Compléter les techniques de préchargement traditionnelles aux service workers
Effectuer une tâche sur un site implique généralement plusieurs étapes. Par exemple, l'achat d'un produit sur un site Web de commerce électronique peut impliquer la recherche d'un produit, le choix d'un article dans la liste des résultats, l'ajout de l'article au panier et la finalisation de l'opération en passant au paiement.
En termes techniques, parcourir différentes pages implique d'effectuer 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 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 de requêtes réseau ultérieures, 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 moins, elle ne sera pas fiable rapide.
Pour accélérer ces requêtes, si vous pouvez anticiper l'action de l'utilisateur, vous pouvez demander ces pages et ces é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 prefetching, 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 manières d'utiliser des 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 des balises <link rel="prefetch">
de manière dynamique à certaines parties du flux. Par exemple, dans les fiches, la page de résultats suivante est récupérée dès que l'utilisateur fait défiler la liste jusqu'en bas:
Les fichiers préchargés sont demandés au niveau le plus bas et stocké 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, à 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
habituelles de la ressource s'appliquent.
La mise en cache des service workers permet de 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 aux service workers pour précharger les posts les plus populaires sur sa page d'accueil. Ils utilisent également l'API Network Information afin d'éviter le préchargement pour les utilisateurs qui disposent d'une connexion 2G.
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.
Implémenter la mise en cache préalable 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 pré-cache les pages statiques et les sous-ressources de pages
La mise en cache préalable est la capacité du service worker à enregistrer des fichiers dans le cache pendant l'installation.
Dans les cas suivants, la mise en cache préalable est utilisée pour atteindre un objectif semblable au préchargement: accélérer les navigations.
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 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 ...
]);
Sous-ressources de la page de mise en cache préalable
La mise en cache préalable des éléments statiques susceptibles d'être utilisés par les différentes sections du site (par exemple, JavaScript, CSS, etc.) constitue une bonne pratique générale et peut améliorer davantage 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">
dans les fiches afin de précharger les pages d'informations détaillées sur les premiers produits d'une fiche. Si vous avez déjà mis en pré-cache les sous-ressources de la page produit, cela peut accélérer la navigation.
Pour ce faire, procédez comme suit:
- 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é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. Passé ce délai, les règles Cache-Control
d'une ressource s'appliquent. À partir de 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 rendant ces ressources disponibles hors connexion.
Dans l'exemple précédent, il est possible de compléter le <link rel="prefetch">
utilisé pour le préchargement d'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 "stale-while-revalidate". 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 disponible, ou du réseau. Le cache est toujours tenu à 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 un indice de ressource conçu 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 fiche produit affichée côté client, il peut être nécessaire d'injecter plusieurs balises <link rel="prefetch">
de manière dynamique sur la page, en fonction d'une réponse d'API. Cela peut momentanément faire perdre du temps au thread principal de la page et compliquer l'implémentation.
Dans ce cas, utilisez une stratégie de communication "page to service worker" pour déléguer la tâche de préchargement complète au service worker. Ce type de communication peut être obtenu en utilisant worker.postMessage():
Le package Workbox Window simplifie ce type de communication, en faisant abstraction de nombreux détails de l'appel sous-jacent en cours.
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 afin d'é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
}
});