DEV Community

Cover image for Angular - Estratégias de roteamento e History API
Paulo Lôbo
Paulo Lôbo

Posted on • Edited on

Angular - Estratégias de roteamento e History API

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.

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay