Migrar do Workbox v4 para v5

Este guia se concentra nas mudanças interruptivas introduzidas na Workbox v5, com exemplos das mudanças que você precisa fazer ao fazer upgrade da Workbox v4.

Alterações importantes

Classes de plug-in renomeadas

Vários pacotes do Workbox v4 incluíam classes com o nome Plugin. Na v5, essas classes foram renomeadas para seguir o padrão de identificador de pacote + Plugin:

  • BackgroundSyncPlugin
  • BroadcastUpdatePlugin
  • CacheableResponsePlugin
  • ExpirationPlugin
  • RangeRequestsPlugin

Essa renomeação será aplicada se você estiver usando as classes por importações de módulo ou pelos namespaces workbox.*.

Ponto de substituição do manifesto de pré-cache padrão

Anteriormente, ao usar uma das ferramentas de build em "inject manifest" , o arquivo do service worker de origem foi verificado quanto à presença de precacheAndRoute([]), com a matriz vazia [] usada como um marcador de posição para o ponto em que o manifesto de pré-cache foi injetado.

No Workbox v5, a lógica de substituição mudou, e agora self.__WB_MANIFEST é usado por padrão como o ponto de injeção.

// v4:
precacheAndRoute([]);

// v5:
precacheAndRoute(self.__WB_MANIFEST);

Conforme descrito nesta discussão, acreditamos que essa mudança oferece uma experiência mais simples e, ao mesmo tempo, dá aos desenvolvedores mais controle sobre como o manifesto injetado é usado no código do service worker personalizado. Se necessário, você pode mudar essa string de substituição usando a opção de configuração injectionPoint.

Duas opções que anteriormente eram compatíveis com rotas de navegação, blacklist e whitelist, foram renomeadas como denylist e allowlist.

A workbox-routing já oferecia suporte a um método, registerNavigationRoute(), que, por baixo dos panos, fazia duas coisas:

  1. Detectado se um determinado evento fetch teve ou não mode de 'navigate'.
  2. Se sim, responda a essa solicitação usando o conteúdo de um URL fixado no código e armazenado em cache anteriormente, independentemente do URL para o qual a navegação é direcionada.

Esse é um padrão comum a ser usado ao implementar a arquitetura de shell do app.

A segunda etapa, gerar uma resposta lendo do cache, não está dentro das responsabilidades do workbox-routing. Em vez disso, consideramos que ela faz parte da workbox-precaching, usando um novo método, createHandlerBoundToURL(). Esse novo método pode trabalhar em conjunto com a classe NavigationRoute já existente no workbox-routing para realizar a mesma lógica.

Se você estiver usando a opção navigateFallback em um dos comandos "generate SW" da ferramenta de build, a mudança acontecerá automaticamente. Se você já tiver configurado as opções navigateFallbackBlacklist ou navigateFallbackWhitelist, mude para navigateFallbackDenylist ou navigateFallbackAllowlist, respectivamente.

Se você usa "inject manifest" ou apenas gravar o service worker e seu service worker da Workbox v4 chamar registerNavigationRoute() diretamente, será necessário fazer uma mudança no código para ter o comportamento equivalente.

// v4:
import {getCacheKeyForURL} from 'workbox-precaching';
import {registerNavigationRoute} from 'workbox-routing';

const appShellCacheKey = getCacheKeyForURL('/app-shell.html');
registerNavigationRoute(appShellCacheKey, {
  whitelist: [...],
  blacklist: [...],
});

// v5:
import {createHandlerBoundToURL} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';

const handler = createHandlerBoundToURL('/app-shell.html');
const navigationRoute = new NavigationRoute(handler, {
  allowlist: [...],
  denylist: [...],
});
registerRoute(navigationRoute);

Não é mais necessário chamar getCacheKeyForURL(), porque createHandlerBoundToURL() cuidará disso para você.

Remoção de makeRequest() de workbox-strategies

Chamar makeRequest() equivale a chamar handle() em uma das classes workbox-strategy. As diferenças entre os dois métodos eram tão pequenas que manter os dois não fazia sentido. Os desenvolvedores que chamaram makeRequest() vão poder passar a usar handle() sem fazer mais mudanças:

// v4:
const strategy = new StaleWhileRevalidate({...});
const response = await strategy.makeRequest({event, request});

// v5:
const strategy = new StaleWhileRevalidate({...});
const response = await strategy.handle({event, request});

Na v5, handle() trata request como um parâmetro obrigatório e não voltará a usar event.request. Transmita uma solicitação válida ao chamar handle().

workbox-broadcast-update sempre usa postMessage()

Na v4, a biblioteca workbox-broadcast-update usaria, por padrão, a API Broadcast Channel para enviar mensagens quando há suporte a ela e volta a usar postMessage() somente quando o canal de transmissão não é compatível.

Percebemos que ter que detectar duas possíveis fontes de mensagens recebidas tornou a escrita do código no lado do cliente muito complicada. Além disso, em alguns navegadores, as chamadas postMessage() do service worker enviadas para páginas clientes são automaticamente armazenadas em buffer até que um listener de eventos message seja configurado. Não há buffer com a API Broadcast Channel, e as mensagens transmitidas são descartadas se forem enviadas antes que uma página do cliente esteja pronta para recebê-las.

Por esses motivos, mudamos a workbox-broadcast-update para usar sempre a postMessage() na v5. As mensagens são enviadas uma por vez para todas as páginas do cliente no escopo do service worker atual.

Para acomodar esse novo comportamento, remova qualquer código que você tenha em páginas de cliente que criaram instâncias de BroadcastChannel e configure um listener de evento message em navigator.serviceWorker:

// v4:
const updatesChannel = new BroadcastChannel('api-updates');
updatesChannel.addEventListener('message', event => {
  const {cacheName, updatedUrl} = event.data.payload;
  // ... your code here ...
});

// v5:
// This listener should be added as early as possible in your page's lifespan
// to ensure that messages are properly buffered.
navigator.serviceWorker.addEventListener('message', event => {
  // Optional: ensure the message came from workbox-broadcast-update
  if (event.meta === 'workbox-broadcast-update') {
    const {cacheName, updatedUrl} = event.data.payload;
    // ... your code here ...
  }
});

Os usuários do workbox-window não precisam fazer nenhuma mudança, porque a lógica interna foi atualizada para detectar chamadas postMessage().

As ferramentas de build exigem o Node.js v8 ou mais recente

As versões do Node.js anteriores à v8 não são mais compatíveis com workbox-webpack-plugin, workbox-build ou workbox-cli. Se você estiver executando uma versão do Node.js anterior à 8, atualize o ambiente de execução para uma versão compatível.

workbox-webpack-plugin Requer o webpack v4 ou mais recente

Se você estiver usando workbox-webpack-plugin, atualize a configuração do webpack para usar pelo menos o webpack v4.

Reestruturação da opção de ferramenta de build

Vários parâmetros de configuração workbox-build, workbox-cli e workbox-webpack-plugin não têm mais suporte. Por exemplo, generateSW sempre vai criar um pacote de ambiente de execução do Workbox local para você, então a opção importWorkboxFrom não faz mais sentido.

Consulte a documentação da ferramenta relevante para ver as listas de opções compatíveis.

Remoção de generateSWString do build da caixa de trabalho.

O modo generateSWString foi removido do workbox-build. Esperamos que esse impacto seja mínimo, já que foi usado internamente pelo workbox-webpack-plugin.

Alterações opcionais

Como usar importações de módulo

Embora essa mudança seja a) opcional e b) tecnicamente possível com o uso do Workbox v4, a maior mudança prevista para a v5 é um modelo em que você cria seu próprio service worker em pacote importando os módulos do Workbox. Essa abordagem é uma alternativa a chamar importScripts('/path/to/workbox-sw.js') na parte superior do service worker e usar o Workbox pelo namespace workbox.*.

Se você estiver usando uma das ferramentas de build (workbox-webpack-plugin, workbox-build, workbox-cli) no modo "gerar SW", essa mudança vai acontecer automaticamente. Todas essas ferramentas vão gerar um pacote local e personalizado do Workbox runtime com o código necessário para implementar a lógica do service worker. Nesse cenário, não há mais dependência do workbox-sw ou da cópia CDN do Workbox. Dependendo do valor da configuração do inlineWorkboxRuntime, o ambiente de execução do Workbox será dividido em um arquivo separado, que será implantado com o service worker (quando definido como false, que é o padrão) ou incluído inline com a lógica do service worker (quando definido como true).

Se você estiver usando as ferramentas de build no modo "inject manifest" ou não estiver usando as ferramentas de build do Workbox, saiba mais sobre como criar seu próprio pacote de execução do Workbox no guia Como usar os bundlers (webpack/Rollup) com o Workbox.

A documentação e os exemplos da v5 foram escritos com base na sintaxe de importação de módulos, mas o namespace workbox.* vai continuar sendo compatível com a Workbox v5.

Como ler respostas pré-armazenadas em cache

Alguns desenvolvedores precisam ler as respostas pré-armazenadas em cache diretamente do cache, em vez de usá-las implicitamente com o método precacheAndRoute(). Um padrão comum na v4 é primeiro receber a chave de cache específica da versão atual de um recurso pré-armazenado em cache e, em seguida, transmitir essa chave com o nome do cache da pré-armazenagem para caches.match() para receber o Response.

Para simplificar esse processo, workbox-precaching na v5 é compatível com um novo método equivalente, matchPrecache():

// v4:
import {cacheNames} from 'workbox-core';
import {getCacheKeyForURL} from 'workbox-precaching';

const cachedResponse = await caches.match(
  getCacheKeyForURL(`/somethingPrecached`),
  {
    cacheName: cacheNames.precache,
  }
);

// v5:
import {matchPrecache} from 'workbox-precaching';

const cachedResponse = await matchPrecache(`/somethingPrecached`);

Adoção do TypeScript

Na v5, as bibliotecas de tempo de execução do Workbox são escritas em TypeScript. Continuaremos a publicar módulos e pacotes JavaScript transcompilados para acomodar desenvolvedores que não adotaram o TypeScript, mas se você estiver usando o TypeScript, poderá se beneficiar de informações precisas e sempre atualizadas diretamente do projeto Workbox.

Exemplo de migração

Este commit ilustra uma migração bastante complexa, com comentários inline. Ele usa o Rollup para incluir um ambiente de execução do Workbox personalizado no worker de serviço final em vez de carregar o ambiente de execução do CDN.

Embora não cubra todas as alterações interruptivas, veja o antes e o depois do upgrade de um arquivo de service worker da v4 para a v5, incluindo a mudança para o TypeScript.

Como receber ajuda

A maioria das migrações é simples. Se você encontrar problemas não abordados neste guia, abra um problema no GitHub.