Categorias
PWA - Progressive web apps

Armazenamento de dados no Browser

Armazenamento de dados no Browser ou client-side é algo possível por diferentes APIs, no passado tivemos o uso de Cookies agora temos localStorage, sessionStorage, IndexedDB e CacheStorage API. Sem uso de back-end ou bibliotecas externas, suporte direto do Browser.

Nesse post iremos entender a diferença entre os tipos de armazenamento de dados no Browser e quando utiliza-los.

Cookies

Por muitos e muitos anos cookies foram utilizados para persistir dados na web, com o passar dos anos esse recurso evoluiu e passou por algumas melhorias mas também criou problemas relacionados a privacidade. Nos últimos anos os principais navegadores passaram a implementar restrições ao uso de Cookies. Recentemente Chrome, Firefox e Edge implementaram restrições de uso de cookies em aplicações com domínios diferentes.

Já é público por parte do time do Chrome a descontinuação de suporte ao uso de Cookies.

LocalStorage e SessionStorage

Posso fala que é o modo mais simples de armazenamento e dados na máquina do usuário. Introduzidos no HTML5 ambas permitem o armazenamento de texto no browser do usuário com um limite de até 5MB na maioria dos Browsers

SessionStorage

Como o nome sugere permite o armazenamento de dados na sessão do usuário(aba), quando a aba for fechada os dados serão removidos. Ela pode ser utilizadas em conjunto com outras API, com o armazenamento de dados temporário

LocalStorage

Sua utilização é simples mas atualmente seu uso é pouco recomendado já que a IndexedDB disponibiliza mais recursos para armazenamento a longo prazo. Além disso a localStorage possuí suas limitações:

  • Sua execução é síncrona
  • Tem uma limitação de armazenamento 5mb
  • E não possui acesso por service workers e web workers

IndexedDB

Banco de dados não relacional(noSQL) que realiza transações assíncronas. Com a IndexedDB conseguimos armazenar objetoos e realizar consultas através de índices. Com IndexedDB conseguimos trabalhar com, objetos, texto, arquivos e blobs.

Diferente da LocalStorage a IndexedDB possui acesso por web workers e service workers, nesse caso sendo um item crucial para armazenamento de dados offline em uma progressive web app.

Umas das desvantagens da IndexedDB é a complexidade de se trabalhar com essa API, seu comportamento pode ser simplificado por libs externas além da adição de recursos extras como, Promises.

CacheStorage API

A Cache API é um sistema de armazenamento de requisições e respostas realizadas a rede. Podemos armazenar requisições realizadas durante a execução da aplicação ou podemos armazenar requisições em background somente para uso de dados.

A API foi criada para permitir que service workers realizassem cache de requisições feitas a rede para permitir respostas rápidas ou reduzir um impacto na latências de conexões de dispositivos móveis.

O que podemos armazenar com cacheStorage API?

Apenas Requisições e respostas HTTP. Entretanto essas requisições podem conter qualquer tipo de dados transferido sobre o protocolo HTTP, por exemplo:

  • Imagens
  • Páginas
  • JavaScript
  • Arquivos CSS
  • Objetos JSON

Utilizando armazenamento de dados em uma PWA

Numa recomendação geral podemos classificar da seguinte forma:

  • Para recursos da aplicação como arquivos: Cache API Storage
  • Para dados e consulta: IndexedDB

Porque não é recomendado o uso de SessionStorage ou LocalStorage para PWAs? Simplesmente pela limitação de ter acesso através de service workers mas o recurso pode se utilizado como um fallback para navegadores que não possuem suporte a Service Worker.

Quanto eu posso armazenar?

Essa informação pode variar por navegadores mas em geral estamos falando de centenas de megabytes, para uma aplicação Web é bastante.

  • Chrome permite utilizar 60% do total do espaço em disco para diferentes domínios e APIs
  • Internet Explorer 10 permite 250MB no total mas irá avisar o usuário quando a aplicação utilizar mais de 10BM
  • Firefox tem um limite de 2GB, mas você pode determinar quanto espaço você terá disponível com a StorageManager API
  • Safari irá permitir até 1GB e irá requisitar permissão ao usuário quando atingir 200MB.

Esse post serviu como uma introdução mas já tinha feito um post no canal sobre LocalStorage a alguns anos você pode conferir aqui: LocalStorage: Armazenando dados com JavaScript

Categorias
Web

Lighthouse 6.0

Lighthouse para quem não conhece ele é o sistema de auditorias de performance, accessibilidade, SEO e PWA dentro do Chrome Dev tools. Também com a possibilidade de instalação no firefox através de extensão e com NPM.

