Service Workers mais novos, por padrão

tl;dr

A partir do Chrome 68, as solicitações HTTP que verificam se há atualizações para o script do service worker não serão mais atendidas pelo cache HTTP por padrão. Isso resolve um problema comum com o desenvolvedor, em que a configuração de um cabeçalho Cache-Control inadvertida no script do service worker pode levar a atualizações atrasadas.

Se você já desativou o armazenamento em cache HTTP para seu script /service-worker.js veiculando-o com Cache-Control: max-age=0, não verá nenhuma alteração devido ao novo comportamento padrão.

Além disso, a partir do Chrome 78, a comparação byte a byte será aplicada aos scripts carregados em um service worker via importScripts(). Qualquer alteração feita em um script importado acionará o fluxo de atualização do service worker, assim como uma alteração no service worker de nível superior faria.

Contexto

Sempre que você navegar para uma nova página no escopo de um service worker, chame explicitamente registration.update() do JavaScript ou quando um service worker for "ativado" por um evento push ou sync, o navegador vai solicitar, em paralelo, o recurso JavaScript que foi originalmente transmitido à chamada navigator.serviceWorker.register() para procurar atualizações no script do service worker.

Para os fins deste artigo, vamos supor que o URL seja /service-worker.js e que ele contenha uma única chamada para importScripts(), que carrega o código adicional que é executado dentro do service worker:

// Inside our /service-worker.js file:
importScripts('path/to/import.js');

// Other top-level code goes here.

O que está mudando?

Antes do Chrome 68, a solicitação de atualização de /service-worker.js era feita pelo cache HTTP, como a maioria das buscas. Isso significa que, se o script foi enviado originalmente com Cache-Control: max-age=600, as atualizações nos próximos 600 segundos (10 minutos) não iriam para a rede. Portanto, o usuário pode não receber a versão mais atualizada do service worker. No entanto, se max-age for maior que 86.400 (24 horas), ele será tratado como se fosse 86.400, para evitar que os usuários fiquem presos a uma versão específica para sempre.

A partir da versão 68, o cache HTTP será ignorado quando você solicitar atualizações para o script do service worker. Portanto, os aplicativos da Web atuais poderão ter um aumento na frequência das solicitações para o script do service worker. As solicitações de importScripts ainda serão feitas pelo cache HTTP. No entanto, esse é apenas o padrão. Uma nova opção de registro, updateViaCache, que oferece controle sobre esse comportamento, está disponível.

updateViaCache

Agora, os desenvolvedores podem transmitir uma nova opção ao chamar navigator.serviceWorker.register(): o parâmetro updateViaCache. Ele usa um destes três valores: 'imports', 'all' ou 'none'.

Os valores determinam se e como o cache HTTP padrão do navegador entra em jogo ao fazer a solicitação HTTP para verificar se há recursos atualizados do service worker.

  • Quando definido como 'imports', o cache HTTP nunca será consultado durante a verificação de atualizações para o script /service-worker.js, mas será consultado ao buscar qualquer script importado (no nosso exemplo, path/to/import.js). Esse é o padrão e corresponde ao comportamento a partir do Chrome 68.

  • Quando definido como 'all', o cache HTTP será consultado ao fazer solicitações para o script /service-worker.js de nível superior, bem como para quaisquer scripts importados dentro do service worker, como path/to/import.js. Essa opção corresponde ao comportamento anterior no Chrome, anterior ao Chrome 68.

  • Quando definido como 'none', o cache HTTP não será consultado ao fazer solicitações para o /service-worker.js de nível superior ou para qualquer script importado, como o path/to/import.js hipotético.

Por exemplo, o código a seguir registrará um service worker e garantirá que o cache HTTP nunca seja consultado ao verificar atualizações para o script /service-worker.js ou para qualquer script referenciado por importScripts() dentro de /service-worker.js:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js', {
    updateViaCache: 'none',
    // Optionally, set 'scope' here, if needed.
  });
}

