Utiliser des plug-ins

Lorsque vous utilisez Workbox, vous pouvez manipuler une requête et une réponse pendant leur récupération ou leur mise en cache. Les plug-ins Workbox vous permettent d'ajouter des comportements supplémentaires à votre service worker avec un minimum de code récurrent. Elles peuvent être empaquetées et réutilisées dans vos propres projets, ou publiées publiquement pour que d'autres puissent également les utiliser.

Workbox nous fournit un certain nombre de plug-ins prêts à l'emploi. Si vous avez l'esprit tranquille, vous pouvez écrire des plug-ins personnalisés adaptés aux exigences de votre application.

Plug-ins Workbox disponibles

Workbox propose les plug-ins officiels suivants à utiliser dans votre service worker:

Que ce soit l'un des plug-ins listés ci-dessus ou un plug-in personnalisé, les plug-ins Workbox sont utilisés avec une stratégie Workbox en ajoutant une instance du plug-in à la propriété plugins de la stratégie:

import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
import {ExpirationPlugin} from 'workbox-expiration';

registerRoute(
  ({request}) => request.destination === 'image',
  new CacheFirst({
    cacheName: 'images',
    plugins: [
      new ExpirationPlugin({
        maxEntries: 60,
        maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
      }),
    ],
  })
);

Méthodes de plug-ins personnalisés

Un plug-in Workbox doit implémenter une ou plusieurs fonctions de rappel. Lorsque vous ajoutez un plug-in à une stratégie, les fonctions de rappel sont automatiquement exécutées au bon moment. La stratégie transmet à votre fonction de rappel des informations pertinentes sur la requête et/ou la réponse actuelles, ce qui donne au plug-in le contexte nécessaire pour agir. Les fonctions de rappel suivantes sont compatibles:

  • cacheWillUpdate: appelé avant qu'un Response ne soit utilisé pour mettre à jour un cache. Avec cette méthode, la réponse peut être modifiée avant d'être ajoutée au cache, ou vous pouvez renvoyer null pour éviter de mettre à jour complètement le cache.
  • cacheDidUpdate: appelé lorsqu'une nouvelle entrée est ajoutée au cache ou si une entrée existante est mise à jour. Les plug-ins qui utilisent cette méthode peuvent être utiles lorsque vous souhaitez effectuer une action après une mise à jour du cache.
  • cacheKeyWillBeUsed: appelé avant qu'une requête ne soit utilisée comme clé de cache. Cela se produit à la fois pour les recherches dans le cache (lorsque mode est défini sur 'read') et pour les écritures dans le cache (lorsque mode est défini sur 'write'). Ce rappel est pratique si vous devez remplacer ou normaliser des URL avant de les utiliser pour accéder aux caches.
  • cachedResponseWillBeUsed: cette méthode est appelée juste avant l'utilisation d'une réponse du cache, ce qui vous permet d'examiner cette réponse. À ce stade, vous pouvez renvoyer une réponse différente ou renvoyer null.
  • requestWillFetch: appelé chaque fois qu'une requête est sur le point d'être transmise au réseau. Cette approche est utile lorsque vous devez modifier le Request juste avant qu'il ne passe sur le réseau.
  • fetchDidFail: appelé lorsqu'une requête réseau échoue, très probablement en raison de l'absence de connectivité réseau. Ne se déclenche pas lorsque le navigateur dispose d'une connexion réseau, mais reçoit une erreur (par exemple, 404 Not Found).
  • fetchDidSucceed: appelé chaque fois qu'une requête réseau aboutit, quel que soit le code de réponse HTTP.
  • handlerWillStart: appelé avant le début de l'exécution de toute logique de gestionnaire, ce qui est utile si vous devez définir l'état initial du gestionnaire. Par exemple, si vous souhaitez savoir combien de temps le gestionnaire a mis pour générer une réponse, vous pouvez noter l'heure de début de ce rappel.
  • handlerWillRespond: appelé avant que la méthode handle() de la stratégie renvoie une réponse, ce qui est utile si vous devez modifier une réponse avant de la renvoyer à un RouteHandler ou à une autre logique personnalisée.
  • handlerDidRespond: appelé lorsque la méthode handle() de la stratégie a renvoyé une réponse. C'est à ce moment-là qu'il peut être utile d'enregistrer les détails de la réponse finale (par exemple, après des modifications apportées par d'autres plug-ins).
  • handlerDidComplete: appelé une fois que toutes les propositions d'extension de durée de vie ajoutées à l'événement depuis l'appel de la stratégie ont été réglées. Ceci est utile si vous devez générer un rapport sur des données qui doivent attendre la fin de l'exécution du gestionnaire pour calculer des éléments tels que l'état de succès du cache, la latence du cache, la latence du réseau et d'autres informations utiles.
  • handlerDidError: appelé si le gestionnaire ne peut pas fournir de réponse valide depuis n'importe quelle source, ce qui est le moment idéal pour fournir une sorte de réponse de remplacement comme alternative à l'échec total.

