Service Workers mais novos, por padrão

Texto longo, leia o resumo

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

Se você já desativou o armazenamento em cache HTTP do script /service-worker.js com Cache-Control: max-age=0, não vai notar nenhuma mudança devido ao novo comportamento padrão.

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

Contexto

Sempre que você navega para uma nova página que está no escopo de um service worker, chame explicitamente registration.update() do JavaScript ou quando um service worker é "ativado" por um evento push ou sync. O navegador vai, em paralelo, solicitar o recurso JavaScript que foi originalmente transmitido para a 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 um código adicional executado dentro do worker de serviço:

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

// Other top-level code goes here.

O que muda?

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

A partir da versão 68, o cache HTTP será ignorado ao solicitar atualizações do script do service worker. Portanto, os aplicativos da Web atuais podem apresentar um aumento na frequência de solicitações do script do service worker. As solicitações de importScripts ainda vão passar pelo cache HTTP. Mas esse é apenas o padrão. Uma nova opção de registro, updateViaCache, está disponível e oferece controle sobre esse comportamento.

updateViaCache

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

Os valores determinam se e como o cache HTTP padrão do navegador entra em ação 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 ao verificar atualizações do script /service-worker.js, mas será consultado ao buscar scripts importados (path/to/import.js, no nosso exemplo). 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 todos os scripts importados no worker do serviço, 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 scripts importados, como o path/to/import.js hipotético.

Por exemplo, o código a seguir vai registrar um service worker e garantir que o cache HTTP nunca seja consultado ao verificar atualizações no script /service-worker.js ou em 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 nos scripts importados

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

A única maneira de forçar um service worker já instalado a detectar mudanças em um script importado era mudar 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 mudança do URL importado é que o conteúdo do script do service worker de nível superior muda, o que, por sua vez, aciona o fluxo de atualização do service worker.

A partir do Chrome 78, sempre que uma verificação de atualização for realizada para um arquivo de worker de serviço de nível superior, as verificações serão feitas ao mesmo tempo para determinar se o conteúdo de todos os scripts importados mudou ou não. Dependendo dos cabeçalhos Cache-Control usados, essas verificações de script importadas podem ser atendidas pelo cache HTTP se updateViaCache estiver definido como 'all' ou 'imports' (que é o valor padrão), ou podem ser enviadas diretamente à rede se updateViaCache estiver definido como 'none'.

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

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

O que os desenvolvedores precisam fazer?

Se você tiver desativado o armazenamento em cache HTTP do script /service-worker.js usando Cache-Control: max-age=0 (ou um valor semelhante), não vai notar nenhuma mudança devido ao novo comportamento padrão.

Se você enviar o script /service-worker.js com o armazenamento em cache HTTP ativado, intencionalmente ou porque é o padrão do seu ambiente de hospedagem, pode começar a notar um aumento nas solicitações HTTP adicionais de /service-worker.js feitas no seu servidor, 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, será necessário definir explicitamente updateViaCache: 'all' ao registrar o service worker.

Como pode haver um grande número de usuários em versões mais antigas do navegador, ainda é uma boa ideia continuar definindo o cabeçalho HTTP Cache-Control: max-age=0 em scripts de worker de serviço, mesmo que navegadores mais recentes possam ignorá-los.

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

Como exibir scripts importados

A partir do Chrome 78, os desenvolvedores podem notar mais solicitações HTTP recebidas para recursos carregados por importScripts(), já que agora elas serão verificadas para atualizações.

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

Como alternativa, se você quiser que seus scripts importados sejam verificados para atualizações frequentes, veicule-os com Cache-Control: max-age=0 ou use updateViaCache: 'none'.

Leitura adicional

Os artigos O ciclo de vida do service worker e Práticas recomendadas de armazenamento em cache e armadilhas de idade máxima, ambos de Jake Archibald, são leituras recomendadas para todos os desenvolvedores que implantam algo na Web.