Como processar solicitações de navegação

Responda a solicitações de navegação sem esperar na 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. É aí que os service workers têm o maior impacto na performance: 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 rápidas e confiáveis, além de serem resilientes quando a rede estiver indisponível. Essa é a maior vantagem de desempenho de um service worker 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 potencialmente 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 sub-recursos, como imagens, scripts e estilos.

No manipulador de eventos fetch de um service worker, é possível determinar se uma solicitação é uma navegação verificando a propriedade request.mode no FetchEvent. Se 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, seja (razoavelmente) atualizado. Infelizmente, acessar a rede sempre que o usuário navega para uma nova página significa que cada navegação pode ser lenta. No mínimo, isso significa que ele não será confiavelmente rápido.

Abordagens diferentes para arquiteturas

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

Embora não haja uma solução única para todos os casos, 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 tiver um número relativamente pequeno (pense em algumas dezenas) de URLs exclusivos, e cada um deles corresponder a um arquivo HTML estático diferente, uma abordagem viável é apenas armazenar em cache todos esses arquivos HTML e responder às solicitações de navegação com o HTML armazenado em cache apropriado.

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

Como alternativa, se você preferir evitar o pré-armazenamento em cache de todo o HTML, talvez porque os usuários tendem a navegar apenas para um subconjunto de URLs no site, use uma estratégia de armazenamento em cache de ambiente de execução stale-while-revalidate. No entanto, tenha cuidado com essa abordagem, já que cada documento HTML é armazenado em cache e atualizado separadamente. O uso do armazenamento em cache de ambiente de execução para HTML é mais apropriado 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 a revalidação desses URLs de forma independente.

Apps com apenas uma página

Uma arquitetura de página única é frequentemente usada por aplicativos da web modernos. Nela, 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 conforme o usuário interage com o app da Web, o que resulta em uma navegação "simulada". Embora as navegações subsequentes possam ser "falsas", a navegação inicial é real, e ainda é importante garantir que ela não seja bloqueada na rede.

Felizmente, se você estiver usando a arquitetura de página única, há um padrão simples a ser seguido 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, composto, talvez, por um indicador de carregamento genérico ou um conteúdo de esqueleto. Depois que o navegador carregar esse HTML do cache, o JavaScript do lado do cliente vai assumir o controle e renderizar o conteúdo HTML correto para o URL da solicitação de navegação original.

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

Apps de várias páginas

Se o servidor da Web gera o HTML do site de forma dinâmica ou se você tem mais do que algumas dezenas de páginas exclusivas, é muito mais difícil evitar a rede ao processar solicitações de navegação. As orientações em Outros casos provavelmente se aplicam a você.

No entanto, para um determinado subconjunto de apps de várias páginas, é 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 service worker 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 enquadrar nessa categoria e você quiser conhecer 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 seu PWA podem ajudar você a começar.

Todos os outros

Se não for possível responder às solicitações de navegação com HTML em cache, tome medidas para garantir que a adição de um service worker ao site (para processar outras solicitações que não sejam HTML) não acabe deixando as navegações mais lentas. Iniciar o service worker sem usá-lo para responder a uma solicitação de navegação introduz uma pequena latência, conforme explicado em Como criar apps mais rápidos e resilientes com o service worker (link em inglês). Para reduzir essa sobrecarga, ative um recurso chamado pré-carregamento de navegação e use a resposta da rede pré-carregada no manipulador de eventos fetch.

O Workbox oferece uma biblioteca auxiliar que detecta se o pré-carregamento de navegação é compatível e, em caso afirmativo, simplifica o processo de instruir o service worker a usar a resposta da rede.