Mettre en cache les ressources pendant l'exécution

Certains éléments de votre application Web peuvent être peu utilisés, très volumineux ou varier en fonction de l'appareil (comme les images responsives) ou de la langue de l'utilisateur. Il s'agit d'instances où la mise en cache préalable peut être un anti-modèle. Vous devez plutôt vous appuyer sur la mise en cache de l'environnement d'exécution.

Dans Workbox, vous pouvez gérer la mise en cache des éléments au moment de l'exécution en utilisant le module workbox-routing pour faire correspondre les routes, et gérer les stratégies de mise en cache correspondantes avec le module workbox-strategies.

Stratégies de mise en cache

Vous pouvez gérer la plupart des routes pour les éléments avec l'une des stratégies de mise en cache intégrées. Elles sont abordées en détail plus tôt dans cette documentation, mais en voici quelques-unes qui méritent d'être résumées:

  • La fonctionnalité Stale when Revalidate utilise une réponse mise en cache pour une requête si elle est disponible et met à jour le cache en arrière-plan avec une réponse du réseau. Par conséquent, si l'élément n'est pas mis en cache, il attend la réponse du réseau et l'utilise. Cette stratégie est assez sûre, car elle met régulièrement à jour les entrées de cache qui en dépendent. L'inconvénient est qu'elle demande toujours un élément au réseau en arrière-plan.
  • Network First tente d'abord d'obtenir une réponse du réseau. Si une réponse est reçue, il la transmet au navigateur et l'enregistre dans un cache. Si la requête réseau échoue, la dernière réponse mise en cache est utilisée, ce qui permet d'accéder à l'élément hors connexion.
  • Cache First recherche d'abord une réponse dans le cache et l'utilise si elle est disponible. Si la requête ne se trouve pas dans le cache, le réseau est utilisé et toute réponse valide est ajoutée au cache avant d'être transmise au navigateur.
  • Réseau uniquement force la réponse à provenir du réseau.
  • L'option Cache uniquement force la réponse à provenir du cache.

Vous pouvez appliquer ces stratégies à la sélection de requêtes à l'aide des méthodes proposées par workbox-routing.

Appliquer des stratégies de mise en cache avec la correspondance de routes

workbox-routing expose une méthode registerRoute pour faire correspondre les routes et les gérer à l'aide d'une stratégie de mise en cache. registerRoute accepte un objet Route qui accepte à son tour deux arguments:

  1. Chaîne, expression régulière ou rappel de correspondance pour spécifier les critères de correspondance de route.
  2. Un gestionnaire de la route, généralement une stratégie fournie par workbox-strategies.

Il est préférable d'utiliser des rappels de correspondance pour mettre en correspondance les routes, car ils fournissent un objet de contexte qui inclut l'objet Request, la chaîne d'URL de la requête, l'événement d'extraction et une valeur booléenne indiquant si la requête est de même origine.

Le gestionnaire gère ensuite la route correspondante. L'exemple suivant crée une route qui correspond aux requêtes d'image de même origine à venir, en appliquant d'abord le cache, en revenant à la stratégie réseau.

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';

// A new route that matches same-origin image requests and handles
// them with the cache-first, falling back to network strategy:
const imageRoute = new Route(({ request, sameOrigin }) => {
  return sameOrigin && request.destination === 'image'
}, new CacheFirst());

// Register the new route
registerRoute(imageRoute);

Utiliser plusieurs caches

Workbox vous permet de regrouper les réponses mises en cache dans des instances Cache distinctes à l'aide de l'option cacheName disponible dans les stratégies groupées.

Dans l'exemple suivant, les images utilisent une stratégie "obsolète pendant la revalidation", tandis que les éléments CSS et JavaScript utilisent une stratégie de retour au cache orientée réseau vers le cache. La route de chaque élément place les réponses dans des caches distincts, en ajoutant la propriété cacheName.

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst, StaleWhileRevalidate } from 'workbox-strategies';

// Handle images:
const imageRoute = new Route(({ request }) => {
  return request.destination === 'image'
}, new StaleWhileRevalidate({
  cacheName: 'images'
}));

// Handle scripts:
const scriptsRoute = new Route(({ request }) => {
  return request.destination === 'script';
}, new CacheFirst({
  cacheName: 'scripts'
}));

// Handle styles:
const stylesRoute = new Route(({ request }) => {
  return request.destination === 'style';
}, new CacheFirst({
  cacheName: 'styles'
}));

// Register routes
registerRoute(imageRoute);
registerRoute(scriptsRoute);
registerRoute(stylesRoute);
<ph type="x-smartling-placeholder">
</ph> Capture d&#39;écran d&#39;une liste d&#39;instances Cache dans l&#39;onglet &quot;Application&quot; des outils de développement de Chrome. Trois caches distincts sont affichés: l&#39;un nommé &quot;scripts&quot;, l&#39;autre &quot;styles&quot; et le dernier &quot;images&quot;.
Visionneuse de l'espace de stockage Cache dans le panneau "Application" des outils pour les développeurs Chrome. Les réponses pour différents types d'éléments sont stockées dans des caches distincts.

Définir un délai d'expiration pour les entrées de cache

Tenez compte des quotas de stockage lorsque vous gérez le ou les caches de service worker. ExpirationPlugin simplifie la maintenance du cache et est exposé par workbox-expiration. Pour l'utiliser, spécifiez-le dans la configuration d'une stratégie de mise en cache:

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';

