Ao usar o Workbox, talvez você queira manipular uma solicitação e uma resposta enquanto são buscadas ou armazenadas em cache. Os plug-ins do Workbox permitem adicionar comportamentos adicionais ao service worker com um mínimo de boilerplate extra. Eles podem ser empacotados e reutilizados em seus próprios projetos ou lançados publicamente para outras pessoas usarem.
O Workbox oferece vários plug-ins prontos para uso. Se você for do tipo criativo, poderá criar plug-ins personalizados de acordo com os requisitos do seu aplicativo.
Plug-ins do Workbox disponíveis
O Workbox oferece os seguintes plug-ins oficiais para uso no seu worker de serviço:
BackgroundSyncPlugin
: se uma solicitação de rede falhar, o plug-in permite que você a adicione a uma fila de sincronização em segundo plano para ser solicitada novamente quando o próximo evento de sincronização for acionado.BroadcastUpdatePlugin
: permite enviar uma mensagem em um canal de transmissão ou porpostMessage()
sempre que um cache for atualizado.CacheableResponsePlugin
: apenas solicitações de cache que atendem a critérios específicos.ExpirationPlugin
: gerencia o número e a idade máxima dos itens em um cache.RangeRequestsPlugin
: responde a solicitações que incluem um cabeçalho de solicitação HTTPRange
.
Os plug-ins da caixa de trabalho, um dos listados acima ou um personalizado, são usados com uma estratégia do Workbox ao adicionar uma instância do plug-in à propriedade plugins
da estratégia:
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étodos para plug-ins personalizados
Um plug-in do Workbox precisa implementar uma ou mais funções de callback. Quando você adiciona um plug-in a uma estratégia, as funções de callback são executadas automaticamente no momento certo. A estratégia transmite informações relevantes para a função de callback sobre a solicitação e/ou resposta atual, ao seu plug-in o contexto necessário para agir. As seguintes funções de callback são compatíveis:
cacheWillUpdate
: é chamada antes que umResponse
seja usado para atualizar um cache. Nesse método, a resposta pode ser modificada antes de ser adicionada ao cache ou é possível retornarnull
para evitar a atualização completa do cache.cacheDidUpdate
: chamado quando uma nova entrada é adicionada a um cache ou se uma entrada atual é atualizada. Os plug-ins que usam esse método podem ser úteis quando você quer realizar uma ação após uma atualização de cache.cacheKeyWillBeUsed
: chamado antes que uma solicitação seja usada como uma chave de cache. Isso ocorre para pesquisas de cache (quandomode
é'read'
) e gravações de cache (quandomode
é'write'
). Esse callback é útil se você precisar substituir ou normalizar URLs antes de usá-los para acessar caches.cachedResponseWillBeUsed
: é chamado pouco antes de uma resposta de um cache ser usada, o que permite examinar essa resposta. Nesse momento, você pode retornar uma resposta diferente ou retornarnull
.requestWillFetch
: é chamado sempre que uma solicitação está prestes a ser enviada à rede. Útil quando você precisa alterar oRequest
pouco antes de ele ir para a rede.fetchDidFail
: é chamado quando uma solicitação de rede falha, provavelmente devido à ausência de conectividade de rede, e não é acionado quando o navegador tem uma conexão de rede, mas recebe um erro (por exemplo,404 Not Found
).fetchDidSucceed
: é chamada sempre que uma solicitação de rede é bem-sucedida, independentemente do código de resposta HTTP.handlerWillStart
: é chamado antes que qualquer lógica de gerenciador comece a ser executada. Isso é útil se você precisar definir o estado inicial do gerenciador. Por exemplo, se você quiser saber quanto tempo o gerenciador levou para gerar uma resposta, anote o horário de início nesse callback.handlerWillRespond
: chamado antes do métodohandle()
da estratégia retornar uma resposta, o que será útil se você precisar modificar uma resposta antes de retorná-la a umaRouteHandler
ou outra lógica personalizada.handlerDidRespond
: é chamado depois que o métodohandle()
da estratégia retorna uma resposta. É quando pode ser útil registrar todos os detalhes da resposta final (por exemplo, após alterações feitas por outros plug-ins).handlerDidComplete
: é chamado depois que todas as promessas de tempo de vida estendidas adicionadas ao evento da invocação da estratégia foram resolvidas. Isso é útil se você precisar gerar relatórios sobre dados que precisam esperar até que o gerenciador seja concluído para calcular coisas como status de ocorrência em cache, latência de cache, latência de rede e outras informações úteis.handlerDidError
: é chamado se o gerenciador não puder fornecer uma resposta válida de qualquer fonte. Esse é o momento ideal para fornecer algum tipo de resposta alternativa como alternativa à falha total.
Todos esses callbacks são async
e, portanto, exigem que await
seja usado sempre que um evento de cache ou de busca atinja o ponto relevante para o callback em questão.
Se um plug-in usasse todos os callbacks acima, o código resultante seria este:
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;
},
};
O objeto event
disponível nos callbacks listados acima é o evento original que acionou a ação de busca ou armazenamento em cache. Às vezes, não há um evento original. Por isso, seu código precisa verificar se ele existe antes de fazer referência a ele.
Todos os callbacks de plug-in também recebem um objeto state
, que é exclusivo para um plug-in específico e a estratégia que ele invoca. Isso significa que você pode escrever plug-ins em que um callback pode executar condicionalmente uma tarefa com base no que outro callback no mesmo plug-in fez. Por exemplo, calcule a diferença entre executar requestWillFetch()
e fetchDidSucceed()
ou fetchDidFail()
.
Plug-ins de terceiros
Se você desenvolver um plug-in e achar que ele é útil fora do seu projeto, recomendamos publicá-lo como um módulo. Confira abaixo uma pequena lista de plug-ins do Workbox fornecidos pela comunidade:
cloudinary-workbox-plugin
, que reescreve dinamicamente solicitações de imagens hospedadas no Cloudinary com base na velocidade de conexão atual.- O
workbox-plugin-firebase-auth
ajuda a gerenciar oAuthorization: Bearer
para solicitações de saída que precisam de autenticação do Firebase.
Você pode encontrar mais plug-ins do Workbox fornecidos pela comunidade pesquisando no repositório do npm.
Por fim, se você criou um plug-in do Workbox e quer compartilhar, adicione a palavra-chave workbox-plugin
ao publicá-lo. Se você tiver, entre em contato pelo Twitter @WorkboxJS.