PWA: Uma grande lista de dicas e truques para Progressive Web Apps
Tags: ptbr, pwa, webdev, javascript
Published: 2019-08-05 23:47:38

Ultimamente tenho feito muitas palestras sobre o Progressive Web Apps. No final das palestras, normalmente há uma seção de perguntas e respostas em que o público faz perguntas ou propõe ideias. Muitas vezes durante essas sessões, me perguntam questões realmente úteis que valem a pena compartilhar com um público mais amplo.

Nesse artigo, juntei uma lista de algumas das perguntas que me fazem regularmente sobre os Progressive Web Apps e Service Workers e tentei incluir as respostas mais precisas que pude. Algumas dessas perguntas podem parecer óbvias, algumas não tão óbvias - mas, no geral, espero que sejam úteis!

Então... vamos lá! Sem nenhuma ordem em particular, essa lista de dicas úteis, truques e pegadinhas que podem ajudá-lo a construir o seu próximo Progressive Web App!

---

# Como posso saber quantos usuários estão usando a funcionalidade Adicionar à tela inicial (A2HS) no meu site?

Quando o banner A2HS (_Add to homescreen_) é exibido, você pode escutar o evento `beforeinstallprompt` para determinar a escolha que o usuário fez quando foi apresentado ao banner.

O código abaixo mostra isso em ação:

```js
window.addEventListener("beforeinstallprompt", function(event) {
  event.userChoice.then(function(result) {
    if (result.outcome == "dismissed") {
      // Usuário dispensou o banner, enviar para o nosso analytics
    } else {
      // User accepted! Send to analytics
      // Usuário aceitou o banner, enviar para o nosso analytics
    }
  });
});
```

Usando o código acima, você pode determinar se o usuário descartou o banner ou se decidiu adicionar seu aplicativo à tela inicial. Usando uma ferramenta de captura de dados, você poderá rastrear sua escolha e determinar se essa funcionalidade é benéfica para seus usuários.

Outra técnica furtiva é definir na url de início em seu arquivo **manifest.json** uma **querystring** indicando que ele foi aberto por meio da tela inicial do dispositivo de um usuário.

Por exemplo, você pode atualizar a propriedade `start_url` no **manifest.json**:

```json
{
    "name": "Progressive Beer",
    "short_name": "beer",
    "start_url": "index.html?start=a2hs"
}
```

Com a url de início atualizada, incluindo a querystring, irá permitir que suas ferramentas de análise de dados determinem quantos usuários chegam ao seu PWA por meio do ícone na tela inicial do dispositivo.

# O banner Adicionar ao Homescreen não faz sentido para o meu site. Como desabilito essa funcionalidade? Eu quero esconder isso!

Usando um pouco de código, você pode sobrescrever a funcionalidade padrão e fazer com que o navegador ignore o banner Adicionar à tela inicial (A2HS). Ao adicionar o seguinte código à sua página, você poderá acessar o evento do prompt do banner e substituir o comportamento padrão:

```js
window.addEventListener("beforeinstallprompt", function(e) {
  e.preventDefault();
  return false;
});
```

Dependendo do tipo do seu aplicativo web, pode não fazer sentido mostrar esse aviso. Talvez o seu site cubra tópicos sensíveis ou até mesmo um evento de curta duração, e o banner passa a ser mais irritante para o usuário do que útil.

# Minha funcionalidade Adicionar à tela inicial (A2HS) não parece estar funcionando - ajuda!?

Ok, então você adicionou corretamente um arquivo **manifest.json** ao seu site e o referenciou na tag **head** do seu HTML da seguinte forma:

```html
<link rel="manifest" href="manifest.json"> 
```

No entanto, se por algum motivo você ainda não estiver vendo o banner na parte inferior da página, há algumas coisas que você pode querer verificar. Em primeiro lugar, para o banner A2HS aparecer, alguns critérios precisam ser atendidos:

- Seu site precisa estar executando HTTPS, ter um arquivo de manifesto válido (com uma URL e um ícone de início) e ter um arquivo de **service worker** ativo.
- O usuário também precisa ter visitado seu site pelo menos duas vezes nos últimos cinco minutos. A razão para isso é que, se o banner aparecer muitas vezes, pode ser muito spam para o usuário. Esses banners de "instalar nosso aplicativo nativo" já são ruins em alguns sites!