// Evict image cache entries older thirty days:
const imageRoute = new Route(({ request }) => {
  return request.destination === 'image';
}, new CacheFirst({
  cacheName: 'images',
  plugins: [
    new ExpirationPlugin({
      maxAgeSeconds: 60 * 60 * 24 * 30,
    })
  ]
}));

// Evict the least-used script cache entries when
// the cache has more than 50 entries:
const scriptsRoute = new Route(({ request }) => {
  return request.destination === 'script';
}, new CacheFirst({
  cacheName: 'scripts',
  plugins: [
    new ExpirationPlugin({
      maxEntries: 50,
    })
  ]
}));

// Register routes
registerRoute(imageRoute);
registerRoute(scriptsRoute);

Respecter les quotas de stockage peut s'avérer compliqué. Il est recommandé de prendre en compte les utilisateurs susceptibles d'être soumis à une pression sur le stockage ou qui souhaitent tirer le meilleur parti de leur espace de stockage. Les paires ExpirationPlugin de la boîte de travail peuvent vous aider à atteindre cet objectif.

Remarques concernant les origines multiples

L'interaction entre votre service worker et vos assets multi-origines est très différente de celle des assets de même origine. La complexité du partage des ressources entre origines multiples (CORS, Cross-Origin Resource Sharing) concerne également la manière dont vous gérez les ressources multi-origines dans un service worker.

Réponses opaques

Lors d'une requête multi-origine en mode no-cors, la réponse peut être stockée dans le cache d'un service worker et même utilisée directement par le navigateur. Cependant, le corps de la réponse lui-même ne peut pas être lu via JavaScript. C'est ce que l'on appelle une réponse opaque.

Les réponses opaques sont une mesure de sécurité destinée à empêcher l'inspection d'un élément multi-origine. Vous pouvez toujours envoyer des requêtes pour des éléments multi-origines et même les mettre en cache, mais vous ne pouvez tout simplement pas lire le corps de la réponse ni même lire son code d'état.

N'oubliez pas d'activer le mode CORS

Même si vous chargez des éléments multi-origines qui définissent des en-têtes CORS permissifs qui vous permettent de lire les réponses, le corps de la réponse multi-origine peut rester opaque. Par exemple, le code HTML suivant déclenchera des requêtes no-cors qui donneront lieu à des réponses opaques, quels que soient les en-têtes CORS définis:

<link rel="stylesheet" href="https://example.com/path/to/style.css">
<img src="https://example.com/path/to/image.png">

Pour déclencher explicitement une requête cors qui générera une réponse non opaque, vous devez explicitement activer le mode CORS en ajoutant l'attribut crossorigin à votre code HTML:

<link crossorigin="anonymous" rel="stylesheet" href="https://example.com/path/to/style.css">
<img crossorigin="anonymous" src="https://example.com/path/to/image.png">

Ce point est important lorsque les routes de votre service worker mettent en cache les sous-ressources chargées au moment de l'exécution.

Il est possible que la boîte de travail ne mette pas en cache les réponses opaques

Par défaut, Workbox adopte une approche prudente de la mise en cache des réponses opaques. Comme il est impossible d'examiner le code de réponse à la recherche de réponses opaques, la mise en cache d'une réponse d'erreur peut entraîner une interruption persistante de l'expérience si une stratégie "cache first" ou "cache-only" est utilisée.

Si vous devez mettre en cache une réponse opaque dans Workbox, vous devez utiliser une stratégie axée sur le réseau ou une stratégie obsolète pendant la validation pour la gérer. Oui, cela signifie que l'élément sera toujours demandé au réseau à chaque fois, mais cela garantit que les réponses ayant échoué ne seront pas conservées et seront à terme remplacées par des réponses utilisables.

Si vous utilisez une autre stratégie de mise en cache et qu'une réponse opaque est renvoyée, Workbox vous avertit que la réponse n'a pas été mise en cache en mode de développement.

Forcer la mise en cache des réponses opaques

Si vous êtes absolument certain de vouloir mettre en cache une réponse opaque à l'aide d'une stratégie de type "cache first" ou "cache uniquement", vous pouvez forcer Workbox à le faire à l'aide du module workbox-cacheable-response:

import {Route, registerRoute} from 'workbox-routing';
import {NetworkFirst, StaleWhileRevalidate} from 'workbox-strategies';
import {CacheableResponsePlugin} from 'workbox-cacheable-response';

const cdnRoute = new Route(({url}) => {
  return url === 'https://cdn.google.com/example-script.min.js';
}, new CacheFirst({
  plugins: [
    new CacheableResponsePlugin({
      statuses: [0, 200]
    })
  ]
}))

registerRoute(cdnRoute);

Réponses opaques et API navigator.storage

Pour éviter les fuites d'informations entre les domaines, une marge intérieure importante est ajoutée à la taille d'une réponse opaque utilisée pour calculer les limites de quota de stockage. Cela affecte la manière dont l'API navigator.storage génère des rapports sur les quotas de stockage.

Cette marge intérieure varie selon le navigateur, mais pour Chrome, la taille minimale d'une réponse opaque mise en cache dans l'espace de stockage global utilisé est d'environ 7 mégaoctets. Gardez cela à l'esprit lorsque vous déterminez le nombre de réponses opaques que vous souhaitez mettre en cache, car vous pourriez facilement dépasser les quotas de stockage beaucoup plus tôt que prévu.