Verifica se há atualizações para scripts importados

Antes do Chrome 78, qualquer script de service worker carregado por importScripts() só era recuperado uma vez (verificando primeiro no cache HTTP ou pela rede, dependendo da configuração de updateViaCache). Após essa recuperação inicial, ela é armazenada internamente pelo navegador e nunca é buscada novamente.

A única maneira de forçar um service worker já instalado a captar alterações em um script importado era alterar o URL do script, geralmente adicionando um valor semver (por exemplo, importScripts('https://example.com/v1.1.0/index.js')) ou incluindo um hash do conteúdo (por exemplo, importScripts('https://example.com/index.abcd1234.js')). Um efeito colateral da alteração do URL importado é que a mudança de conteúdo do script do service worker de nível superior, que, por sua vez, aciona o fluxo de trabalho de serviço.

A partir do Chrome 78, sempre que uma verificação de atualização for realizada para um arquivo de service worker de nível superior, serão feitas verificações ao mesmo tempo para determinar se o conteúdo de algum script importado foi alterado. Dependendo dos cabeçalhos Cache-Control usados, essas verificações de script importados poderão ser realizadas pelo cache HTTP se updateViaCache estiver definido como 'all' ou 'imports' (que é o valor padrão), ou as verificações poderão ir diretamente para a rede se updateViaCache estiver definido como 'none'.

Se uma verificação de atualização para um script importado resultar em uma diferença byte por byte em comparação com o que foi armazenado anteriormente pelo service worker, isso acionará o fluxo completo de atualização do service worker, mesmo que o arquivo do service worker de nível superior permaneça o mesmo.

O comportamento do Chrome 78 corresponde ao que o Firefox implementou há vários anos, no Firefox 56. O Safari também já implementa esse comportamento.

O que os desenvolvedores precisam fazer?

Se você desativou o armazenamento em cache HTTP para seu script /service-worker.js exibindo-o com Cache-Control: max-age=0 (ou um valor semelhante), não verá nenhuma alteração devido ao novo comportamento padrão.

Se você exibir o script /service-worker.js com o armazenamento em cache HTTP ativado, seja intencionalmente ou porque é apenas o padrão do seu ambiente de hospedagem, poderá começar a ver um aumento de solicitações HTTP adicionais para /service-worker.js feitas no seu servidor. Essas são solicitações que costumavam ser atendidas pelo cache HTTP. Se você quiser continuar permitindo que o valor do cabeçalho Cache-Control influencie a atualização do /service-worker.js, comece a definir explicitamente updateViaCache: 'all' ao registrar seu service worker.

Como pode haver uma cauda longa de usuários em versões de navegadores mais antigas, ainda é uma boa ideia continuar definindo o cabeçalho HTTP Cache-Control: max-age=0 nos scripts do service worker, mesmo que os navegadores mais recentes possam ignorá-los.

Os desenvolvedores podem usar essa oportunidade para decidir se querem desativar explicitamente os scripts importados do armazenamento em cache HTTP agora e adicionar updateViaCache: 'none' ao registro do service worker.

Exibição de scripts importados

A partir do Chrome 78, os desenvolvedores podem ver mais solicitações HTTP recebidas para recursos carregados via importScripts(), já que serão verificadas se há atualizações.

Se você quiser evitar esse tráfego HTTP extra, defina cabeçalhos Cache-Control de longa duração ao exibir scripts que incluem semver ou hashes nos URLs e confie no comportamento updateViaCache padrão de 'imports'.

Como alternativa, se você quiser verificar se há atualizações frequentes nos scripts importados, veicule-os com Cache-Control: max-age=0 ou use updateViaCache: 'none'.

Leia mais

As leituras The Service Worker Lifecycle e Práticas recomendadas em cache e armadilhas de max-age, de Jake Archibald, são recomendadas para todos os desenvolvedores que implantam qualquer coisa na Web.