Service workers plus récents par défaut

tl;dr

À partir de Chrome 68, les requêtes HTTP qui recherchent les mises à jour du script du service worker ne seront plus traitées par défaut par le cache HTTP. Cela permet de contourner une difficulté courante des développeurs : la définition d'un en-tête Cache-Control involontaire dans le script de service worker peut retarder les mises à jour.

Si vous avez déjà désactivé la mise en cache HTTP pour votre script /service-worker.js en le diffusant avec Cache-Control: max-age=0, vous ne devriez constater aucun changement en raison du nouveau comportement par défaut.

De plus, à partir de Chrome 78, la comparaison octet par octet sera appliquée aux scripts chargés dans un service worker via importScripts(). Toute modification apportée à un script importé déclenche le flux de mise à jour du service worker, comme le ferait une modification du service worker de niveau supérieur.

Contexte

Chaque fois que vous accédez à une nouvelle page comprise dans le champ d'application d'un service worker, appelez explicitement registration.update() à partir de JavaScript, ou lorsqu'un service worker est "allumé" via un événement push ou sync, le navigateur demande en parallèle la ressource JavaScript initialement transmise à l'appel navigator.serviceWorker.register() pour rechercher des mises à jour du script du service worker.

Pour les besoins de cet article, supposons que son URL soit /service-worker.js et qu'elle contienne un seul appel à importScripts(), qui charge du code supplémentaire exécuté dans le service worker:

// Inside our /service-worker.js file:
importScripts('path/to/import.js');

// Other top-level code goes here.

Ce qui change

Avant Chrome 68, la requête de mise à jour pour /service-worker.js était effectuée via le cache HTTP (comme le sont la plupart des extractions). Cela signifie que si le script a été envoyé à l'origine avec Cache-Control: max-age=600, les mises à jour dans les 600 secondes (10 minutes) suivantes ne seraient pas transmises au réseau. L'utilisateur risque donc de ne pas recevoir la version la plus récente du service worker. Toutefois, si max-age était supérieur à 86 400 (24 heures), il serait traité comme s'il s'agissait de 86 400, pour éviter que les utilisateurs ne soient bloqués indéfiniment sur une version particulière.

À partir de la version 68, le cache HTTP sera ignoré lors des demandes de mises à jour du script de service worker. Par conséquent, les applications Web existantes peuvent constater une augmentation de la fréquence des requêtes pour leur script de service worker. Les requêtes sur importScripts passent toujours par le cache HTTP. Toutefois, il ne s'agit que de l'option par défaut. Une nouvelle option d'enregistrement, updateViaCache, est disponible et permet de contrôler ce comportement.

updateViaCache

Les développeurs peuvent désormais transmettre une nouvelle option lors de l'appel de navigator.serviceWorker.register(): le paramètre updateViaCache. Il peut prendre l'une des trois valeurs suivantes: 'imports', 'all' ou 'none'.

Ces valeurs déterminent si et comment le cache HTTP standard du navigateur entre en jeu lors de la requête HTTP visant à rechercher les ressources de service worker mises à jour.

  • Si la valeur est 'imports', le cache HTTP n'est jamais consulté lors de la recherche de mises à jour du script /service-worker.js, mais il est consulté lors de la récupération des scripts importés (path/to/import.js, dans notre exemple). Il s'agit du comportement par défaut, qui correspond au comportement à partir de Chrome 68.

  • Si ce paramètre est défini sur 'all', le cache HTTP est consulté lors de l'exécution de requêtes pour le script /service-worker.js de premier niveau, ainsi que pour tous les scripts importés dans le service worker, comme path/to/import.js. Cette option correspond au comportement précédent dans Chrome avant la version 68.

  • Si ce paramètre est défini sur 'none', le cache HTTP n'est pas consulté lors de requêtes pour le /service-worker.js de premier niveau ou pour des scripts importés, tels que path/to/import.js hypothétique.

Par exemple, le code suivant enregistre un service worker et garantit que le cache HTTP n'est jamais consulté lors de la recherche de mises à jour du script /service-worker.js ou de tout script référencé via importScripts() dans /service-worker.js:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js', {
    updateViaCache: 'none',
    // Optionally, set 'scope' here, if needed.
  });
}

Recherche des mises à jour des scripts importés

