Como processar solicitações de navegação

Responda às 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 direciona para um novo URL. É aqui que os service workers causam maior impacto no desempenho: se você usa um service worker para responder a solicitações de navegação sem esperar pela rede, é possível garantir que as navegações sejam rápidas e confiáveis, além de serem resilientes quando a rede não está disponí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 "hierarquia" do tráfego de rede. O HTML carregado por meio de uma solicitação de navegação inicia o fluxo de todas as outras solicitações de sub-recursos, como imagens, scripts e estilos.

Dentro do 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 ela estiver definida como 'navigate', será uma solicitação de navegação.

Como regra geral, não use Cache-Control headers de longa duração para armazenar a resposta HTML em cache para uma solicitação de navegação. Normalmente, eles são atendidos pela rede, com Cache-Control: no-cache, para garantir que o HTML e a cadeia de solicitações de rede subsequentes sejam (razoavelmente) atualizados. Incorrer na rede sempre que o usuário navega para uma nova página, infelizmente, significa que a navegação pode ser lenta. No mínimo, isso significa que ele não será rápido de maneira confiável.

Diferentes abordagens para arquiteturas

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

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

Sites estáticos pequenos

Caso seu app da Web consista em um número relativamente pequeno de URLs exclusivos (algumas dúzias) e cada um desses URLs corresponda a um arquivo HTML estático diferente, uma abordagem viável é simplesmente armazenar em cache todos esses arquivos HTML e responder às solicitações de navegação com o HTML adequado em cache.

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

Como alternativa, se você preferir evitar o armazenamento prévio de todo o HTML em cache, talvez porque os usuários tendem a acessar apenas um subconjunto de URLs no seu site, use uma estratégia de armazenamento em cache desatualizado durante a revalidação. No entanto, tenha cuidado com essa abordagem, porque cada documento HTML individual é armazenado em cache e atualizado separadamente. Usar o armazenamento em cache no tempo de execução para HTML é mais apropriado se você tem um pequeno número de URLs que são acessados com frequência pelo mesmo conjunto de usuários e se você se sente confortável em saber que esses URLs são revalidados independentemente um do outro.

Apps com uma única página

A arquitetura de uma única página é usada com frequência 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 ao que é efetivamente 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 esteja bloqueada na rede.

Se você usa 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 que já foi armazenado em cache, independentemente do URL solicitado. Esse HTML precisa ser simples, consistindo, talvez, um indicador de carregamento genérico ou conteúdo esqueleto. Depois que o navegador carregar esse HTML a partir do cache, o JavaScript existente do lado do cliente assumirá o controle e processará o conteúdo HTML correto para o URL da solicitação de navegação original.

A caixa de trabalho fornece 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 negações para limitar esse comportamento a um subconjunto de URLs.

Apps com várias páginas

Se o servidor da Web gerar o HTML do site dinamicamente ou se você tiver várias páginas exclusivas, será muito mais difícil evitar a rede ao processar solicitações de navegação. O conselho em Todo o restante provavelmente se aplicará a você.

No entanto, para um determinado subconjunto de aplicativos de várias páginas, você pode implementar um service worker que replica totalmente a lógica usada no seu 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 especial, se o servidor da Web usar JavaScript (sem depender de recursos específicos do Node.js, como o 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 dos SPAs: arquiteturas alternativas para seu PWA podem ajudar você.

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 seu site (para processar outras solicitações não HTML) não atrase a navegação. Se o service worker for iniciado sem usá-lo para responder a uma solicitação de navegação, uma pequena quantidade de latência será introduzida, 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 dentro do manipulador de eventos fetch.

O Workbox fornece uma biblioteca auxiliar que detecta se há suporte ao pré-carregamento de navegação e, em caso afirmativo, simplifica o processo de informar ao service worker para usar a resposta de rede.

Foto de Aaron Burden no Unsplash