Arquitetura

Para projetar seu aplicativo para aproveitar ao máximo a tecnologia que torna os PWAs confiáveis, instaláveis e capazes, comece entendendo o aplicativo e as restrições dele, além de escolher uma arquitetura adequada para ambos.

SPA x MPA

Atualmente, existem dois padrões principais de arquitetura no desenvolvimento da Web: aplicativos de página única, ou SPAs, e aplicativos de várias páginas, ou MPAs.

Apps de página única são definidos porque o JavaScript do lado do cliente controla a maior parte ou toda a renderização HTML de uma página com base nos dados recuperados ou fornecidos pelo app. O app substitui a navegação integrada do navegador, substituindo-a pela funcionalidade de roteamento e gerenciamento de visualizações.

Apps com várias páginas geralmente têm HTML pré-renderizado enviado diretamente ao navegador, muitas vezes aprimorado com JavaScript do lado do cliente após o navegador terminar de carregar o HTML, e contando com os mecanismos de navegação integrados do navegador para exibir visualizações subsequentes.

Ambas as arquiteturas podem ser usadas para criar PWAs.

Cada um tem vantagens e desvantagens. Escolher o melhor para seu caso de uso e contexto é fundamental para fornecer uma experiência rápida e confiável aos usuários.

Apps de página única

Prós
  • Principalmente atualizações in-page atômicas.
  • Dependências do lado do cliente carregadas na inicialização.
  • Os carregamentos subsequentes são rápidos devido ao uso do cache.
Desvantagens
  • Alto custo de carregamento inicial.
  • O desempenho depende do hardware do dispositivo e da conexão de rede.
  • É necessária uma complexidade adicional do aplicativo.

Os apps de página única são uma boa opção de arquitetura se:

  • A interação do usuário se concentra principalmente em atualizações atômicas de dados interconectados exibidos na mesma página, por exemplo, em um painel de dados em tempo real ou em um app de edição de vídeo.
  • Seu aplicativo tem dependências de inicialização apenas no lado do cliente, por exemplo, um provedor de autenticação de terceiros com um custo de inicialização incrivelmente alto.
  • Os dados necessários para o carregamento de uma visualização dependem de um contexto específico do lado do cliente, por exemplo, a exibição de controles para um hardware conectado.
  • O app é pequeno e simples o bastante para que o tamanho e a complexidade não afetem os contras listados acima.

Os SPAs podem não ser uma boa opção de arquitetura nos seguintes casos:

  • O desempenho do carregamento inicial é essencial. Os SPAs geralmente precisam carregar mais JavaScript para determinar o que deve ser carregado e como exibir. O tempo de análise e execução desse JavaScript, combinado com a recuperação do conteúdo, é mais lento do que o envio do HTML renderizado.
  • O app é executado principalmente em dispositivos com velocidades baixas ou médias. Como os SPAs dependem do JavaScript para renderização, a experiência do usuário depende muito mais da potência do dispositivo do que de uma MPA.

Como os SPAs precisam substituir a navegação integrada do navegador pelo roteamento, eles exigem um nível mínimo de complexidade para atualizar com eficiência a visualização atual, gerenciar mudanças de navegação e limpar visualizações anteriores que, de outra forma, seriam gerenciadas pelo navegador, o que dificulta a manutenção e exige mais do usuário.

Apps com várias páginas

Prós
  • Principalmente atualizações de página inteira.
  • A velocidade de renderização inicial é fundamental.
  • O script do lado do cliente pode ser uma melhoria.
Desvantagens
  • As visualizações secundárias exigem outra chamada de servidor.
  • O contexto não é transferido entre as visualizações.
  • Requer um servidor ou pré-renderização.

Apps com várias páginas são uma boa opção de arquitetura se:

  • A interação do usuário se concentra principalmente em visualizações de um único dado com dados opcionais baseados em contexto, por exemplo, um app de notícias ou de e-commerce.
  • A velocidade de renderização inicial é fundamental, pois enviar o HTML já renderizado ao navegador é mais rápido do que montá-lo a partir de uma solicitação de dados após o carregamento, a análise e a execução de uma alternativa baseada em JavaScript.
  • A interatividade ou o contexto do cliente pode ser incluído como uma melhoria após o carregamento inicial. Por exemplo, a inserção de um perfil em uma página renderizada ou a adição de componentes secundários dependentes do contexto do cliente.

