Angular - Estratégias de roteamento e History API

Paulo Lôbo - Aug 15 - - Dev Community

Aviso: todo e qualquer conteúdo postado é com objetivo de relembrar ou manter os meus conhecimentos e espero que possa te ajudar na sua caminhada pelo aprendizado também.
Esse post é vivo e será atualizado periodicamente.
Caso você encontre alguma falha ou perceba que falta algo, me ajude a melhorar :)


Veja um resumo do passo a passo que o angular faz para realizar o roteamento de uma aplicação:

  1. Configuração de Rotas: primeiro, você define as rotas no módulo de roteamento com RouterModule.forRoot(routes);
  2. Serviço Router: depois, você utiliza os serviços do Router para realizar a navegação;
  3. Atualização da URL: em seguida o angular atualiza a History API e também atualiza a url na barra de endereços do navegador, ou não(falo dele no final);
  4. Correspondência de Rotas: O angular compara a URL com as rotas definidas e carrega o componente correspondente;
  5. Renderização e Detecção de Mudanças: Por fim, renderiza o componente e atualiza o DOM.

Tipos de estratégias

Os frontends SPAs possuem 2 estratégias mais comuns de roteamento:
HashLocationStrategy(Hash mode) e PathLocationStrategy(History mode).

Para quem já trabalha com SPAs no dia-a-dia sabe bem a diferença mais básica das duas estratégias:

PathLocationStrategy (History Mode)

As URLs seguem o padrão tradicional de navegação na web, sem nenhum #. Por exemplo:
https://paulo.com/home.

HashLocationStrategy (Hash Mode):

As URLs incluem um # seguido do caminho. O que vem após o # não é enviado ao servidor e é tratado inteiramente pelo navegador.
Exemplo de URL: https://paulo.com/#/home.

O PathLocationStrategy é a configuração default do angular, e caso deseje utilizar a estratégia de hash, precisará declarar assim no seu arquivo de rotas:

RouterModule.forRoot(routes, {useHash: true})
Enter fullscreen mode Exit fullscreen mode

Há alguns debates sobre o melhor uso de cada um. Alguns comentam sobre a estratégia de se utilizar o HashLocation somente em arquitetura SSR e outros que entendem que traz mais simplicidade e por isso o utilizam em todos os cenários, mas não vou entrar nesse detalhe. Fica a dica caso se interesse em procurar mais sobre a discussão :)


History API

Por baixo dos panos o angular usa a History API para se comunicar com o roteamento do navegador.

Link para implementação da PathLocationStrategy

Imagem mostrando o acionamento do angular durante uma mudança de rota, usando estratégia de pathlocation:
Imagem mostrando o acionamento do angular durante uma mudança de rota

Link para implementação da HashLocationStrategy

Imagem mostrando o acionamento do angular durante uma mudança de rota, usando estratégia de hashlocation:
Imagem mostrando o acionamento do angular durante uma mudança de rota

A History é uma interface/API do navegador que permite manipular o histórico de navegação do usuário sem recarregar a página. Ela foi introduzida com a especificação do HTML5 e oferece um conjunto de métodos para adicionar, modificar ou remover entradas do histórico do navegador, além de responder a mudanças no estado da navegação.

Veja:

na imagem é mostrada a url localhost:4200 e no console do navegador é mostrado o tamanho do objeto history api, utilizando o history.length. O history.length possui o tamanho igual a 1
na imagem é mostrada a url localhost:4200/componentA e no console do navegador é mostrado o tamanho do objeto history api, utilizando o history.length. O history.length possui o tamanho igual a 2
na imagem é mostrada a url localhost:4200/componentB e no console do navegador é mostrado o tamanho do objeto history api, utilizando o history.length. O history.length possui o tamanho igual a 3

repare que a cada mudança de rota, o objeto "history" vai sendo incrementado.

Tanto o location(import { Location } from "@angular/common"), quanto o router(import { Router } from "@angular/router")acionam/comunicam com a History API

Isso ocorre porque toda vez que navegamos para uma rota qualquer, o angular aciona o platformLocation, que por sua vez, aciona o método history.pushState. Da mesma forma, o método history.replaceState é invocado toda vez que utilizamos o replaceUrl.

Um ponto interessante é que o angular também atualiza o objeto Location.
O Location mantém todos os dados da rota durante a navegação.

Repare, que ao usar o PathLocation, o objeto location mostra o pathname que correlaciona com a mesma rota na url do navegador:
a imagem mostra o console.log do location que correlaciona com a mesma rota na url do navegador

Já ao usar o hashlocation, o pathname fica sempre vazio e somente o atributo "hash" é alterado:
a imagem mostra o console.log do location que correlaciona com a mesma rota na url do navegador.

Em breve solto um post sobre a importância na escolha das estratégias ao criar um app Server Side Rendering(https://angular.dev/guide/ssr).

Uma observação importante é que apesar da History API conseguir suprir as principais necessidades e servir para os frontends SPA’s mais atuais, a partir do momento que avançamos para alguns cenários, como a própria necessidade de se realizar a observabilidade de um SPA, notamos algumas debilidades nessa API. Para sanar esses problemas, uma nova proposta de substituição dessa API está em andamento, que é a Navigation API. Ela ainda está em fase experimental e falaremos mais dela no post sobre monitoramento e performance de SPA.


SkipLocationChange

Lembra do que escrevi sobre o angular acionar o histórico.pushState?
O que essa opção faz é garantir que o conteúdo seja renderizado na tela, mas dessa vez sem acionar o método history.pushstate que é responsável por definir a URL do navegador. Só o status interno do Router que será atualizado. Nesse caso, o navegador não sabe que houve mudança no histórico.

Vamos a um exemplo…
Repare que,

o history.state possui tamanho == 1
imagem mostrando o tamanho do objeto history.state

E quando navego para uma próxima rota com o skipLocation ativo(
this.router.navigate(['componentA'], {skipLocationChange: true});
), ele não altera a url e nem o estado da api de histórico
imagem mostrando o tamanho do objeto history.state

no entanto, quando acessamos os eventos que o router emite, é possível ver que o estado interno do Router está atualizado
imagem mostrando o tamanho do objeto history.state e também mostrando o console.log do objeto activatedRoute

Dessa forma, somente o angular tem o estado mais atual e o navegador não possui a informação mais atualizada.


Eu espero que tenha gostado e te ajudado a melhorar a compreensão de algo ou até mesmo aberto caminhos para novos conhecimentos. Conto com você nas críticas e sugestões para irmos melhorando o conteúdo e mantendo sempre atualizado para a comunidade.

. .
Terabox Video Player