Quando utilizzi Workbox, potresti voler manipolare una richiesta e una risposta durante il recupero o la memorizzazione nella cache. I plug-in Workbox ti consentono di aggiungere comportamenti aggiuntivi al tuo worker di servizio con un minimo di boilerplate aggiuntivo. Possono essere pacchettizzati e riutilizzati nei tuoi progetti oppure rilasciati pubblicamente per consentirne l'utilizzo anche ad altri.
Workbox fornisce una serie di plug-in pronti all'uso e, se sei un tipo ingegnoso, 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:
BackgroundSyncPlugin
: se una richiesta di rete non va a buon fine, questo plug-in ti consente di aggiungerla a una coda di sincronizzazione in background per richiederla di nuovo al successivo evento di sincronizzazione.BroadcastUpdatePlugin
: consente di inviare un messaggio su un canale di trasmissione o tramitepostMessage()
ogni volta che una cache viene aggiornata.CacheableResponsePlugin
: memorizza nella cache solo le richieste che soddisfano criteri specifici.ExpirationPlugin
: gestisce il numero e la durata massima degli elementi in una cache.RangeRequestsPlugin
: rispondi alle richieste che includono un'intestazione della richiesta HTTPRange
.
I plug-in Workbox, che si tratti di uno dei plug-in elencati sopra o di 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 informazioni pertinenti sulla richiesta e/o sulla risposta corrente, fornendo al plug-in il contesto necessario per intervenire. Sono supportate le seguenti funzioni di callback:
cacheWillUpdate
: viene chiamato prima che venga utilizzato unResponse
per aggiornare una cache. In questo metodo, la risposta può essere modificata prima di essere aggiunta alla cache oppure puoi restituirenull
per evitare di aggiornare completamente la cache.cacheDidUpdate
: viene chiamato 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
: viene chiamato prima che una richiesta venga utilizzata come chiave della cache. Questo accade sia per le ricerche nella cache (quandomode
è'read'
) sia per le scritture nella cache (quandomode
è'write'
). Questo callback è utile se devi eseguire l'override o la normalizzazione degli URL prima di utilizzarli per accedere alle cache.cachedResponseWillBeUsed
: viene chiamato appena prima che venga utilizzata una risposta da una cache, il che ti consente di esaminarla. A questo punto, puoi restituire una risposta diversa o restituirenull
.requestWillFetch
: viene chiamato ogni volta che una richiesta sta per andare alla rete. È utile quando devi modificare ilRequest
poco prima che venga inviato 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 e non si attiva quando il browser dispone di una connessione di rete, ma riceve un errore (ad esempio404 Not Found
).fetchDidSucceed
: viene chiamato ogni volta che una richiesta di rete va a buon fine, indipendentemente dal codice di risposta HTTP.handlerWillStart
: viene chiamato prima dell'avvio dell'esecuzione della logica dell'handler, il che è utile se devi impostare lo stato iniziale dell'handler. 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
: viene chiamato prima che il metodohandle()
della strategia restituisca una risposta. È utile se devi modificare una risposta prima di restituirla aRouteHandler
o a un'altra logica personalizzata.handlerDidRespond
: viene richiamato dopo che il metodohandle()
della strategia restituisce una risposta. In questo caso può 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 durata estesa aggiunte all'evento dal richiamo della strategia si sono risolte. Questa operazione è utile se devi generare report su dati che devono attendere il completamento dell'handler per calcolare elementi come lo stato di hit della cache, la latenza della cache, la latenza della rete e altre informazioni utili.handlerDidError
: viene chiamato se il gestore non è in grado di fornire una risposta valida da qualsiasi origine. È il momento ottimale per fornire una sorta di risposta di riserva come alternativa al fallimento totale.
Tutti questi callback sono async
e pertanto richiedono che await
venga utilizzato ogni volta che un evento di cache o di recupero raggiunge il punto pertinente per il callback in questione.
Se un plug-in utilizzasse tutti i callback precedenti, il codice risultante sarebbe il seguente:
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 della cache. A volte non è presente un evento originale, pertanto il codice deve verificare se esiste prima di farvi riferimento.
A tutti i callback dei plug-in viene trasmesso anche un oggetto state
, che è univoco per un particolare plug-in e per la strategia da esso chiamata. Ciò significa che puoi scrivere plug-in in cui un callback può eseguire condizionatamente un'attività in base a ciò che ha fatto un altro callback nello 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 ritieni che venga 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:
cloudinary-workbox-plugin
, che riscrive dinamicamente le richieste di immagini ospitate su Cloudinary in base alla velocità di connessione attuale.workbox-plugin-firebase-auth
aiuta a gestireAuthorization: Bearer
per le richieste in uscita che richiedono l'autenticazione Firebase.
Potresti essere in grado di trovare altri plug-in Workbox forniti dalla community cercando nel repository di npm.
Infine, se hai creato un plug-in Workbox che vorresti condividere, aggiungi la parola chiave workbox-plugin
quando lo pubblichi. Se lo hai fatto, comunicacelo su Twitter @WorkboxJS.