Tous ces rappels sont async. Par conséquent, await doit être utilisé chaque fois qu'un événement de cache ou d'extraction atteint le point pertinent pour le rappel concerné.

Si un plug-in a utilisé tous les rappels ci-dessus, le code obtenu est le suivant:

const myPlugin = {
  cacheWillUpdate: async ({request, response, event, state}) => {
    // Return `response`, a different `Response` object, or `null`.
    return response;
  },
  cacheDidUpdate: async ({
    cacheName,
    request,
    oldResponse,
    newResponse,
    event,
    state,
  }) => {
    // No return expected
    // Note: `newResponse.bodyUsed` is `true` when this is called,
    // meaning the body has already been read. If you need access to
    // the body of the fresh response, use a technique like:
    // const freshResponse = await caches.match(request, {cacheName});
  },
  cacheKeyWillBeUsed: async ({request, mode, params, event, state}) => {
    // `request` is the `Request` object that would otherwise be used as the cache key.
    // `mode` is either 'read' or 'write'.
    // Return either a string, or a `Request` whose `url` property will be used as the cache key.
    // Returning the original `request` will make this a no-op.
    return request;
  },
  cachedResponseWillBeUsed: async ({
    cacheName,
    request,
    matchOptions,
    cachedResponse,
    event,
    state,
  }) => {
    // Return `cachedResponse`, a different `Response` object, or null.
    return cachedResponse;
  },
  requestWillFetch: async ({request, event, state}) => {
    // Return `request` or a different `Request` object.
    return request;
  },
  fetchDidFail: async ({originalRequest, request, error, event, state}) => {
    // No return expected.
    // Note: `originalRequest` is the browser's request, `request` is the
    // request after being passed through plugins with
    // `requestWillFetch` callbacks, and `error` is the exception that caused
    // the underlying `fetch()` to fail.
  },
  fetchDidSucceed: async ({request, response, event, state}) => {
    // Return `response` to use the network response as-is,
    // or alternatively create and return a new `Response` object.
    return response;
  },
  handlerWillStart: async ({request, event, state}) => {
    // No return expected.
    // Can set initial handler state here.
  },
  handlerWillRespond: async ({request, response, event, state}) => {
    // Return `response` or a different `Response` object.
    return response;
  },
  handlerDidRespond: async ({request, response, event, state}) => {
    // No return expected.
    // Can record final response details here.
  },
  handlerDidComplete: async ({request, response, error, event, state}) => {
    // No return expected.
    // Can report any data here.
  },
  handlerDidError: async ({request, event, error, state}) => {
    // Return a `Response` to use as a fallback, or `null`.
    return fallbackResponse;
  },
};

L'objet event disponible dans les rappels répertoriés ci-dessus est l'événement d'origine qui a déclenché l'action d'extraction ou de mise en cache. Il peut arriver qu'il n'y ait pas d'événement d'origine. Votre code doit donc vérifier s'il existe avant de le référencer.

Tous les rappels de plug-in reçoivent également un objet state, propre à un plug-in particulier et à la stratégie qu'il appelle. Cela signifie que vous pouvez écrire des plug-ins dans lesquels un rappel peut effectuer une tâche de manière conditionnelle en fonction de l'action d'un autre rappel du même plug-in (par exemple, calculer la différence entre l'exécution de requestWillFetch() et de fetchDidSucceed() ou fetchDidFail()).

Plug-ins tiers

Si vous développez un plug-in et que vous pensez qu'il est utilisé en dehors de votre projet, nous vous encourageons à le publier en tant que module. Voici une courte liste des plug-ins Workbox fournis par la communauté:

Vous pouvez peut-être trouver d'autres plug-ins Workbox fournis par la communauté en effectuant une recherche dans le dépôt npm.

Enfin, si vous avez créé un plug-in Workbox que vous souhaitez partager, ajoutez le mot clé workbox-plugin lors de la publication. Si c'est le cas, dites-le-nous sur Twitter (@WorkboxJS).