Nesse mês de maio foi anunciado a versão 6.0 do Lighthouse, que estará disponível na versão 84 do Chrome. Essa nova versão contém as seguintes melhorias:

  • Novas métricas
  • Atualização da pontuação referente a performance
  • Novas auditoria sobre JavaScript não utilizado e Acessibilidade
  • Atualização no Lighthouse CI
  • Agora a aba Audits mudou para Lighthouse
  • Mudanças na emulação mobile
  • Performance Budget

Novas métricas

Largest Contentful Paint(LCP)

Maior pintura com conteúdo é uma medida da experiência de carregamento percebida. Ele marca o ponto durante o carregamento da página quando o conteúdo principal foi carregado e é visível para o usuário. O LCP é um complemento importante para First Contentful Paint(FCP), que captura apenas o início da experiência de carregamento.

Cumulative Layout Shift (CLS)

Deslocamento cumulativo de layout é uma medida da estabilidade visual. Quantifica quanto o conteúdo de uma página muda visualmente. Uma pontuação baixa no CLS é um sinal para os desenvolvedores de que seus usuários não estão passando por mudanças indevidas de conteúdo.

Total Blocking Time(TBT)

Tempo total de bloqueio quantifica a capacidade de resposta de carga, medindo a quantidade total de tempo em que o encadeamento principal foi bloqueado por tempo suficiente para impedir a capacidade de resposta da entrada. O TBT mede a quantidade total de tempo entre a FCP e tempo de interação.

Atualização de pontuação de Performance

A pontuação de performance é baseado nas seguintes métricas:

  • First Contentful Paint – 15%
  • Speed Index – 15%
  • Lagest Contentful Paint – 25%
  • Time to Interactive – 15%
  • Total Blocking – 25%
  • Cumulative Layout Shift – 5%

Lighthouse CI

No último Chrome Dev Summit foi anunciado o Lighthouse CI, um CLI em node de código aberto que realiza auditoria trazendo os resultados do Lighthouse para terminal de linha de comando. Agora Lighthouse tem suporte nativo de vários provedores de integração continua(CI), incluindo Travis, Circle, Gitlab e Github actions.

Para instalar o lighthouse CLI em seu terminal de linha de comando execute o seguinte código:

npm install -g lighthouse

Depois de instalado você pode realizar auditorias rodando o seguinte comado:

lighthouse https://www.example.com --view

O post completo sobre o lançamento você confere aqui: https://web.dev/lighthouse-whats-new-6.0/

Categorias
HTML5 JavaScript Tutoriais

Trabalhando com XMLHttpRequest e Fetch API

Nesse post vamos trabalhar com duas opções para realizar requisições Assíncrona a dados no servidor XMLHttpRequest e Fetch API. Com a popularização do jQuery por muito tempo utilizamos a biblioteca para fazer requisições AJAX pela facilidade, melhorias com recursos extras e o suporte aos browsers antigos.

Mas temos um recurso antigo que nos permite realizar requisições ao servidor com Vanilla JavaScript, o XMLHttpRequest.

XMLHttpRequest

XMLHttpRequest é um objeto XHR para interação com servidores. Com ele podemos requisitar dados sem realizar o reload de todo conteúdo, para você que está programando agora isso pode parecer básico, mas não era possível no começo da web.

Com a popularização do AJAX o XMLHttpRequest foi utilizado como recurso base para o conceito. O nome sugere que a API é focada em XML, mas elas pode resgatar qualquer tipo de dado.

Utilizando XMLHttpRequest

Para esse exemplo iremos fazer uma requisição a um arquivo em nosso projeto:

function onLoadRequest(event) { console.log(this.responseText); } const oRequest = new XMLHttpRequest(); oRequest.addEventListener('load', onLoadRequest); oRequest.open('GET', '/dados.json'); oRequest.send();

No código acima criamos uma objeto XMLHttRequest, onde adicionamos um listener para ouvir quando a requisição for lida. Assim abrimos uma requisição do tipo GET para arquivo dados.json em nosso projeto. E por fim enviamos a requisição com o método “send”

Por padrão essa requisição será assíncrona, isso significa que a execução do código continuará sendo executada e quando os dados forem recebido a função de callback onLoadRequest será executada.

Tratando as resposta

Temos diversos tipos de atributos de respostas a requisição os principais são responseXML e responseText no exemplo anterior tratamos o responseText.

responseXML: é utilizado para tratar requisições feitas para arquivos XML, nesse tipo de requisição podemos trabalhar de quatro formas com: XPath, Parsing e serialização de XML, XMLSerializer e expressões regulares.