As MPAs podem não ser uma boa escolha de arquitetura se:

  • Fazer o download, analisar novamente e executar novamente seu JavaScript ou CSS é extremamente caro. Essa desvantagem é reduzida nos PWAs com service workers.
  • O contexto do lado do cliente, como a localização do usuário, não se transfere perfeitamente entre as visualizações, e conseguir esse contexto pode ser caro. Ele precisa ser capturado e recuperado ou solicitado novamente entre as visualizações.

Porque visualizações individuais precisam ser renderizadas dinamicamente por um servidor ou pré-renderizadas antes do acesso, o que pode limitar a hospedagem ou aumentar a complexidade dos dados.

Qual escolher?

Mesmo com esses prós e contras, ambas as arquiteturas são válidas para criar seu PWA. É possível até misturá-las para diferentes partes do seu aplicativo, dependendo das necessidades dele. Por exemplo, fazer com que as páginas "Detalhes do app" sigam uma arquitetura de MPA e o fluxo de finalização de compra siga uma arquitetura de SPA.

Seja qual for a escolha, o próximo passo é entender como melhor usar os service workers para proporcionar a melhor experiência.

O poder do service worker

O service worker tem muito poder além do roteamento básico e entrega de respostas em cache e de rede. Podemos criar algoritmos complexos que podem melhorar a experiência e o desempenho do usuário.

O service worker inclui (SWI)

Um padrão emergente para usar service workers como parte integrante da arquitetura de um site é a inclusão de service workers (SWI). O SWI divide os recursos individuais, geralmente uma página HTML, em partes com base nas necessidades de armazenamento em cache e os agrupa no service worker para melhorar a consistência, o desempenho e a confiabilidade, reduzindo o tamanho do cache. Um site com um cabeçalho global, uma área de conteúdo, uma barra lateral e um rodapé.

Esta imagem é um exemplo de página da Web. Ela tem cinco seções diferentes que dividem a página em:

  • Layout geral.
  • Cabeçalho global (barra escura superior).
  • Área de conteúdo (linhas à esquerda no meio e imagem).
  • Barra lateral (barra alta em tom escuro médio no meio direito).
  • Rodapé (barra inferior escura).

Layout geral

O layout geral provavelmente não vai mudar com frequência e não tem dependências. Ele é um bom candidato para o pré-armazenamento em cache.

O cabeçalho e o rodapé globais contêm itens como o menu superior e o rodapé do site, e apresentam um desafio específico: se a página fosse armazenada em cache como um todo, eles podem mudar entre os carregamentos de página, dependendo de quando a página foi armazenada em cache.

Ao separar e armazenar em cache independentemente do conteúdo, você garante que os usuários sempre recebam a mesma versão, independentemente de quando forem armazenados em cache. Como são atualizados com pouca frequência, eles também são bons candidatos para o pré-armazenamento em cache. No entanto, eles têm uma dependência: o CSS e o JavaScript do site.

CSS e JavaScript

O ideal é que o CSS e o JavaScript do site sejam armazenados em cache com uma estratégia desatualizada durante a revalidação para permitir atualizações incrementais sem precisar atualizar o service worker, como é o caso com recursos pré-armazenados em cache. Ainda assim, eles também precisam ser mantidos em uma versão mínima sempre que o service worker é atualizado com um novo cabeçalho ou rodapé global. Por isso, o cache também precisa ser atualizado com a versão mais recente dos recursos quando o service worker é instalado.

Área de conteúdo

Em seguida, temos a área de conteúdo. Dependendo da frequência das atualizações, usar a rede primeiro ou ficar desatualizada durante a revalidação é uma boa estratégia. As imagens precisam ser armazenadas em cache com uma estratégia que prioriza o cache, conforme discutido anteriormente.

Por fim, presumindo que o conteúdo da barra lateral contém conteúdo secundário, como tags e itens relacionados, ele não é suficientemente importante para extrair da rede. Uma estratégia de revalidação desatualizada funciona para isso.

Depois de passar por tudo isso, talvez você esteja pensando que só é possível fazer esse tipo de armazenamento em cache por seção para aplicativos de página única. Mas, ao adotar padrões inspirados em Inclusões de borda ou Inclusões do lado do servidor no seu service worker, com alguns recursos avançados, você pode fazer isso para qualquer arquitetura.

Sua vez de tentar

Você pode testar o que o service worker inclui no próximo codelab:

Respostas de streaming

A página anterior poderia ser criada usando o modelo de shell do app no contexto do SPA, onde o shell do app é armazenado em cache e, em seguida, veiculado e o conteúdo é carregado no lado do cliente. Com a introdução e a ampla disponibilidade da API Streams, tanto o shell do app quanto o conteúdo podem ser combinados no service worker e transmitidos para o navegador, oferecendo a flexibilidade de armazenamento em cache do shell do app com a velocidade dos MPAs.

Isso acontece pelos seguintes motivos:

  • Os streams podem ser criados de modo assíncrono, permitindo que diferentes partes de um stream venham de outras origens.
  • O solicitante de um stream pode começar a trabalhar na resposta assim que o primeiro bloco de dados estiver disponível, em vez de esperar que o item inteiro seja concluído.
  • Analisadores otimizados para streaming, incluindo o navegador, podem exibir progressivamente o conteúdo do stream antes que ele seja concluído, acelerando o desempenho percebido da resposta.

Graças a essas três propriedades de streams, as arquiteturas criadas com streaming geralmente têm uma performance percebida mais rápida do que as demais.

Trabalhar com a API Streams pode ser um desafio, já que ela é complexa e de baixo nível. Felizmente, o módulo Workbox pode ajudar a configurar respostas de streaming para seus service workers.

Domínios, origens e escopo do PWA

Web workers, incluindo service workers, armazenamento e até mesmo uma janela de PWA instalado, são todos regidos por um dos mecanismos de segurança mais importantes da Web: a política de mesma origem. Dentro da mesma origem, as permissões são concedidas, os dados podem ser compartilhados e o service worker pode se comunicar com clientes diferentes. Fora da mesma origem, as permissões não são concedidas automaticamente, e os dados ficam isolados e não podem ser acessados entre origens diferentes.

Política de mesma origem

Dois URLs são definidos como tendo a origem exata se o protocolo, a porta e o host forem os mesmos.

Por exemplo: https://squoosh.app e https://squoosh.app/v2 têm a mesma origem, mas http://squoosh.app, https://squoosh.com, https://app.squoosh.app e https://squoosh.app:8080 estão em origens diferentes. Consulte a referência da MDN da política de mesma origem para mais informações e exemplos.

Alterar subdomínios não é a única maneira de um host. Cada host é composto por um domínio de nível superior (TLD), um domínio de nível secundário (SLD) e zero ou mais rótulos (às vezes chamados de subdomínios), separados por pontos e lidos da direita para a esquerda em um URL. Qualquer alteração em qualquer um dos itens resulta em um host diferente.

No módulo de gerenciamento de janelas, já vimos a aparência do navegador no app quando um usuário navega para uma origem diferente de um PWA instalado.

Esse navegador vai aparecer mesmo que os sites tenham o mesmo TLD e SLD, mas com rótulos diferentes, porque são considerados origens diferentes.

Um dos principais aspectos de uma origem em um contexto de navegação na Web é a forma como o armazenamento e as permissões funcionam. Uma origem compartilha muitos recursos entre todo o conteúdo e PWAs dentro dela, incluindo:

  • Cota e dados de armazenamento (IndexedDB, cookies, armazenamento na Web, armazenamento em cache).
  • Registros de service workers.
  • Permissões concedidas ou negadas (como push da Web, geolocalização, sensores).
  • Registros de push na Web.

Quando você passa de uma origem para outra, todo o acesso anterior é revogado. Portanto, as permissões precisam ser concedidas novamente, e o PWA não pode acessar todos os dados salvos no armazenamento.

Recursos