Construir um PWA (Progressive Web App) é uma maneira de possibilitar que sua aplicação web escrita em html, css e javascript funcione praticamente como um aplicativo para smartphones, desktops e tablets podendo inclusive ser instalada, ter "push notifications" e funcionamento completamente offline. Nesse post não vou me aprofundar tanto no conceito, mas mostrarei como é simples e rápido transformar um projeto Elixir e Phoenix em um PWA. 

Vamos aos passos para criar o seu PWA com Elixir e Phoenix:


Passo 1:


Adicione um arquivo chamado manifest.json no seu priv/static contendo o seguinte conteúdo:

{
  "short_name": "My App", // Nome em que aparecerá junto ao ícone
  "name": "My Very Progressive Web App @PWA", // Descrição que aparecerá enquanto o aplicativo é carregado
  "icons": [ // Coloque aqui a localização dos ícones do seu aplicativo
    {
      "src": "/images/logo.png",  
      "type": "image/png"
    }
  ],
  "start_url": "/", // Aqui vai o endereço principal do seu aplicativo (o que irá ser acessado primeiro quando abrirmos o app)
  "background_color": "#fff", // Definimos uma cor de fundo enquanto ao aplicativo é carregado.
  "display": "standalone", // Definimos o modo primário que o navegador deve considerar para exibir o aplicativo.
  "scope": "/", // Definimos o escopo, limite, das páginas a serem consideradas como PWA
  "theme_color": "#000"   // Definimos uma cor para personalizar a interface do dispositivo em uso
} 
                                             

Este arquivo é o responsável por personalizar a aparência do nosso PWA e um pouco da experiência de uso. Além das configurações setadas acima, também podemos adicionar as seguintes:

  • lang: Definimos o idioma utilizado (ex: pt-BR).
  • orientation: Definimos a orientação de como exibir o aplicativo (ex: any, natural, landscape, landscape-primary, landscape-secondary, portrait, portrait-primary, portrait-secondary).
  • prefer_related_applications: Informa se há uma outra aplicação complementar (Boolean).
  • related_applications: Definimos as aplicações complementares (Array de objetos de aplicações com os possíveis valores: platform, url e id).
  • dir: Definimos a direção do texto nas especifcações do manifesto.

Para agilizar o processo de criação do nosso manifest.json podemos recorrer a ferramentas de automatização. Esse site é bem eficiente e também nos ajuda a gerar os ícones formatados:

https://app-manifest.firebaseapp.com/

Passo 2:


Adicione um arquivo chamado service_worker.js no seu priv/static contendo o seguinte conteúdo:

self.addEventListener('install', function(e) {
  e.waitUntil(
    fetch('/cache_manifest.json')
    .then(function(response) {
      return response.json()
    })  
    .then(function(cacheManifest) {
      var cacheName = 'cache:static:' + cacheManifest.version
      var all = Object.values(cacheManifest.latest).filter(
        function(fn) { return fn.match(/^(images|css|js|fonts)/);
        })
      caches.open(cacheName).then(function(cache) {
        return cache.addAll(all).then(function() {
          self.skipWaiting();
        });
      })
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      if (response) {
        return response;
      }
      return fetch(event.request);
    })
  );
});

Essencialmente, um service worker se comporta como um servidor proxy situado entre uma aplicação web, o navegador e a rede (quando esta estiver disponível). Eles servem, dentre outras coisas, para possibilitar a criação de experiências offline eficientes, interceptar requisições de rede – agindo adequadamente de acordo com o status atual da conexão – e atualizar os assets que residem no servidor. Service workers também permitem o acesso às APIs de push notification e background sync.

- https://developer.mozilla.org/pt-BR/docs/Web/API/Service_Worker_API

No nosso caso, estamos escutando a dois eventos "install" e "fetch".

  • install: Na hora da instalação do aplicativo informamos a localização do nosso cache_manifest.json. Uma vantagem de utilizar o framework Phoenix para PWA's é que ele gera automaticamente este arquivo quando rodamos a task mix phx.digest! Este arquivo é responsável por informar dados de cache que são utilizados para o aplicativo funcionar de forma mais rápida, econômica e até de maneira offline dependendo do caso.
  • fetch: É disparado quando houver uma visita a uma url, se já tivermos cache, responde com o cache, se não executamos o fluxo normal.

Passo 3:


Permita que os arquivos service_worker.js, cache_manifest.json e manifest.json sejam acessados de forma estática, adicionando nas configurações de Plug.Static, encontradas no módulo Endpoint do seu projeto encontrado em (lib/seu_projeto_web/endpoint.ex):

plug Plug.Static,
  at: "/",
  from: :seu_projeto,
  gzip: false,
  only: ~w(css fonts images js favicon.ico robots.txt service_worker.js cache_manifest.json manifest.json) # aqui


Passo 4:


Adicione um link para o seu manifest.json e o seguinte script no layout principal do seu projeto:

<link rel="manifest" href="/manifest.json">
<script>
  if (navigator.serviceWorker) {
    navigator.serviceWorker.register('/service_worker.js', { scope: './' })
      .then(function(reg) {
        console.log('[ServiceWorker]', 'Service worker registered!');
        console.log(reg);
      });
  }
</script>

Este script basicamente registra o nosso service worker no navegador.

É isso! nossa PWA está pronta.

Este blog é uma PWA com Elixir! Se você estiver acessando este artigo através do celular e quiser ver o resultado dos passos acima, clique nas configurações do navegador e em seguida "Adicionar a tela inicial". Se estiver vendo no desktop, provavelmente o seu navegador terá um botão como na imagem abaixo:

Exemplo


Se gostou do conteúdo, você pode assinar o newsletter para sempre se atualizar quando houver novos posts! Prometo que não vou "lotar" a sua caixa de email com spam :D

links e fontes:

https://www.botsquad.com/2018/03/07/phoenix-sw/
https://blog.apiki.com/web-app-manifest/
https://gobacklog.com/blog/progressive-web-apps/
https://vizir.com.br/2017/08/o-que-e-pwa-progressive-web-app-porque-isso-pode-aumentar-seus-resultados-mobile/
https://developer.mozilla.org/pt-BR/docs/Web/API/Service_Worker_API