responseText: se você deseja ler conteúdo de texto ou de uma página web e injetar em sua página Web, esse é o caminho. Atualmente é o formato mais utilizado na web.

Monitorando o processo

No código anterior, adicionamos um listener para o evento de load mas temos a opção de trabalhar com 5 eventos:

  • progress
  • error
  • abort
  • load
  • loadend(abort, load ou error)
// evento disparado quando a requisição for completa function onLoadRequest(event) { console.log(this.responseText); } // evento disparado quando o download do arquivo tem uma progressão function onProgressRequest (oEvent) { if (oEvent.lengthComputable) { let percentComplete = oEvent.loaded / oEvent.total * 100; console.log('Percentagem:', percentComplete + '%') } else { console.log('O total do arquivo é desconhecido'); } } const oRequest = new XMLHttpRequest(); oRequest.addEventListener('load', onLoadRequest); oRequest.addEventListener('progress', onProgressRequest) oRequest.open('GET', '/dados.json'); oRequest.send();

Caso algo de errado aconteça podemos realizar uma verificação para realizar um tratamento. Assim vamos adicionar uma condicional em nosso código:

function onLoadRequest(event) { if(this.status === 200) { console.log(this.responseText) } else { console.log('Somthing wrong happen:',this.status); } }

No código acima verificamos se o status da requisição é 200(sucesso) caso contrário exibimos o status, dai temos uma várias possibilidades: 404, 401, 500…

Fetch API

Fetch API é uma melhoria sobre a XMLHttpRequest. Ela trás a possibilidade de trabalhar com interface para administrar as requisições de recursos na rede, anteriormente tínhamos XMLHttpRequest para acompanhar requisições na rede, mas era uma API bem limitada comparada com as necessidades das aplicações modernas que temos hoje em dia. Por outro lado sua desvantagem que ela está presente apenas nos browsers modernos.

Principal diferença que agora com Fetch Api podemos ter objetos específicos para requisições(Request) e repostas(Response). Isso permite que elas sejam utilizadas em diferentes situações como por exemplo, Service Workers e Cache API.

Ela também fornece uma definição para conceitos relacionados, como CORS e semântica de cabeçalhos HTTP.

Utilizando fetch API

Para realizar uma requisição com fetch API, chamamos o método fetch() presente no Window ou em um Worker global. O método tem como parâmetro obrigatório o caminho do arquivo ao qual desejamos requisitar. Agora vamos para um exemplo simples com fetch API:

fetch('/dados.json') .then((response) => console.log(response));

Primeira diferença, é a quantidade de linhas que escrevemos, também a opção de se trabalhar com Promises. No caso acima realizamos uma requisição para o mesmo endereço caso sucesso exibimos em nosso console o tipo de resposta que será seguinte, um objeto do tipo Response com as seguintes informações:

body: (...) bodyUsed: false headers: Headers __proto__: Headers ok: true redirected: false status: 200 statusText: "OK" type: "basic" url: "http://127.0.0.1:5500/dados.json"

Com podemos ver temos o corpo de nossa resposta que terá:

  • Nosso conteúdo
  • Status da requisição e do conteúdo
  • Informações sobre redirecionamento
  • Tipo da requisição
  • Cabeçalho da requisição

Se compararmos como XMLHttpRequest as informações serão as seguinte:

onabort: null onerror: null onload: null onloadend: null onloadstart: null onprogress: null onreadystatechange: null ontimeout: null readyState: 4 response: "{↵ "name":"fellyph",↵ "sobrenome": "cintra",↵ "blog": "https://blog.fellyph.com.br"↵}" responseText: "{↵ "name":"fellyph",↵ "sobrenome": "cintra",↵ "blog": "https://blog.fellyph.com.br"↵}" responseType: "" responseURL: "http://127.0.0.1:5500/dados.json" responseXML: null status: 200 statusText: "OK" timeout: 0 upload: XMLHttpRequestUpload {onloadstart: null, onprogress: null, onabort: null, onerror: null, onload: null, …} withCredentials: false

Como podemos ver temos a informações de requisições, respostas e eventos tudo num lugar só, isso dificulta o tratamento da informação e realiza um consumo de dados desnecessário para o usuário.

Na requisição anterior caso queiramos tratar os dados da resposta fazemos da seguinte forma:

fetch('/dados.json') .then(response => response.json()) .then(data => console.log(data));

Para o tratamento de erros realizamos da seguinte forma, adicionamos um catch na chamada de nosso catch:

fetch('/dados.json') .then(response => response.json()) .then(data => console.log(data)); .catch(error => { console.log('Algo de errado aconteceu:', error ) });

Tipos de requisição

A fetch api pode realizar requisições para diferentes tipos de dados, como texto, images, como processar arquivos de text linha a linha. Além disso podemos enviar informações e realizar upload de arquivos.

Um exemplo de um envio de um arquivo json:

const data = { name: 'fellyph', sobrenome: 'cintra', blog: 'https://blog.fellyph.com.br' }; fetch('/usuario', { method: 'POST', // ou 'PUT' headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data), }) .then(response => response.json()) .then(data => { console.log('Success:', data); }) .catch((error) => { console.error('Error:', error); });

Suporte

Fetch API é suportada por 95% dos browsers, os browsers que não possuem suporte:

  • Internet Explorer 11
  • Edge 13 e inferior

Podemos verificar o suporte da seguinte forma:

if (window.fetch) { // realizamos o request com fetch } else { // utilizamos um fallback }

XMLHttpRequest vs. Fetch API

Eles surgiram em tempos diferentes, por muito tempo XMLHttpRequest deu conta do recado mas com a evolução das aplicações web começamos a ter a necessidade de multiplas requisições, foi que então começamos a ter problemas com correntes de callbacks requisições a diferentes serviços.

Para solucionar esse problema tivemos a introdução de promises e junto a ela tivemos a inclusão de novas APIs que começaram a utilizar esse recurso como Fetch API, Service Worker entre outras Web APIs.

Podemos dizer que Fetch API é a evolução da XMLHttpRequest. Apesar da estrutura ter mudado drasticamente elas possuem o mesmo objetivo solucionar o problema com requisições assíncronas. Além de ser extremamente poderosa.

Para mais tutoriais sobre desenvolvimento web acesse a página da categoria tutoriais.

Categorias
PWA - Progressive web apps Tutoriais

Geolocation API

Vamos falar sobre geolocation esse post servirá como base para o conteúdo do curso de PWA que estou rodando no meu canal. Na versão 2020 do curso iremos abordar Web APIs disponíveis para iOS e nesse primeiro posts iremos abordar a Geolocation web API.

Umas das primeiras web APIs lançadas junto com o HTML5, para termos noção esse recurso estava disponível na versão 5 do Chrome e Safari em 2010. A Geolocation API possui uma série de funções e eventos que permitem a localização do usuário através doso dados: latitude e longitude.

Relatório do “can I use”

Suporte

Esse recurso é totalmente dependente do device do usuário vimos que o recurso é presente 94% dos browsers que suporte alto. Mas a sua precisão depende que o device que possua GPS, caso contrário essa informação será gerada através de cruzamento de dados, por exemplo, rede e endereço IP. Isso significa se o device não possuir suporte essa informações não serão tão precisas.

GPS

Outro ponto importante é o consumo de bateria, para o os dispositivos móveis o acesso ao GPS causa um custo maior de processamento assim aumenta o consumo de bateria, então é importante fazer o uso consciente desse recurso.

Privacidade

Na maioria dos devices esse recurso é dependente de uma conexão HTTPS, também antes do acesso a esse recurso o browser irá requisitar permissão de acesso a Geolocalização do usuário. Como podemos ver na imagem a seguir:

Exemplo pop up de permissão da apple

Ideal caso armazene ou monitore a movimentação do usuário deixe claro o uso desse recurso. Esse recurso também só será acessado em uma aplicação que estiver rodando em um servidor web.

Código

Depois de uma introdução sobre a API agora vamos ver como utiliza-la em nossa aplicação:

navigator.geolocation.getCurrentPosition(geoSuccess, geoError); const geoSuccess = (position) => { console.log(position.coords.latitude, position.coords.longitude); }; const geoError = (error) => { console.log('Error occurred. Error code: ' + error.code); };

No código acima fazem a chamada da api dentro de navigator, podemos conferir se o browser tem suporte a geolocation verificando se o atribulo é nulo mas em 2020 a api está presente na maioria dos browsers então não vou me preocupar como esse ponto.

Chamamos a função get position responsável por requisitar a latitude e longitude do usuário. Ela recebe como parâmetro duas funções uma parar executar caso sucesso ou falha de acesso ao recurso.

Se a requisição for bem sucedida teremos a chamada da função geoSuccess com o retorno da latitude(position.coords.latitude) e longitude(position.coords.longitude). Em caso de erro teremos a chamada da função geoError com os possíveis códigos:

  • 0: erro desconhecido
  • 1: permissão negada
  • 2: erro na resposta da fonte da informação
  • 3: timed out

Essa é uma introdução ao assunto em breve estarei postando um vídeo sobre o assunto em meu canal. Qualquer dúvida deixe um comentário ou continue lendo mais tutoriais na página da categoria.

Referência: MDN Geolocation API

Veja também as aulas sobre o assunto no curso de PWA

Categorias
Web

PWAs em 2020

Todos os anos temos uma compilação dos últimas features referentes a PWA no Google I/O o congresso anual do Google para desenvolvedores. No último ano 2019 confesso que não fiquei muito empolgado com os lançamentos relacionados a PWA no Google I/O, mas analisando por um outro lado é o resultado de uma maturidade do conceito PWA.

Progressive web apps em si, já tem sua base, com Service Workers e Web manifest não temos muito o que mudar. Saber dos valores de criar apps rápidos, seguros e que cativem o usuário, por fim, temos a evolução das Web APIs esse é um ponto que ainda terá uma evolução, as Web APIs nos permitem implementar recursos antes só possíveis com aplicações nativas esse ponto irei falar mais pra frente.

Por conta da situação que estamos passando as principais conferências no mundo foram canceladas e o Google I/O também está incluso nessa lista então não teremos um evento principal com anúncio de novas features relacionadas a PWAs, mas esse ano acredito que teremos lançamentos menores com seguindo as versões do Chrome e numa previsão otimista teremos um Chrome Summit online.

Releases do Chrome

Com toda a situação com o covid-19 o calendário de lançamentos do Chrome foi alterado, tivemos na última semana a versão 81 sendo lançada com suporte em versão de teste a NFC e suporte total a badging api, mas Google anunciou que irá pular a versão 82 atrasando o anuncio de alguns novos recursos em 6 semanas, mas o Google irá trabalhar apenas em bugs e correções de segurança durante esse período e somente lançar a versão 83. Se a situação se normalizar eles voltarão ao ciclo de 6 semanas.

Projeto Fugu

Apresentação do Projeto Fugu no I/O 2019

Projeto Fugu, é um projeto que visa habilitar na plataforma web recursos que eram somente possíveis com apps nativos uma série de empresas estão envolvidas nesse processo. Mas Claro que os releases do Chrome influenciam na implementação de recursos PWA eles são responsáveis pelos browsers Android e recentemente é o motor por trás do Microsoft Edge.

Com a adoção do Edge ao Chromium aumentou a quantidade de desenvolvedores, assim dando um fôlego maior ao Projeto Fugu na implementação de novas web APIs. Não só apenas Google e Microsoft contribuem com o Projeto Fugu, mas temos empresas como Intel e Samsung como contribuidores.

Google compartilhar uma lista pública de quando as funcionalidades serão implementadas no Chrome, que você confere aqui: https://docs.google.com/spreadsheets/d/1de0ZYDOcafNXXwMcg4EZhT0346QM-QFvZfoD8ZffHeA/edit#gid=557099940

O legal dessa lista é atualizada a cada release do chrome, outro ponto importante você também pode contribuir com sugestões de features: https://developers.google.com/web/updates/capabilities

Recursos para PWAs já lançados em 2020(Abril)

  • Web Share API target
  • Contact Picker API
  • Periodic Background Sync
  • Web OTP API – Screen Lock
  • Clipboard para imagens
  • Launch keyboard Map API

Recursos da Web API previstas para 2020

  • Web NFC
  • Content Index API
  • Screen enumeration API
  • File Handling API
  • getInstalledRelatedApps
  • Native File system API
  • WakeLock API – Screen Lock
  • Shape detection API

iOS

Quase contra-mão o Webkit trabalha de forma isolada, tratando de recursos que a Apple acha prioridade para o safari, por exemplo, na última versão do safari 13.1 tivemos a inclusão de recursos como:

  • Async Clipboard API
  • Picture-in-Picture API
  • Remote Playback API

Muitas empresas já viram o benefício de se investir em PWAs, mas a Apple evita de mencionar o termo PWA por conta de ser um termo vindo do Google para definir o conceito. Segundo acredito no ponto de vista relacionado ao business atual da empresa que a Apple Store, como ela irá encaixar PWAs com apps nativos.

Particularmente acredito que a Apple continuará implementando novos recursos da Web API quando é de seu interesse e a tentará uma implementação da formula diferente da apresentada pelo Google. Mas 2020 ainda não será o ano que teremos full suporte pela Apple. Para saber mais sobre PWA confira a página do curso de Progressive web Apps.