# Estou adicionando recursos ao cache com código no meu service worker, mas o cache não está atualizando quando eu altero o arquivo. Ainda consigo ver a versão mais antiga dos meus arquivos mesmo depois de atualizar a página - por quê?

Comece verificando no **Chrome DevTools** para determinar quais arquivos estão realmente sendo armazenados em cache. Se você abrir o Chrome Dev Tools e acessar a guia **Application**, poderá determinar quais arquivos estão realmente no cache:

![](https://307a6ed092846b809be7-9cfa4cf7c673a59966ad8296f4c88804.ssl.cf3.rackcdn.com/pwa-tips-tricks/service-worker-cache.jpg)

Se você precisar garantir que os arquivos sejam sempre atualizados ao fazer alterações, você pode considerar adicionar versão aos arquivos e renomeá-los. Dessa forma, você garante que cada alteração de arquivo seja armazenada em cache corretamente. Por exemplo, usando [controle de versão de arquivos](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#invalidating_and_updating_cached_responses), podemos referenciar um arquivo JavaScript em nosso HTML da seguinte forma:

```html
<script src=”/js/main-v2.js”>
```

Cada vez que o arquivo é alterado, você aumenta a versão que resulta em um novo download.

Outra técnica para garantir que você sempre obtenha código novo é realmente excluir as entradas em cache atuais quando o service worker é ativado após a atualização. Ao escutar o evento de ativação durante o ciclo de vida do service worker, você pode limpar o cache. [Eu recomendo verificar este link como uma orientação](https://googlechrome.github.io/samples/service-worker/custom-offline-page/).

Dependendo de como o seu PWA foi construído, você pode querer escolher a melhor estratégia para atender às suas necessidades.

# Como faço para ter testes de unidade do meu código do Service Worker?

Testar o código do Service Worker pode ser complicado, mas não tenha medo, Matt Gaunt escreveu um excelente artigo sobre os detalhes do teste dos Service Workers. [Eu recomendo a leitura deste artigo no Medium para mais informações](https://medium.com/dev-channel/testing-service-workers-318d7b016b19).

# Não tenho certeza se meu arquivo manifest.json está funcionando corretamente - como eu testo isso?

Uma das minhas ferramentas favoritas para validar arquivos de [manifesto](https://developer.mozilla.org/en-US/docs/Web/Manifest) é [manifest-validator.appspot.com](https://manifest-validator.appspot.com/). O validador de manifesto de aplicativo web verifica o arquivo e usa a especificação do W3C para determinar se ele é válido. Se você estiver com dificuldade para entender por que o manifesto do seu aplicativo web não parece correto, a ferramenta fornecerá comentários sobre qual parte causou um problema e também diferentes motivos que podem estar causando o problema.

![](https://307a6ed092846b809be7-9cfa4cf7c673a59966ad8296f4c88804.ssl.cf3.rackcdn.com/pwa-tips-tricks/validator.png)

No entanto, se você se esforçar para criar esses arquivos e achar que comete erros aqui e ali, recomendo usar um gerador de arquivo de manifesto. [Este repo do Github criado por Bruce Lawson](https://brucelawson.github.io/manifest/) tem uma ferramenta útil, onde você simplesmente insere seus detalhes e gera um arquivo de manifesto completo para você.

# Com que frequência o arquivo do Service Worker é atualizado?

Toda vez que você navegar para uma nova página que esteja sob o escopo de um service worker, o Chrome fará uma solicitação HTTP padrão para o recurso JavaScript que foi passado para a chamada `navigator.serviceWorker.register()`. Por padrão, essa solicitação HTTP obedecerá às diretivas de cache HTTP, mas se o arquivo do service worker for mais velho que 24 horas, Chrome sempre irá na rede e buscará uma versão nova do arquivo do service worker. Isso é para garantir que os desenvolvedores não implementem acidentalmente um arquivo de service worker "quebrado" ou com bugs que fica preso no navegador para sempre. Pense nisso como um interruptor de segurança para o seu arquivo de service worker.

Para obter mais informações, [recomendo a leitura do artigo a seguir no Stack Overflow, no qual Jeff Posnick, do Google, entra em mais detalhes](https://stackoverflow.com/questions/38843970/service-worker-javascript-update-frequency-every-24-hours/38854905#38854905).

# Meu arquivo do Service Worker está emitindo um erro, mas não tenho certeza do que está errado. Como depurar isso?

Sem dúvida, a maneira mais fácil de depurar seu código do Service Worker é usar as DevTools em seu navegador. Se você abrir o Chrome DevTools e ir para a guia **Sources**, poderá definir um ponto de interrupção para ajudá-lo a depurar o erro.

![](https://307a6ed092846b809be7-9cfa4cf7c673a59966ad8296f4c88804.ssl.cf3.rackcdn.com/pwa-tips-tricks/debugging-service-worker.jpg)

Com o ponto de interrupção definido no DevTools, seu código será pausado quando atingir esse ponto e permitirá que você veja exatamente como sua lógica está sendo executada. Dominar o DevTools é um grande passo em frente para se tornar um melhor desenvolvedor. Embora muitos dos fornecedores de navegadores ofereçam tutoriais para suas ferramentas de desenvolvedor, meu favorito é o Chrome DevTools. Se você quiser saber mais, [recomendo verificar o seguinte link](https://developers.google.com/web/fundamentals/getting-started/codelabs/debugging-service-workers/).

# Eu tentei de tudo, mas por alguma razão maluca minha lógica do Service Worker nunca parece executar - ajuda!?

Vale a pena conferir seu DevTools para ver se você pode ter ativado uma configuração incorretamente. Por exemplo, se você ativar **"Bypass for network"**, a lógica do Service Worker será ignorada e, ao invés disso, buscará recursos na rede ao invés do seu cache.

![](https://307a6ed092846b809be7-9cfa4cf7c673a59966ad8296f4c88804.ssl.cf3.rackcdn.com/pwa-tips-tricks/bypass-for-network.jpg)

Da mesma forma, você pode querer verificar se não tem as outras configurações ativadas quando não precisa delas. Por exemplo, **Offline** e **Update on reload** - fiquei coçando a cabeça várias vezes tentando descobrir por que meu código não estava funcionando, apenas para descobrir que tinha esquecido de desativar uma dessas configurações - d'oh!

# Se um usuário instalou meu aplicativo da Web em sua tela inicial, mas limpa o cache no Chrome, os recursos armazenados em cache do meu site também são limpos?

Sim, como a experiência do Progressive Web App é ativada pelo Chrome, o armazenamento, no momento, é compartilhado. Se um usuário limpar o cache do Chrome, seu PWA também limpará seu armazenamento.

Se você quiser saber mais sobre a funcionalidade aprimorada do A2HS no Chrome, [é altamente recomendável ler o artigo a seguir](https://developers.google.com/web/updates/2017/02/improved-add-to-home-screen#will_my_installed_sites_storage_be_cleared_if_the_user_clears_chromes_cache).

# Quanta memória meu aplicativo Progressive Web pode usar no dispositivo de um usuário?

A resposta honesta é que isso realmente depende do dispositivo e das condições de armazenamento. Como todo armazenamento de navegador, o navegador fica livre para descartá-lo se o dispositivo ficar sob pressão de armazenamento.

Se você quiser determinar quanto armazenamento você tem e quanto você usou, o código a seguir pode ajudar.

```js
navigator.storageQuota.queryInfo("temporary").then(function(info) {
  console.log(info.quota); // A quantidade total em bytes
  console.log(info.usage); // Quantos dados você usou até agora em bytes
});
```

O código acima pode não funcionar em todos os navegadores, mas definitivamente te apontará na direção certa. [Há uma ótima resposta no Stack Overflow que explica isso com mais detalhes](https://stackoverflow.com/questions/35242869/what-is-the-storage-limit-for-a-service-worker).

# Meus recursos em cache parecem expirar de vez em quando, como posso garantir que eles fiquem permanentemente armazenados em cache?

Quando o espaço de armazenamento em um dispositivo está baixo, o navegador limpa automaticamente o armazenamento para aumentar o espaço disponível. Embora isso garanta que o dispositivo de seus usuários seja sempre executado sem problemas, isso pode tornar a construção de uma experiência realmente off-line para a Web um pouco mais difícil.

Não tenha medo! Tem jeito. Se você quiser tornar o armazenamento em cache mais persistente, poderá solicitar explicitamente usando um pouco de código.

```js
if (navigator.storage && navigator.storage.persist) {
  navigator.storage.persist().then(granted => {
    if (granted) {
      alert("Armazenamento persistirá e não será limpo");
    } else {
      alert("Armazenamento não persistirá e pode ser limpo");
    }
  });
}
```

Existem alguns critérios que precisam ser atendidos antes que o armazenamento persistente seja concedido, mas se você quiser saber mais sobre esse ótimo recurso, [recomendo a leitura deste artigo para obter mais informações](https://developers.google.com/web/updates/2016/06/persistent-storage).

# Eu adicionei código para lidar com notificações push no meu arquivo de service worker, mas como posso testá-las rapidamente sem escrever código do lado do servidor?

Se você está procurando uma maneira rápida de simular eventos push dentro de seu aplicativo da Web, o Chrome DevTools fornecem uma maneira rápida e fácil de simulá-las em ação.

![](https://307a6ed092846b809be7-9cfa4cf7c673a59966ad8296f4c88804.ssl.cf3.rackcdn.com/pwa-tips-tricks/simluate-push.jpg)

# Eu criei um aplicativo da Web off-line, mas agora não consigo ver como os usuários estão usando meu aplicativo. Como faço para acompanhar o uso?

Sem dúvida, uma das bibliotecas mais interessantes a aparecer ultimamente deve ser o pacote do Google Analytics Offline. Usando um pouco de mágica inteligente no service worker, a biblioteca enfileirará todas as solicitações do analytics enquanto o usuário estiver off-line e, assim que você recuperar uma conexão, enviará as solicitações enfileiradas para o servidor.

Para começar a usar a biblioteca, basta incluí-la no arquivo do service worker usando o código abaixo.

```js
importScripts('../build/offline-google-analytics-import.js');                   

goog.offlineGoogleAnalytics.initialize();                           

self.addEventListener('install', () => self.skipWaiting());                 
self.addEventListener('activate', () => self.clients.claim());
```

Ao incluir esse código no arquivo do service worker, a biblioteca rastreará as ações realizadas pelo usuário enquanto estiver off-line, criará uma fila e as enviará em ordem quando o usuário recuperar a conectividade. Coisas muito legais!

# Como faço para lidar com parâmetros querystring e cache?

Quando um Service Worker procura uma resposta em cache, ele usa uma URL de solicitação como a chave. Por padrão, o URL de solicitação deve corresponder exatamente a URL usada para armazenar a resposta em cache, incluindo todos os parâmetros querystring na parte de pesquisa do URL.

Por exemplo, se você fizer uma solicitação para uma URL com uma querystring e ela puder corresponder a uma consulta anterior, você talvez descubra que ela não será exibida na próxima vez, porque a querystring é um pouco diferente. Para ignorar querystring ao verificar o cache, use o atributo **ignoreSearch** e defina o valor como true.

O código abaixo dá uma ideia disso em ação:

```js
self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request, {
      **ignoreSearch: true**
    }).then(function(response) {
      return response || fetch(event.request);
    })
  );
});
```

# Finalizando

Houve muitos momentos em que me vi arrancando os cabelos tentando descobrir os detalhes diferentes para os trabalhadores de serviço, apenas para descobrir que a solução era mais simples do que parecia - espero que você tenha achado este artigo útil!

Para manter o compartilhamento de conhecimento, [criei um repositório do Github com todas essas perguntas](https://github.com/deanhume/pwa-tips-tricks). Se você tem alguma dica que gostaria de adicionar, ou algo não parece preciso, por favor, crie um PR e juntos podemos crescer este documento - você nunca sabe como isso poderia ajudar os outros!

# Créditos

- [A BIG list of Progressive Web App tips & tricks](https://deanhume.com/a-big-list-of-progressive-web-app-tips/), escrito originalmente por [Dean Hume](https://twitter.com/deanohume)