Recentemente, a Wavy  lançou um aplicativo de notícias para o SBT, o SBT News.  Ele pode ser acessado em qualquer device clicando aqui, e sendo um progressive web app, ele possui algumas features que antes só eram disponíveis em aplicativos nativos, como notificações push e acesso offline.

Porque não um aplicativo nativo?

Um dos maiores desafios para construir um aplicativo mobile é a barreira de download, não são muitos os usuários que estão dispostos a gastar o espaço precioso com seu aplicativo ou até mesmo a gastar o tempo que leva para baixa-lo. Isso é uma grande vantagem de websites sobre aplicativos nativos, para os usuários, abrir um site é tão difícil quanto clicar em um link.

Mas o que torna um Progressive Web App (PWA para os íntimos) especial?

Bom, realmente não é muita coisa. Um PWA é basicamente uma aplicação web padrão, mas com algumas features extras para smartphones (apesar de terem benefícios para aplicações desktop também).

Captura de Tela 2018-08-29 às 17.17.12.png

As principais features são:

  • Notificações push
  • Abrir o seu app mesmo sem conexão
  • Cache offline automático dos assets da sua aplicação (muito bom para usuários com conexões ruins)
  • Um ícone customizado para a home do usuário e uma splash screen para abrir o seu app.

Essas features são com certeza bem vindas, mas na essência, todo progressive web app é simplesmente uma aplicação web com dois arquivos extras: o service worker, e o manifest.json.

O Service Worker

Esse é o arquivo mais importante de um PWA, ele é responsável pelo cache do seu website e dos seus assets. Ele é só um arquivo javascript que vai ser responsável por todo o trabalho pesado para você.

Você pode encontrar diferente estratégias de caching e exemplos do service worker aqui.


const isLocalhost = Boolean(
 window.location.hostname === ‘localhost’ ||
   window.location.hostname === ‘[::1]’ ||
   window.location.hostname.match(
     /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
   )
);

export default function register() {
 if (process.env.NODE_ENV === ‘production’ && ‘serviceWorker’ in navigator) {
   const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
   if (publicUrl.origin !== window.location.origin) {
     return;
   }

   window.addEventListener(‘load’, () => {
     const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;

     if (isLocalhost) {
       checkValidServiceWorker(swUrl);
       navigator.serviceWorker.ready.then(() => {
         console.log(
           ‘This web app is being served cache-first by a service ‘ +
             ‘worker. To learn more, visit https://goo.gl/SC7cgQ’
         );
       });
     } else {
       registerValidSW(swUrl);
     }
   });
 }
}

function registerValidSW(swUrl) {
 navigator.serviceWorker
   .register(swUrl)
   .then(registration => {
     registration.onupdatefound = () => {
       const installingWorker = registration.installing;
       installingWorker.onstatechange = () => {
         if (installingWorker.state === ‘installed’) {
           if (navigator.serviceWorker.controller) {
             console.log(‘New content is available; please refresh.’);
           } else {
             console.log(‘Content is cached for offline use.’);
           }
         }
       };
     };
   })
   .catch(error => {
     console.error(‘Error during service worker registration:’, error);
   });
}

function checkValidServiceWorker(swUrl) {
 fetch(swUrl)
   .then(response => {
     if (
       response.status === 404 ||
       response.headers.get(‘content-type’).indexOf(‘javascript’) === -1
     ) {
       navigator.serviceWorker.ready.then(registration => {
         registration.unregister().then(() => {
           window.location.reload();
         });
       });
     } else {
       registerValidSW(swUrl);
     }
   })
   .catch(() => {
     console.log(
       ‘No internet connection found. App is running in offline mode.’
     );
   });
}

export function unregister() {
 if (‘serviceWorker’ in navigator) {
   navigator.serviceWorker.ready.then(registration => {
     registration.unregister();
   });
 }
}

O manifest.json

Ele é responsável por como o seu app vai ficar na home do seu usuário, qual a imagem do ícone e do splash, a cor da barra de notificações, etc. Basicamente toda a configuração visual do seu PWA acontece neste arquivo.

É simplesmente um arquivo de configuração, nenhuma mágica.

