Supprimer les service workers qui présentent des bugs

Parfois, un service worker ayant des bugs est déployé, puis des problèmes se produisent. Par exemple, un service worker peut être analysé au moment de l'enregistrement et terminer l'installation. Pourtant, si le code d'un événement fetch présente des bugs, il risque de ne pas répondre aux requêtes, ce qui génère une page vierge. Il est également possible que le balisage de la page soit mis en cache de manière agressive et qu'un service worker ne renvoie que des réponses de balisage obsolètes à partir d'une instance Cache pour les visites ultérieures.

Un service worker peut se retourner de plusieurs façons, ce qui est un problème effrayant sur un site Web de production. Malgré cela, tout n'est pas perdu. Il existe des moyens de remédier à la situation et de repartir sur les rails.

Déployer un service worker no-op

En règle générale, lorsqu'un service worker pose problème, il suffit de déployer un service worker no-op de base qui s'installe et s'active immédiatement, sans gestionnaire d'événements fetch:

// sw.js

self.addEventListener('install', () => {
  // Skip over the "waiting" lifecycle state, to ensure that our
  // new service worker is activated immediately, even if there's
  // another tab open controlled by our older service worker code.
  self.skipWaiting();
});

self.addEventListener('activate', () => {
  // Optional: Get a list of all the current open windows/tabs under
  // our service worker's control, and force them to reload.
  // This can "unbreak" any open windows/tabs as soon as the new
  // service worker activates, rather than users having to manually reload.
  self.clients.matchAll({
    type: 'window'
  }).then(windowClients => {
    windowClients.forEach((windowClient) => {
      windowClient.navigate(windowClient.url);
    });
  });
});

Ce service worker procède immédiatement à l'installation et à l'activation en appelant self.skipWaiting() dans l'événement install. Si vous le souhaitez, vous pouvez déployer du code supplémentaire dans l'événement activate pour forcer le rechargement des autres onglets ouverts avec un WindowClient contrôlé par le service worker.

Il est très important qu'un service worker no-op ne contienne aucun gestionnaire d'événements fetch. Lorsqu'un service worker ne traite pas les requêtes, celles-ci sont transmises au navigateur comme si aucun service worker n'était présent. Une fois qu'un service worker no-op est déployé, il peut être corrigé et déployé ultérieurement en tant que mise à jour.

Cette approche fonctionne en partie parce que les navigateurs disposent de protections solides contre le placement des service workers dans le cache HTTP et parce qu'ils effectuent des vérifications octet par octet du contenu d'un service worker à la recherche de mises à jour. Ces valeurs par défaut permettent de déployer un remplacement no-op pour un service worker présentant des bugs afin de résoudre rapidement le problème.

Mesures supplémentaires à prendre

Le déploiement d'un service worker no-op est suffisant pour neutraliser un service worker défaillant, mais des mesures supplémentaires peuvent être prises si nécessaire.

Que se passe-t-il si vous ne connaissez pas l'URL de l'ancien service worker ?

Parfois, l'URL d'un service worker précédemment installé est inconnue. Cela peut être dû au fait qu'il possède des versions gérées (il contient peut-être un hachage dans son nom, par exemple). Dans ce cas, il peut s'avérer difficile de déployer un service worker no-op correspondant à l'URL de chaque ancien service worker pouvant être enregistré. Cela va à l'encontre des bonnes pratiques, car les développeurs ne se souviendront probablement pas de chaque hachage pour chaque version de service worker déployée.

Heureusement, un en-tête de requête HTTP utile est envoyé avec une requête pour un script de service worker : Service-Worker. Sur le serveur Web, vérifiez la présence de cet en-tête et interceptez la requête pour diffuser un service worker no-op. La réalisation de cet exploit dépend du serveur Web et de la pile backend utilisés. Pour savoir comment procéder, consultez la documentation du langage concerné.

Comme pour les futurs déploiements de service worker, utilisez des noms d'éléments sans version (par exemple, sw.js). Cela rendra les choses beaucoup plus simples par la suite.

Définir un en-tête Clear-Site-Data

Certains navigateurs annulent l'enregistrement de tous les service workers pour une origine si un en-tête de réponse Clear-Site-Data avec la valeur 'storage' est défini. Voici toutefois quelques points à prendre en compte avec cette approche:

Étant donné que la prise en charge de cet en-tête n'est pas totale, il ne peut pas être utilisé seul pour résoudre le problème. Il est donc préférable de considérer Clear-Site-Data comme une mesure à prendre en plus du déploiement d'un service worker no-op.

Les dommages ne sont pas permanents

Il peut être effrayant lorsque l'expérience utilisateur est perturbée par un service worker ayant des bugs, en particulier pour les sites Web volumineux et connus, mais les dommages sont temporaires et réversibles.

S'il est nécessaire de déployer un service worker no-op pour résoudre le problème, prenez le temps de comprendre après coup ce qui s'est passé. À l'avenir, assurez-vous qu'un service worker ne traite que les requêtes auxquelles il est censé le faire. Effectuez des tests fréquents en préproduction et ne déployez les mises à jour que lorsque cela est possible.