Mettre en place un cache client avec Service Workers et Cache API
Le web moderne exige des applications rapides, capables de fonctionner même lorsque la connexion réseau devient instable ou absente. Pour répondre à ce besoin, les navigateurs ont introduit des API capables d'intercepter les requêtes HTTP et de stocker des ressources localement. Un cache judicieusement configuré peut transformer une application lente en une expérience fluide, tout en réduisant la consommation de bande passante et la charge sur les serveurs d'origine.
Les Service Workers constituent aujourd'hui le socle technique privilégié pour orchestrer ce cache. Associés à la Cache API, ils permettent de contrôler finement quelles ressources sont conservées, pendant combien de temps, et selon quelle stratégie. Leur portée dépasse le simple fichier HTML pour englober images, feuilles de style, polices et même des réponses JSON issues d'API tierces.
Ce guide propose un parcours progressif pour comprendre le fonctionnement de ces API, choisir une stratégie adaptée à chaque contexte, puis intégrer concrètement un Service Worker dans un projet web. Les exemples de code restent volontairement génériques afin d'être transposés aussi bien dans une application React, Vue, Svelte ou dans une page statique servie par n'importe quel hébergeur.
Les fondations des Service Workers
Un Service Worker est un script JavaScript que le navigateur exécute en arrière-plan, indépendamment de la page web affichée. Il s'installe via un appel à navigator.serviceWorker.register() et reste actif tant que l'utilisateur ne ferme pas l'onglet ou ne désinstalle pas le service. Cette persistance ouvre la voie au mode hors ligne et à la synchronisation en arrière-plan, même après la fermeture de la page.
Le cycle de vie d'un Service Worker comporte trois phases principales. Durant l'étape install, le navigateur télécharge et exécute le script pour la première fois, moment idéal pour précharger les ressources critiques. L'étape activate suit, une fois l'ancien script déchargé, pour nettoyer les caches obsolètes. Enfin, fetch se déclenche à chaque requête, permettant d'intercepter ou non le trafic réseau.
Pour des raisons de sécurité, les Service Workers ne fonctionnent qu'en HTTPS (sauf sur localhost) et doivent résider à la racine du site ou dans un sous-répertoire cohérent. Cette contrainte garantit qu'un script tiers ne puisse pas intercepter le trafic d'un domaine qui ne lui appartient pas.
La Cache API en pratique
La Cache API, exposée via l'interface caches globale, offre un espace de stockage clé-valeur où les clés sont des objets Request et les valeurs des objets Response. Plusieurs espaces peuvent coexister simultanément, chacun identifié par un nom, ce qui facilite la séparation des ressources par type (par exemple « app-shell-v1 » pour l'interface, « api-v2 » pour les données distantes).
Les méthodes principales couvrent l'essentiel. caches.open(nom) crée ou ouvre un cache. cache.add(url) récupère une ressource réseau et l'insère dans le cache. cache.put(request, response) accepte manuellement les deux extrémités pour un contrôle fin. Enfin, cache.match(request) cherche une entrée correspondant à une requête, pivot des stratégies de lecture.
L'un des pièges classiques consiste à oublier que les corps de réponse ne peuvent être lus qu'une seule fois. Pour réutiliser une réponse mise en cache, il faut la cloner avant de la consommer : response.clone().put() dans le cache puis response renvoyée au client. Cette discipline évite les erreurs subtiles où la page reçoit une réponse vide.
Stratégies de mise en cache courantes
Le choix de la stratégie dépend de la nature de la ressource et de la tolérance à la latence ou à l'obsolescence. Les développeurs disposent généralement de quatre schémas directeurs qu'ils combinent selon les routes :
- Cache First : sert depuis le cache local avec repli réseau en cas d'absence ; idéal pour bundles JavaScript versionnés et images décoratives.
- Network First : tente le réseau en priorité, avec basculement vers le cache en cas d'échec ; adapté aux API JSON où la fraîcheur prime.
- Stale While Revalidate : renvoie immédiatement la version cachée pendant qu'une requête réseau met à jour l'entrée ; compromis apprécié pour les contenus éditoriaux.
- Cache Only ou Network Only : approches réservées aux actifs statiques ou aux endpoints qui ne doivent jamais être persistés.
Ces schémas se déclinent ensuite en variantes : expiration temporelle, segmentation par type de contenu, ou invalidation manuelle lors d'événements applicatifs. Le tableau en fin d'article récapitule les forces et limites de chaque approche.
Implémentation pas à pas
L'écriture d'un Service Worker commence par un fichier séparé, souvent sw.js, placé à la racine. Il contient trois gestionnaires principaux : install pour la mise en cache initiale, activate pour le nettoyage, et fetch pour l'interception. La phase install se prête bien à un appel à cache.addAll() avec un tableau de ressources essentielles.
Voici un squelette typique pour le préchargement des actifs critiques :
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('app-shell-v1').then((cache) =>
cache.addAll(['/', '/index.html', '/styles.css', '/app.js'])
)
);
});
Le gestionnaire fetch applique ensuite la stratégie retenue. Par exemple, pour un mode hors ligne robuste combiné à une mise à jour transparente :
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cached) => {
const networkFetch = fetch(event.request).then((response) => {
const clone = response.clone();
caches.open('app-shell-v1').then((cache) => cache.put(event.request, clone));
return response;
});
return cached || networkFetch;
})
);
});
L'enregistrement côté page s'effectue en général après le chargement du DOM :
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js');
});
}
Cette logique minimaliste suffit pour démarrer. Pour un guide plus complet sur les patterns de cache et l'architecture front-end, le portail principal rassemble plusieurs articles de référence.
Débogage et gestion des versions
Les outils de développement Chrome et Firefox exposent un panneau dédié aux Service Workers, accessible depuis l'onglet Application. Il permet de visualiser les caches actifs, d'inspecter leur contenu, de forcer la mise à jour du script ou de simuler un mode hors ligne. L'option Update on reload facilite les itérations pendant le développement.
La gestion du versionnage repose sur deux mécanismes complémentaires. L'événement activate doit supprimer les caches dont le nom ne correspond plus à la version courante, afin d'éviter l'accumulation de données obsolètes. Parallèlement, l'appel à self.skipWaiting() permet au nouveau script de prendre le contrôle immédiatement, ce qui accélère le déploiement de correctifs critiques.
Quelques écueils méritent une attention particulière. L'utilisation d'un cache trop large consomme rapidement l'espace disque autorisé par le navigateur. La mise en cache de réponses avec des en-têtes Set-Cookie peut compromettre la confidentialité de la session. Un cache mal synchronisé avec l'état du serveur peut renvoyer des informations périmées ; un cache-control: no-store explicite côté serveur reste la meilleure protection pour les données sensibles.
Comparatif et bonnes pratiques
Avant d'intégrer un Service Worker dans un projet de production, il est utile de comparer les différentes familles de cache disponibles.
| Approche | Granularité | Persistance | Cas d'usage typique |
|---|---|---|---|
| Cache API + Service Worker | Par requête HTTP | Manuelle via JS | Sites statiques, PWA, API en lecture |
| HTTP Cache (Cache-Control) | Par ressource | Automatique par le navigateur | Fichiers versionnés, CDN |
| localStorage / sessionStorage | Par clé texte | Permanente ou session | Préférences UI, jetons simples |
| IndexedDB | Par magasin d'objets | Manuelle via JS | Données structurées, gros volumes |
Quelques réflexes aident à tirer le meilleur parti de cette architecture :
- Précharger uniquement les ressources réellement critiques lors de l'install pour limiter le coût initial.
- Préférer des noms de cache versionnés (v1, v2) pour orchestrer les migrations en douceur.
- Servir une page de repli HTML personnalisée pour les chemins non cachés, plutôt que l'erreur générique du navigateur.
- Surveiller la taille du cache depuis le panneau Application et purger régulièrement les entrées obsolètes.
Les Service Workers transforment profondément la façon dont une application web dialogue avec le réseau. Bien configurés, ils offrent une expérience quasi instantanée, résiliente face aux coupures, tout en allégeant la charge serveur. Pour approfondir un point précis ou partager un retour d'expérience, n'hésitez pas à utiliser la page de contact du site. Vous retrouverez également d'autres tutoriels, guides pratiques et actualités pour continuer à monter en compétences.