{
 “short_name”: “My PWA”,
 “name”: “My Progressive Web App”,
 “icons”: [
   {
     “src”: “favicon.ico”,
     “sizes”: “64×64 32×32 24×24 16×16”,
     “type”: “image/x-icon”
   }
 ],
 “start_url”: “./index.html”,
 “display”: “standalone”,
 “theme_color”: “#000000”,
 “background_color”: “#ffffff”
}

 

create-react-app

Uma boa notícia para quem usa o create-react-app, assim que o bootstrap da aplicação é feito, ele já gera um service worker funcionando e também uma base de um manifest.json, então é extremamente fácil começar a brincar com progressive web apps e foi assim que a configuração inicial do SBT News foi feita 😉

Performance

A característica mais importante do seu PWA é que ele precisa ser rápido, realmente rápido. E faz sentido, se a sua aplicação for lenta e travada, demorando décadas para abrir, qual o sentido de fazer uma PWA? O objetivo é ter uma experiência o mais próxima possível de uma aplicação nativa.

Para isso existem algumas ferramentas muito úteis para tornar o seu site mais rápido, primeiro de tudo, uma forma de medir performance. A ferramenta de audit do Google Chrome é interessante para analisar os tempos de renderização e tempos para primeira interação, e o melhor de tudo, já está disponível no seu browser! É só acessar a aba de audits dentro do devtools do chrome. E o seu objetivo é tornar a pontuação do seu site o mais alta possível.

Captura de Tela 2018-08-29 às 17.18.40.png

Além disso, o audits faz análises de acessibilidade, boas práticas, e de quantos itens da checklist de progressive web apps você cumpre!

O que mais impacta na performance é utilizar gzip nos seus assets, isso pode ser ativado tanto no seu servidor no caso de server-side rendering ou na sua cdn no caso de um site estático, como é o caso do SBT Notícias. Apenas por habilitar a compressão, já é possível conseguir notar grandes melhorias na performance da aplicação.

Outra estratégia simples para melhorar o seu score, é fazer code-splitting por rotas, você pode tanto usar o webpack code splitting ou usar uma biblioteca como react-loadable. Isso vai ajudar a diminuir o tamanho do bundle inicial, e consequentemente o tempo de loading inicial.

CSS Componentizado

Outro ponto que não é tão relacionado com uma PWA, mas que teve bastante importância na forma que o SBT News foi desenvolvido, é como lidamos com CSS. Em react, temos algumas opções em relação à CSS como escrever CSS global da forma que sempre fizemos ou usar estilo com escopo de componentes. Nós seguimos com a segunda alternativa, já que ela permite uma quantidade bem menor de efeitos colaterais quando editando o CSS, tornando o trabalho de lidar com todos os estilos muito mais fácil a medida que a  aplicação cresce.

Mas para fazer isso com uma simples aplicação create-react-app você tem duas opções: ou nomeando as classes CSS com um namespace específico por componente na mão, ou usar a prop style nos componentes diretamente. Essas opções não são ideias, pois nomear manualmente as classes dá trabalho e não é um processo perfeito, e no caso da prop style, perdemos features importantes como media queries e pseudo selectors. Então acabamos seguindo com o styled-components, que tornou todo esse processo muito mais simples, podendo escrever basicamente CSS diretamente nos componentes.

E o melhor de tudo é que com o styled-components temos acesso à todas as features avançadas do CSS, como like pseudo, media-selectors e transições.

Além disso, é possível encontrar também alguns pequenos benefícios para a performance, já que como cada componente tem apenas o CSS que precisa para se desenhar, isso aliado com code splitting permite separar o seu CSS em várias partes. Então para cada página, será carregado apenas o CSS necessário para desenhar seus componentes, evitando assim que o navegador precise analisar blocos monolíticos de estilo que nem estão sendo utilizados na tela exibida.

Working with development of progressive web apps in React.js, RESTful and GraphQL apis with node.js and spring framework.

Posted by:João Gonçalves

<span class="lt-line-clamp__line">Working with development of progressive web apps in React.js, RESTful and GraphQL apis with</span> <span class="lt-line-clamp__line lt-line-clamp__line--last">node.js and spring framework.</span>

Deixe seu comentário