O que a equipe do Bulletin aprendeu sobre os service workers ao desenvolver um PWA.
Esta é a primeira de uma série de postagens do blog sobre as lições que a equipe do Google Bulletin aprendeu ao criar um PWA externo. Nessas postagens, vamos compartilhar alguns dos desafios que enfrentamos, as abordagens que seguimos para superá-las e conselhos gerais para evitar armadilhas. Isso não vale oferece uma visão geral completa dos PWAs. O objetivo é compartilhar o que aprendemos com a experiência da nossa equipe.
Nesta primeira postagem, abordaremos algumas informações básicas e, em seguida, nos aprofundaremos em todos os o que aprendemos sobre os service workers.
Contexto
O Mural estava em desenvolvimento ativo de meados de 2017 a meados de 2019.
Por que escolhemos criar um PWA
Antes de nos aprofundarmos no processo de desenvolvimento, vamos examinar por que criar um PWA foi uma opção atraente para este projeto:
- Capacidade de iterar rapidamente. Especialmente valioso porque o Mural seria testado em em vários mercados.
- Única base de código. Os usuários estavam divididos de maneira quase uniforme entre Android e iOS. Um PWA poderíamos criar um único app da Web que funcionasse nas duas plataformas. Isso aumentou a velocidade e o impacto da equipe.
- Atualizado de maneira rápida e independente do comportamento do usuário. Os PWAs podem atualizar automaticamente reduz a quantidade de clientes desatualizados em todo o mundo. Conseguimos expandir a divisão de back-end alterações em um tempo de migração muito curto para os clientes.
- Facilmente integrada a apps próprios e de terceiros. Essas integrações eram um requisito para o app. Em um PWA, isso significava simplesmente abrir um URL.
- Removemos o atrito da instalação de um app.
Nossa estrutura
Para o Mural, usamos o Polymer, mas qualquer plataforma moderna com vai funcionar.
O que aprendemos sobre service workers
Não é possível ter um PWA sem um serviço worker. Service Workers oferecem muita capacidade, como estratégias avançadas de armazenamento em cache, recursos off-line, sincronização em segundo plano, Embora os service workers aumentem um pouco a complexidade, descobrimos que os benefícios superaram complexidade.
Gere-a se puder
Evite escrever um script de service worker manualmente. Escrever service workers manualmente exige gerenciar recursos em cache e reescrever a lógica comum à maioria das bibliotecas de service workers, como como Workbox.
Dito isso, devido ao nosso conjunto interno de tecnologias, não seria possível usar uma biblioteca para gerar e gerenciar nosso service worker. Os aprendizados abaixo podem, às vezes, refletir isso. Acesse Armadilhas para service workers não gerados para saber mais.
Nem todas as bibliotecas são compatíveis com service workers
Algumas bibliotecas JS fazem suposições que não funcionam como esperado quando executadas por um service worker. Para
instância, supondo que window
ou document
estejam disponíveis, ou usando uma API não disponível para o serviço
workers (XMLHttpRequest
, armazenamento local etc). Verifique se todas as bibliotecas essenciais que você precisa
são compatíveis com service workers. Para este PWA específico, queríamos usar
gapi.js para autenticação, mas foram
porque ela não oferecia suporte a service workers. Os autores das bibliotecas também devem reduzir ou remover
suposições desnecessárias sobre o contexto do JavaScript sempre que possível para viabilizar o uso do service worker
casos, como evitar APIs incompatíveis com service workers e evitar problemas
estado.
Evitar acessar IndexedDB durante a inicialização
Não leia IndexedDB quando o script do seu service worker ou, caso contrário, você poderá entrar nesta situação indesejada:
- O usuário tem um app da Web com a versão N do IndexedDB (IDB)
- Novo aplicativo da web é enviado com a versão N+1 do IDB
- O usuário acessa o PWA, que aciona o download de um novo service worker
- O novo service worker lê do IDB antes de registrar o manipulador de eventos
install
, acionando uma O ciclo de upgrade do IDB vai de N a N+1 - Como o usuário tem um cliente antigo com a versão N, o processo de upgrade do service worker fica ativo como ativo conexões ainda estão abertas para a versão antiga do banco de dados
- O service worker trava e nunca instala
No nosso caso, o cache foi invalidado na instalação do service worker. Portanto, se o service worker nunca instalado, os usuários nunca receberam o aplicativo atualizado.
Torne a página resiliente
Embora os scripts dos service workers sejam executados em segundo plano, eles também podem ser encerrados a qualquer momento, mesmo no meio de operações de E/S (rede, IDB, etc). Todo processo de longa duração precisa ser retomável a qualquer momento.
No caso de um processo de sincronização que enviava arquivos grandes para o servidor e os salvava no IDB, nossa solução para uploads parciais interrompidos era aproveitar o recurso retomável da biblioteca de upload interno sistema, salvando o URL de upload retomável no IDB antes do envio e usando esse URL para retomar uma fazer upload caso não tenha sido concluído na primeira vez. Além disso, antes de qualquer operação de E/S de longa duração, estado foi salvo no IDB para indicar em que ponto do processo estávamos para cada registro.
Não dependam do estado global
Como os service workers existem em um contexto diferente, muitos símbolos que você pode esperar existir não são
presente. Grande parte do nosso código foi executada em um contexto de window
e em um contexto de service worker (como
como geração de registros, flags, sincronização etc.). O código precisa ficar na defensiva sobre os serviços que usa, como
armazenamento local ou cookies. Você pode usar
globalThis
para se referir ao objeto global de uma maneira que funcione em todos os contextos. Usar também os dados armazenados
em variáveis globais com moderação, já que não há garantia de quando o script será encerrado e
o estado removido.
Desenvolvimento local
Um componente importante dos service workers é armazenar recursos em cache localmente. No entanto, durante o desenvolvimento,
é exatamente o oposto do que você quer, especialmente quando as atualizações são feitas lentamente. Você ainda quer
o worker do servidor instalado para que você possa depurar problemas com ele ou trabalhar com outras APIs, como
sincronização em segundo plano ou notificações. No Chrome, você pode fazer isso com o Chrome DevTools,
ativar a caixa de seleção Ignorar para a rede (painel Aplicativo > painel Service workers)
além de marcar a caixa de seleção Desativar cache no painel Rede para também
o cache de memória. Para abranger mais navegadores, optamos por uma solução diferente,
incluindo uma flag para desativar o armazenamento em cache no nosso service worker, que é ativado por padrão no
builds. Isso garante que os desenvolvedores sempre recebam as alterações mais recentes sem problemas de armazenamento em cache. Está
importante também incluir o cabeçalho Cache-Control: no-cache
para impedir que o navegador
armazenar em cache todos os recursos.
Farol
O Lighthouse oferece vários recursos de depuração. ferramentas úteis para PWAs. Ele verifica o site e gera relatórios sobre PWAs, desempenho, acessibilidade, SEO e outras práticas recomendadas. Recomendamos executar o Lighthouse do Google Cloud para alertá-lo se você interromper um dos critérios para ser um PWA. Na verdade, isso aconteceu uma vez, em que o service worker não estava instalando e não percebemos isso antes do envio de produção. Ter o Lighthouse como parte da nossa CI teria evitou isso.
Adote a entrega contínua
Como os service workers podem ser atualizados automaticamente, os usuários não conseguem limitar upgrades. Isso reduz significativamente a quantidade de clientes desatualizados em todo o mundo. Quando o usuário abriu nosso app, o service worker atenderia o cliente antigo enquanto baixava lentamente o novo cliente. Quando o um novo cliente for baixado, será solicitado que o usuário atualize a página para acessar novos recursos. Mesmo que o usuário ignorou essa solicitação, na próxima vez que ele atualizasse a página, receberia a nova do cliente. Como resultado, é muito difícil para um usuário recusar atualizações no mesmo para apps iOS/Android.
Conseguimos realizar alterações interruptivas de back-end com um tempo de migração muito curto para clientes. Normalmente, daríamos um mês para os usuários atualizarem para clientes mais recentes antes de alterações interruptivas. Como o aplicativo seria veiculado enquanto estava desatualizado, era possível que clientes mais antigos existisse livremente se o usuário não abrisse o app por muito tempo. No iOS, os service workers são despejados depois de algumas semanas então esse caso não acontece. No Android, esse problema poderia ser atenuado pela não veiculação enquanto ou expirar manualmente após algumas semanas. Na prática, nunca encontramos problemas de clientes desatualizados. A rigidez de uma equipe depende do uso específico dela mas os PWAs oferecem muito mais flexibilidade do que apps iOS/Android.
Como conseguir valores de cookies em um service worker
Às vezes, é necessário acessar valores de cookies em um contexto de service worker. No nosso caso,
necessárias para acessar valores de cookies a fim de gerar um token para autenticar as solicitações de API primárias. Em um
service worker, as APIs síncronas, como document.cookies
, não estarão disponíveis. Você sempre pode enviar uma
para clientes ativos (em janelas) do service worker para solicitar os valores de cookies,
é possível que o service worker seja executado em segundo plano sem nenhum cliente na janela
disponíveis, por exemplo, durante uma sincronização em segundo plano. Para contornar isso, criamos um endpoint em nossa
de front-end que simplesmente transmitiu o valor do cookie de volta para o cliente. O service worker fez uma
solicitação de rede para esse endpoint e ler a resposta para obter os valores de cookie.
Com o lançamento API Cookie Store, essa solução alternativa não deve mais ser necessária para os navegadores compatíveis, pois oferece acesso assíncrono a cookies do navegador e pode ser usado diretamente pelo service worker.
Dificuldades para service workers não gerados
Verifique se o script do service worker muda caso algum arquivo estático armazenado em cache seja alterado
Em um padrão PWA comum, um service worker instala todos os arquivos estáticos de aplicativos durante a
a fase install
, que permite que os clientes acessem o cache da API Cache Storage diretamente para todos
visitas subsequentes . Os service workers só são instalados quando o navegador detecta que o serviço
o script do worker mudou de alguma forma, então tivemos que garantir que o próprio arquivo de script do service worker
alterado de alguma forma quando um arquivo armazenado em cache é alterado. Fizemos isso manualmente incorporando um hash da
de arquivo estático de recursos dentro do script do nosso service worker, de modo que cada versão produzia um
arquivo JavaScript do service worker. As bibliotecas de service workers, como
O Workbox automatiza esse processo para você.
Teste de unidade
As APIs de service worker funcionam adicionando listeners de eventos ao objeto global. Exemplo:
self.addEventListener('fetch', (evt) => evt.respondWith(fetch('/foo')));
Esse teste pode ser complicado porque você precisa simular o gatilho do evento, o objeto do evento, aguardar
o callback respondWith()
e aguardar a promessa antes de finalmente fazer a declaração no resultado. Um
maneira mais fácil de estruturar isso é delegar toda a implementação a outro arquivo, o que facilita
é treinado e testado.
import fetchHandler from './fetch_handler.js';
self.addEventListener('fetch', (evt) => evt.respondWith(fetchHandler(evt)));
Devido às dificuldades do teste de unidade do script de um service worker, mantivemos o service worker principal o mais simples possível, dividindo a maior parte da implementação em outros módulos. Como esses arquivos fossem apenas módulos JS padrão, poderiam ser mais facilmente testados com a unidade usando testes padrão bibliotecas.
Fique de olho nas partes 2 e 3
Nas partes 2 e 3 desta série, falaremos sobre o gerenciamento de mídia e problemas específicos do iOS. Se você quiser mais informações sobre a criação de um PWA no Google, visite nossos perfis de autor para descobrir como entrar em contato: