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 code répétitif minimal. Vous pouvez les empaqueter et les réutiliser dans vos propres projets, ou les publier pour que d'autres puissent également les utiliser.
Workbox propose un certain nombre de plug-ins prêts à l'emploi. Si vous êtes du genre à être débrouillard, 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:
BackgroundSyncPlugin
: si une requête réseau échoue, ce plug-in vous permet de l'ajouter à une file d'attente de synchronisation en arrière-plan pour qu'elle soit à nouveau demandée lorsque le prochain événement de synchronisation est déclenché.BroadcastUpdatePlugin
: permet d'envoyer un message sur un canal de diffusion ou viapostMessage()
chaque fois qu'un cache est mis à jour.CacheableResponsePlugin
: ne met en cache que les requêtes qui répondent à des critères spécifiques.ExpirationPlugin
: gère le nombre et l'âge maximal des éléments dans un cache.RangeRequestsPlugin
: répond aux requêtes qui incluent un en-tête de requête HTTPRange
.
Les plug-ins Workbox, qu'il s'agisse de l'un des plug-ins répertoriés ci-dessus ou d'un plug-in personnalisé, 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 pour les 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 en cours, fournissant à votre plug-in le contexte dont il a besoin pour prendre des mesures. Les fonctions de rappel suivantes sont prises en charge:
cacheWillUpdate
: appelé avant qu'unResponse
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 renvoyernull
pour éviter de mettre à jour entièrement le cache.cacheDidUpdate
: appelé lorsqu'une nouvelle entrée est ajoutée à un cache ou qu'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 (lorsquemode
est défini sur'read'
) et pour les écritures en cache (lorsquemode
est'write'
). Ce rappel est utile si vous devez remplacer ou normaliser les URL avant de les utiliser pour accéder aux caches.cachedResponseWillBeUsed
: cette méthode est appelée juste avant qu'une réponse d'un cache ne soit utilisée, ce qui vous permet de l'examiner. À ce stade, vous pouvez renvoyer une autre réponse ounull
.requestWillFetch
: appelé chaque fois qu'une requête est sur le point d'être envoyée au réseau. Utile lorsque vous devez modifier leRequest
juste avant qu'il ne soit envoyé au réseau.fetchDidFail
: appelé lorsqu'une requête réseau échoue, probablement en raison d'une absence de connectivité réseau. Il 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 à générer une réponse, vous pouvez noter l'heure de début dans ce rappel.handlerWillRespond
: appelé avant que la méthodehandle()
de la stratégie ne renvoie une réponse. Cela est utile si vous devez modifier une réponse avant de la renvoyer à unRouteHandler
ou à une autre logique personnalisée.handlerDidRespond
: appelé après que la méthodehandle()
de la stratégie a renvoyé une réponse. C'est là qu'il peut être utile d'enregistrer les détails de la réponse finale (par exemple, après les modifications apportées par d'autres plug-ins).handlerDidComplete
: appelé une fois que toutes les promesses d'extension de la durée de vie ajoutées à l'événement à partir de l'appel de la stratégie sont réglées. Cela est utile si vous devez générer un rapport sur des données qui doivent attendre la fin du gestionnaire afin de calculer des éléments tels que l'état de succès de 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 à partir de n'importe quelle source. C'est le moment idéal pour fournir une réponse de remplacement à la place de l'échec pur et simple.
Tous ces rappels sont des async
et nécessitent donc d'utiliser await
chaque fois qu'un événement de cache ou de récupération atteint le point pertinent pour le rappel concerné.
Si un plug-in utilisait tous les rappels ci-dessus, le code obtenu serait 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 listés ci-dessus est l'événement d'origine qui a déclenché l'action de récupération ou de mise en cache. Parfois, il n'y aura pas un é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
, qui est 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 ce qu'un autre rappel du même plug-in a fait (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 peut être utilisé en dehors de votre projet, nous vous encourageons à le publier en tant que module. Vous trouverez ci-dessous une courte liste de plug-ins Workbox fournis par la communauté:
cloudinary-workbox-plugin
, qui réécrit dynamiquement les requêtes d'images hébergées par Cloudinary en fonction de la vitesse de connexion actuelle.workbox-plugin-firebase-auth
permet de gérer lesAuthorization: Bearer
pour les requêtes sortantes nécessitant Firebase Authentication.
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
lorsque vous le publiez. Si c'est le cas, dites-le-nous sur Twitter (@WorkboxJS).