Utilizzo dei plug-in

Quando utilizzi Workbox, potresti voler manipolare una richiesta e una risposta mentre vengono recuperate o memorizzate nella cache. I plug-in Workbox ti consentono di aggiungere ulteriori comportamenti al service worker con un boilerplate minimo in più. Possono essere confezionati e riutilizzati nei tuoi progetti o resi disponibili pubblicamente per essere utilizzati anche da altri.

Workbox mette a disposizione una serie di plug-in pronti all'uso e, se preferisci, puoi scrivere plug-in personalizzati in base ai requisiti della tua applicazione.

Plug-in Workbox disponibili

Workbox offre i seguenti plug-in ufficiali da utilizzare nel service worker:

I plug-in Workbox, che si tratti di uno dei plug-in elencati sopra o un plug-in personalizzato, vengono utilizzati con una strategia Workbox, aggiungendo un'istanza del plug-in alla proprietà plugins della strategia:

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
      }),
    ],
  })
);

Metodi per i plug-in personalizzati

Un plug-in Workbox deve implementare una o più funzioni di callback. Quando aggiungi un plug-in a una strategia, le funzioni di callback vengono eseguite automaticamente al momento giusto. Strategy passa alla funzione di callback le informazioni pertinenti sulla richiesta e/o risposta corrente, fornendo al plug-in il contesto necessario per agire. Sono supportate le seguenti funzioni di callback:

  • cacheWillUpdate: richiamato prima di un Response, che viene utilizzato per aggiornare una cache. Con questo metodo, la risposta può essere modificata prima di essere aggiunta alla cache oppure puoi restituire null per evitare di aggiornare completamente la cache.
  • cacheDidUpdate: viene richiamato quando viene aggiunta una nuova voce a una cache o se viene aggiornata una voce esistente. I plug-in che utilizzano questo metodo possono essere utili quando vuoi eseguire un'azione dopo un aggiornamento della cache.
  • cacheKeyWillBeUsed: richiamato prima di una richiesta, che viene utilizzata come chiave cache. Questo si verifica sia per le ricerche nella cache (quando mode è 'read') sia per le scritture nella cache (quando mode è 'write'). Questo callback è utile se devi sostituire o normalizzare gli URL prima di utilizzarli per accedere alle cache.
  • cachedResponseWillBeUsed: viene richiamata appena prima dell'utilizzo di una risposta da una cache, che consente di esaminare la risposta. A questo punto, puoi restituire una risposta diversa o null.
  • requestWillFetch: viene chiamato ogni volta che una richiesta sta per essere inviata alla rete. Utile quando devi cambiare Request appena prima che vada alla rete.
  • fetchDidFail: viene chiamato quando una richiesta di rete non va a buon fine, molto probabilmente a causa dell'assenza di connettività di rete. Non si attiva quando il browser dispone di una connessione di rete, ma riceve un errore (ad esempio, 404 Not Found).
  • fetchDidSucceed: viene chiamato ogni volta che una richiesta di rete ha esito positivo, indipendentemente dal codice di risposta HTTP.
  • handlerWillStart: chiamato prima dell'avvio di qualsiasi logica del gestore, utile se devi impostare lo stato iniziale del gestore. Ad esempio, se vuoi sapere quanto tempo ha impiegato il gestore per generare una risposta, puoi prendere nota dell'ora di inizio in questo callback.
  • handlerWillRespond: richiamato prima che il metodo handle() della strategia restituisca una risposta, utile se devi modificare una risposta prima di restituirla a RouteHandler o a un'altra logica personalizzata.
  • handlerDidRespond: richiamato dopo che il metodo handle() della strategia restituisce una risposta. Questo è il momento in cui potrebbe essere utile registrare i dettagli finali della risposta (ad esempio, dopo le modifiche apportate da altri plug-in).
  • handlerDidComplete: richiamato dopo che tutte le promesse di estensione della durata di vita aggiunte all'evento dalla chiamata della strategia sono state risolte. Ciò è utile se devi creare un report sui dati che devono attendere il completamento del gestore per calcolare elementi come lo stato di hit della cache, la latenza della cache, la latenza di rete e altre informazioni utili.
  • handlerDidError: viene chiamato se il gestore non può fornire una risposta valida da un'origine qualsiasi, che è il momento ottimale per fornire una sorta di risposta di riserva come alternativa al fallback.

Tutti questi callback sono async, pertanto sarà necessario utilizzare await ogni volta che un evento di cache o di recupero raggiunge il punto pertinente per il callback interessato.

Se un plug-in utilizza tutti i callback precedenti, il codice risultante sarebbe:

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'oggetto event disponibile nei callback elencati sopra è l'evento originale che ha attivato l'azione di recupero o cache. A volte non ci sarà un evento originale, quindi il tuo codice dovrebbe controllare se esiste prima di fare riferimento a esso.

Tutte le richiamate dei plug-in vengono trasmesse anche un oggetto state, univoco per un determinato plug-in e la strategia che richiama. Ciò significa che puoi scrivere plug-in in cui un callback può eseguire un'attività in modo condizionale a seconda dell'azione eseguita da un altro callback dello stesso plug-in (ad esempio, calcolare la differenza tra l'esecuzione di requestWillFetch() e fetchDidSucceed() o fetchDidFail()).

Plug-in di terze parti

Se sviluppi un plug-in e pensi che possa essere utilizzato al di fuori del tuo progetto, ti invitiamo a pubblicarlo come modulo. Di seguito è riportato un breve elenco di plug-in Workbox forniti dalla community:

Potresti riuscire a trovare altri plug-in Workbox forniti dalla community eseguendo una ricerca nel repository di npm.

Infine, se hai creato un plug-in Workbox che vuoi condividere, aggiungi la parola chiave workbox-plugin quando la pubblichi. In questo caso, faccelo sapere su Twitter @WorkboxJS.