1

Service worker para um app 100% no navegador: as 4 regras de cache que eu usaria de novo

Fiz um app web que funciona sem backend e continua abrindo offline depois da primeira visita. Os dados ficam no próprio navegador (IndexedDB para os documentos, localStorage para preferências pequenas). O que deu mais trabalho não foi o app, foi o service worker. Ficaram quatro regras:

1. Asset versionado = cache first, sem medo.
Todo JS/CSS vai com ?v=<versão>. Se a URL muda a cada deploy, o arquivo em cache nunca fica velho, então pode servir direto do cache.

2. A página (navigate) = network first, cache como reserva.
O HTML não tem versão na URL. Se servir do cache primeiro, o usuário fica preso numa versão antiga. Então: tenta a rede, guarda a cópia boa, e só cai no cache quando está offline. Cada página fica salva com a própria URL; se não tiver cópia, cai na página principal do app.

3. Dado vivo nunca entra no cache.
Endpoints .php e um rates.json (câmbio) passam direto, sem respondWith. Servir câmbio de três semanas atrás como se fosse de hoje é pior do que não mostrar nada.

4. O nome do cache leva a versão, e o activate apaga os antigos.
caches.keys() → filtra pelo prefixo do app → apaga tudo que não é a versão atual → clients.claim(). Sem isso, cada deploy deixa um cache inteiro esquecido no disco do usuário.

Dois detalhes que não são do service worker mas mordem igual:

  • Formatação de número e moeda: Intl.NumberFormat com o locale do documento, não do navegador. Um documento em alemão aberto num navegador em português precisa sair 1.234,56 €, não € 1,234.56.
  • PDF: window.print() com um CSS @media print bem feito resolve sem biblioteca de PDF e sem mandar nada para servidor.

Alguém aqui usa Workbox ou prefere escrever o service worker na mão como eu? Queria entender em que ponto a biblioteca começa a valer a pena.

Carregando publicação patrocinada...
1

O "sem medo" da regra 1 depende do deploy. Se o servidor ignora a query, app.js?v=2 é o app.js que estiver no disco na hora. Com FTP ou rsync, se o HTML chega antes do JS novo, o JS velho responde 200 na URL nova e, com cache first, fica lá até o próximo deploy. O mínimo é subir os assets antes do HTML. Hash no nome (app.3f2a1c.js) resolve melhor: a URL nova dá 404 até o arquivo chegar, e com if (res.ok) antes do cache.put nada errado entra.

A regra 4 também pega as páginas da regra 2. No cache versionado, cada deploy apaga todas; em cache separado, o HTML guardado aponta pra um ?v= já apagado e abre quebrado offline. No install dá pra baixar de novo as páginas já guardadas.

O Workbox eu usaria quando o ?v= global pesar: mudou uma linha, baixa tudo. O precache dele compara revisão por arquivo e só baixa o que mudou.

1

Os dois pontos procedem, obrigado pela leitura cuidadosa.

Regra 1: aqui o deploy FTP e o servidor ignora a query, ento o cenrio que voc descreveu podia acontecer. E no service worker pior: o install faz addAll das URLs com o ?v= novo, e se o JS velho ainda estiver no disco ele entra no cache com a URL nova. Mudei o script de deploy para subir nesta ordem: assets, depois o HTML, e o sw.js por ltimo. Hash no nome seria mais robusto, como voc disse (o 404 protege sozinho), mas pede reescrever as referncias no build. Por enquanto a ordem cobre o caso comum.

Regra 4: verdade. As pginas que a regra 2 guarda moram no mesmo cache versionado, ento cada deploy apaga todas e offline sobra s a pgina principal. No abre quebrado, mas perde as outras. Ler as URLs de navegao do cache antigo no install e baixar de novo uma boa sada; vou testar.

E o ponto do Workbox responde a minha pergunta: comparar reviso por arquivo justamente o que falta quando um ?v= global obriga a baixar tudo por causa de uma linha.