Como processar solicitações de navegação

Responda a solicitações de navegação sem esperar pela rede usando um service worker.

As solicitações de navegação são solicitações de documentos HTML feitas pelo navegador sempre que você insere um novo URL na barra de navegação ou segue um link em uma página que leva a um novo URL. É aqui que os service workers têm o maior impacto no desempenho: se você usar um service worker para responder a solicitações de navegação sem esperar pela rede, poderá garantir que as navegações sejam confiáveis e rápidas, além de resilientes quando a rede estiver indisponível. Essa é a maior vantagem de desempenho vinda de um worker de serviço, em comparação com o que é possível com o armazenamento em cache HTTP.

Conforme detalhado no guia Identificar recursos carregados da rede, uma solicitação de navegação é a primeira de muitas solicitações feitas na cascata de tráfego de rede. O HTML carregado por uma solicitação de navegação inicia o fluxo de todas as outras solicitações de subrecursos, como imagens, scripts e estilos.

No manipulador de eventos fetch de um worker de serviço, é possível determinar se uma solicitação é uma navegação verificando a propriedade request.mode no FetchEvent. Se ele estiver definido como 'navigate', será uma solicitação de navegação.

Como regra geral, não use Cache-Control headers de longa duração para armazenar em cache a resposta HTML de uma solicitação de navegação. Normalmente, elas precisam ser atendidas pela rede com Cache-Control: no-cache para garantir que o HTML, junto com a cadeia de solicitações de rede subsequentes, esteja (razoavelmente) atualizado. Ir contra a rede toda vez que o usuário navega para uma nova página significa que cada navegação pode ser lenta. Isso significa que não será confiável.

Diferentes abordagens para arquiteturas

Descobrir como responder a solicitações de navegação evitando a rede pode ser complicado. A abordagem certa depende muito da arquitetura do seu site e do número de URLs exclusivos para os quais os usuários podem navegar.

Embora não exista uma solução única, as diretrizes gerais a seguir podem ajudar você a decidir qual abordagem é a mais viável.

Sites estáticos pequenos

Se o app da Web consistir em um número relativamente pequeno (pense em algumas dezenas) de URLs exclusivos e cada um desses URLs corresponder a um arquivo HTML estático diferente, uma abordagem viável é armazenar em cache todos esses arquivos HTML e responder às solicitações de navegação com o HTML em cache apropriado.

Com o pré-cache, é possível armazenar o HTML em cache com antecedência, assim que o service worker for instalado, e atualizar o HTML em cache sempre que você recriar o site e implantar o service worker novamente.

Como alternativa, se você preferir evitar o pré-cache de todo o HTML, talvez porque os usuários tendem a acessar apenas um subconjunto de URLs no seu site, use uma estratégia de armazenamento em cache de execução stale-while-revalidate. No entanto, tenha cuidado com essa abordagem, porque cada documento HTML é armazenado em cache e atualizado separadamente. O uso do armazenamento em cache de execução para HTML é mais adequado se você tiver um pequeno número de URLs que são revisitados com frequência pelo mesmo conjunto de usuários e se você se sentir confortável com esses URLs sendo revalidados independentemente uns dos outros.

Apps de página única

Uma arquitetura de página única é frequentemente usada por aplicativos da Web modernos. Nele, o JavaScript do lado do cliente modifica o HTML em resposta às ações do usuário. Esse modelo usa a API History para modificar o URL atual à medida que o usuário interage com o app da Web, levando a uma navegação "simulada". Embora as navegações subsequentes possam ser "falsas", a navegação inicial é real, e ainda é importante verificar se ela não está bloqueada na rede.

Felizmente, se você estiver usando a arquitetura de página única, há um padrão simples a seguir para exibir a navegação inicial do cache: o shell do aplicativo. Nesse modelo, o service worker responde às solicitações de navegação retornando o mesmo arquivo HTML único que já foi pré-armazenado em cache, independentemente do URL solicitado. Esse HTML precisa ser básico, consistindo, talvez, de um indicador de carregamento genérico ou de conteúdo esquelético. Depois que o navegador carregar esse HTML do cache, o JavaScript do lado do cliente assumirá e renderizará o conteúdo HTML correto para o URL da solicitação de navegação original.

O Workbox fornece as ferramentas necessárias para implementar essa abordagem. O navigateFallback option permite especificar qual documento HTML usar como shell do app, junto com uma lista opcional de permissões e negações para limitar esse comportamento a um subconjunto de URLs.

Apps de várias páginas

Se o servidor da Web gerar o HTML do site de forma dinâmica ou se você tiver mais de algumas dezenas de páginas únicas, será muito mais difícil evitar a rede ao processar solicitações de navegação. As sugestões em Tudo o mais provavelmente se aplicam a você.

No entanto, para um determinado subconjunto de apps com várias páginas, talvez seja possível implementar um service worker que replique totalmente a lógica usada no servidor da Web para gerar HTML. Isso funciona melhor se você puder compartilhar informações de roteamento e modelos entre os ambientes do servidor e do worker de serviço e, em particular, se o servidor da Web usar JavaScript (sem depender de recursos específicos do Node.js, como acesso ao sistema de arquivos).

Se o servidor da Web se enquadra nessa categoria e você quer explorar uma abordagem para mover a geração de HTML da rede para o service worker, as orientações em Além de SPAs: arquiteturas alternativas para sua PWA podem ajudar.

Todos os outros

Se você não conseguir responder às solicitações de navegação com HTML em cache, tome medidas para garantir que adicionar um worker de serviço ao seu site (para processar outras solicitações que não sejam HTML) não vai acabar atrasando suas navegações. A inicialização do service worker sem usá-lo para responder a uma solicitação de navegação vai introduzir uma pequena quantidade de latência (conforme explicado em Como criar apps mais rápidos e resilientes com o service worker). É possível reduzir essa sobrecarga ativando um recurso chamado pré-carregamento de navegação e, em seguida, usando a resposta de rede que foi pré-carregada no manipulador de eventos fetch.

O Workbox oferece uma biblioteca auxiliar que detecta se o pré-carregamento de navegação é compatível. Se for, simplifica o processo de informar ao service worker para usar a resposta da rede.

Foto de Aaron Burden no Unsplash