Accueil / Articles

Activer le support hors ligne dans les applications web avec des service workers

Les travailleurs de service et l’API Cache permettent à un site de se charger instantanément et de continuer à fonctionner hors ligne. Rédaction du travailleur, enregistrement de celui-ci et choix des stratégies de mise en cache.

Éditeur : REACTAPP.TOP5 min de lecture1098 mots

Sources: ☕ JavaScript Hack That Makes Any Website Work Offline

Imaginez quelqu’un qui consulte votre site depuis un train, où la connexion fluctue toutes les quelques secondes. Sur la plupart des sites web, une telle connexion instable signifie un problème insoluble : une erreur du navigateur indiquant que l’utilisateur est hors ligne. Et si votre site pouvait contourner complètement ce problème et continuer de fonctionner malgré tout ?

Ce n’est pas une fonctionnalité expérimentale de l’avenir. Cela est déjà possible aujourd’hui grâce à une technologie de navigateur appelée Service Worker. Un Service Worker agit comme un intermédiaire scriptable situé entre votre application web et le réseau. Il peut intercepter les demandes avant même qu’elles n’atteignent le serveur et y répondre lui-même à l’aide de fichiers stockés localement, ce qui permet à votre site de continuer de fonctionner même en l’absence totale de connexion.

Ce truc permet non seulement d’ajouter une solution de secours utile, mais il peut également accélérer considérablement les temps de chargement et rendre votre application bien plus résistante aux réseaux défaillants. Et bien qu’il paraisse avancé, sa mise en place est plutôt simple.

Ce qui rend ce truc possible : les Service Workers associés à l’API Cache

Deux fonctionnalités du navigateur travaillent ensemble pour rendre cela possible :

  1. Service Worker : un script en arrière-plan qui s’exécute indépendamment du thread principal de votre page, agissant comme une couche réseau de remplacement.
  2. API Cache : une interface intégrée au navigateur qui vous permet de stocker et de récupérer des ressources de manière programmée, un peu comme un stockage clé-valeur. C’est là que vous placerez l’HTML, le CSS, le JavaScript, les images et les autres éléments dont votre site a besoin.

C’est le flux général : la première fois qu’une personne visite votre site depuis Internet, le Service Worker s’installe et télécharge les fichiers importants dans son cache. Par la suite, toute demande réseau effectuée par votre page passe d’abord par le Service Worker. Lorsque l’utilisateur perd sa connexion, le worker répond en utilisant ce qui est déjà stocké dans le cache, au lieu d’essayer — et d’échouer — de se connecter au serveur, ce qui permet à la page de s’afficher presque instantanément.

Étape 1 : Écrire le script du Service Worker

Commencez par créer un fichier nommé sw.js à la racine de votre projet. C’est ce script qui est chargé d’installer le cache et d’intercepter les demandes futures.

// sw.js

const CACHE_NAME = 'my-website-cache-v1';
const urlsToCache = [
  '/',
  '/index.html',
  '/styles.css',
  '/script.js',
  '/images/logo.png'
];

// The 'install' event is fired when the service worker is first installed.
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

// The 'fetch' event is fired for every network request.
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        // If the request is in the cache, serve the cached version.
        if (response) {
          console.log('Serving from cache:', event.request.url);
          return response;
        }

        // Otherwise, fetch from the network.
        console.log('Fetching from network:', event.request.url);
        return fetch(event.request);
      })
  );
});

Ce fichier écoute principalement deux événements liés au cycle de vie :

  • install : c’est ici que vous ouvrez un cache nommé et que vous y ajoutez la liste des fichiers que vous souhaitez avoir à disposition même en l’absence de connexion réseau.
  • fetch : cet événement se produit pour chaque requête effectuée par la page. Le worker vérifie s’il existe déjà une réponse correspondante dans le cache ; si c’est le cas, cette copie en mémoire est renvoyée, sinon la requête est envoyée au réseau comme d’habitude.

Étape 2 : Enregistrer le Worker depuis votre application

Lorsque le script worker est prêt, il faut encore indiquer au navigateur de l’utiliser. Ajoutez le fragment suivant dans votre fichier de script principal, ou insérez-le directement à l’intérieur d’une balise <script> dans votre HTML.

// Register the service worker
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js')
      .then(registration => {
        console.log('Service Worker registered successfully:', registration);
      })
      .catch(error => {
        console.error('Service Worker registration failed:', error);
      });
  });
}

Ce bloc vérifie d’abord si le navigateur actuel prend en charge l’API Service Worker, et si c’est le cas, il enregistre votre fichier sw.js. Notez le chemin utilisé pour son enregistrement : /sw.js doit se trouver à la racine de votre site, car un Service Worker ne peut contrôler que les pages situées dans le répertoire depuis lequel il a été enregistré.

Vérifier son fonctionnement

Pour voir cela en action, chargez votre site dans un navigateur qui prend en charge les Service Workers — Chrome, Firefox et Edge conviennent tous.

  • Ouvrez les outils de développement du navigateur (F12, ou Ctrl+Shift+I).
  • Passez au panneau Application.
  • Dans la barre latérale, trouvez Service Workers. Votre fichier sw.js doit y apparaître en tant que service actif.
  • Cliquez sur Cache Storage pour confirmer que votre cache nommé existe et contient les fichiers que vous avez listés.
  • Cochez la case "Offline" en haut de la section Service Worker.
  • Réchargez la page.
  • Si tout est configuré correctement, la page s’affiche immédiatement même en l’absence d’accès au réseau. Les résultats de la console dans les outils de développement confirmeront que les requêtes sont interceptées et répondues directement depuis le cache plutôt que depuis le réseau.

    Pour aller plus loin : autres stratégies de mise en cache

    Ce qui vient d’être décrit correspond à une approche cache en premier, réseau en secours — idéale pour des ressources qui changent rarement, comme les images statiques ou les scripts regroupés. Mais les Service Workers ne se limitent pas à ce modèle unique ; il existe quelques autres stratégies courantes :

    • Privilégier le réseau, recourir au cache en dernier recours : adapté aux contenus qui changent fréquemment et doivent rester à jour. Le processus tente d’abord de récupérer les données via le réseau, et ne recourt au cache que si cette demande échoue, par exemple en raison d’une connexion médiocre.
    • Utiliser les données obsolètes tant que la validation n’est pas terminée : le processus répond immédiatement avec les données déjà en cache pour plus de rapidité, tout en lançant simultanément une demande réseau en arrière-plan afin de mettre à jour le cache pour la prochaine chargement de la page. Cela permet des réponses rapides dès maintenant et du contenu mis à jour peu de temps après.

    Maîtriser ce modèle de base hors ligne vous prépare également à créer des applications web progressives complètes, où le support hors ligne est combiné à des fonctionnalités telles que les notifications push et la possibilité d’installer le site sur l’écran d’accueil d’un appareil comme une application native.

    Intégrer ce modèle dans votre projet représente un investissement relativement faible pour des résultats significatifs : au lieu qu’une connexion interrompue gâche complètement l’expérience, vos utilisateurs ne remarquent à peine l’interruption.

    Lectures complémentaires

  • Workers dédiés, partagés et de service : choisir le bon thread du navigateur — Comprenez en quoi les workers dédiés, partagés et de service diffèrent par leur portée, leurs mécanismes de communication et leur fonction, et découvrez quand chacun d’eux améliore réellement une application web.