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 do desenvolvedor, em que a definição de um cabeçalho Cache-Control acidental no script do service worker pode levar a atualizações atrasadas.

Se você já desativou o armazenamento em cache HTTP para o script /service-worker.js, disponibilizando-o com Cache-Control: max-age=0, não verá 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 a 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.

Contexto

Sempre que você acessar uma nova página no escopo de um service worker, chamar 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 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 outro código que é executado no 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 por meio do cache HTTP, como a maioria das buscas. Isso significava que, se o script fosse 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 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.

Da versão 68 em diante, o cache HTTP será ignorado ao solicitar atualizações do script do service worker. Portanto, os aplicativos da Web atuais poderão ter um aumento na frequência de solicitações para esse script. As solicitações de importScripts ainda passarão 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 é usado 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 se há atualizações para o script /service-worker.js, mas será consultado ao buscar os 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 quaisquer scripts importados dentro do service worker, como path/to/import.js. Essa opção corresponde ao comportamento anterior no Chrome, em relação 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 se há 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() era recuperado apenas uma vez (verificando primeiro o cache HTTP ou a rede, dependendo da configuração de updateViaCache). Após essa recuperação inicial, ele seria armazenado internamente pelo navegador e nunca buscado novamente.

A única maneira de forçar um service worker já instalado a coletar 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 o fluxo de conteúdo do service worker de nível superior é acionado, o que atualiza o fluxo de conteúdo do service worker.

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, as verificações serão feitas ao mesmo tempo para determinar se o conteúdo de algum script importado mudou ou não. Dependendo dos cabeçalhos Cache-Control usados, essas verificações de script importadas poderão ser atendidas pelo cache HTTP se updateViaCache estiver definido como 'all' ou 'imports' (que é o valor padrão), ou as verificações poderão ser diretamente na rede se updateViaCache estiver definido como 'none'.

Se uma verificação de atualização de 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 o script /service-worker.js veiculando-o com Cache-Control: max-age=0 (ou um valor semelhante), não vai notar nenhuma mudança 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, talvez você comece a notar 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, precisará começar a definir explicitamente updateViaCache: 'all' ao registrar seu service worker.

Como pode haver uma grande quantidade de usuários em versões mais antigas do navegador, ainda é recomendável continuar configurando 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 o uso dos scripts importados do armazenamento em cache HTTP e adicionar updateViaCache: 'none' ao registro do service worker, se apropriado.

Como exibir scripts importados

A partir do Chrome 78, os desenvolvedores podem ver mais solicitações HTTP recebidas para recursos carregados por importScripts(), já que agora elas serão verificadas quanto a 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 use o comportamento padrão updateViaCache de 'imports'.

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

Leia mais

As leituras "The Service Worker Lifecycle" e "Cache Best Practices & max-age gochas", (ambos de Jake Archibald), são leituras recomendadas para todos os desenvolvedores que implantam algo na Web.