Avant Chrome 78, tout script de service worker chargé via importScripts() n'était récupéré qu'une seule fois (en vérifiant d'abord le cache HTTP ou via le réseau, selon la configuration updateViaCache). Après cette première récupération, elles sont stockées en interne par le navigateur et ne sont jamais récupérées à nouveau.

Le seul moyen de forcer un service worker déjà installé à récupérer les modifications apportées à un script importé était de modifier l'URL de ce script, généralement en ajoutant une valeur de semver (par exemple, importScripts('https://example.com/v1.1.0/index.js')) ou en incluant un hachage du contenu (par exemple, importScripts('https://example.com/index.abcd1234.js')). La modification de l'URL importée a pour effet secondaire de changer le contenu du script de nœud de calcul de premier niveau, ce qui déclenche à son tour le flux de mise à jour du service.

À partir de Chrome 78, chaque fois qu'une vérification de mise à jour est effectuée pour un fichier service worker de niveau supérieur, des vérifications sont effectuées en même temps pour déterminer si le contenu des scripts importés a changé. Selon les en-têtes Cache-Control utilisés, ces vérifications de script importées peuvent être effectuées par le cache HTTP si updateViaCache est défini sur 'all' ou 'imports' (valeur par défaut), ou si les vérifications peuvent aller directement sur le réseau si updateViaCache est défini sur 'none'.

Si une vérification de mise à jour pour un script importé entraîne une différence octet par octet par rapport à ce qui était précédemment stocké par le service worker, cela déclenche le flux complet de mise à jour du service worker, même si le fichier de service worker de niveau supérieur reste le même.

Le comportement de Chrome 78 correspond à ce que Firefox a implémenté il y a plusieurs années, dans Firefox 56. Safari implémente déjà également ce comportement.

Que doivent faire les développeurs ?

Si vous avez désactivé la mise en cache HTTP pour votre script /service-worker.js en le diffusant avec Cache-Control: max-age=0 (ou une valeur similaire), vous ne devriez constater aucune modification en raison du nouveau comportement par défaut.

Si vous diffusez votre script /service-worker.js avec la mise en cache HTTP activée, soit intentionnellement, soit parce qu'il s'agit simplement de la valeur par défaut de votre environnement d'hébergement, vous constaterez peut-être une augmentation du nombre de requêtes HTTP supplémentaires pour /service-worker.js effectuées sur votre serveur. Il s'agit de requêtes qui étaient traitées par le cache HTTP. Si vous souhaitez continuer à autoriser la valeur de l'en-tête Cache-Control à influencer l'actualisation de votre /service-worker.js, vous devez commencer à définir explicitement updateViaCache: 'all' lors de l'enregistrement de votre service worker.

Étant donné que le nombre d'utilisateurs peut être longue sur les anciennes versions de navigateur, il est toujours recommandé de continuer à définir l'en-tête HTTP Cache-Control: max-age=0 sur les scripts de service worker, même si les navigateurs plus récents peuvent les ignorer.

Les développeurs peuvent profiter de cette occasion pour décider s'ils souhaitent désactiver explicitement la mise en cache HTTP pour leurs scripts importés dès maintenant et ajouter updateViaCache: 'none' à l'enregistrement de leur service worker, le cas échéant.

Diffuser des scripts importés

À partir de Chrome 78, les développeurs peuvent voir plus de requêtes HTTP entrantes pour les ressources chargées via importScripts(), car elles seront désormais recherchées pour les mises à jour.

Si vous souhaitez éviter ce trafic HTTP supplémentaire, définissez des en-têtes Cache-Control de longue durée lorsque vous diffusez des scripts qui incluent du code semver ou des hachages dans leurs URL, et utilisez le comportement updateViaCache par défaut de 'imports'.

Si vous souhaitez que vos scripts importés soient fréquemment mis à jour, assurez-vous de les diffuser avec Cache-Control: max-age=0 ou d'utiliser updateViaCache: 'none'.

Complément d'informations

Les sections "Service Worker Lifecycle" (Cycle de vie des travailleurs de service) et "Caching best practices & max-age haschas" (Bonnes pratiques de mise en cache et "max-age getchas") sont recommandées pour tous les développeurs qui déploient des applications sur le Web.