Fala, comunidade dev! 👋
No primeiro artigo da nossa série sobre a evolução arquitetural de um YMS (do Angular 16 para a versão 21), mostrei como deletamos o app.module.ts e abraçamos os Standalone Components. Se você perdeu, recomendo dar uma olhada lá antes de seguir.
Mas depois de remover o módulo principal, uma dúvida natural surge: como fica o roteamento? Afinal, a navegação de um sistema corporativo gigantesco costuma ser um emaranhado complexo de rotas protegidas e carregamento sob demanda (Lazy Loading).
Neste artigo, vou detalhar como o roteamento no Angular deixou de ser verboso para se tornar uma das APIs mais elegantes do ecossistema Front-end.
1. Lazy Loading sem Módulos: Mais direto e eficiente
No passado, para não carregar o YMS inteiro no primeiro clique do usuário, nós usávamos o Lazy Loading apontando para Módulos. O código era mais ou menos assim:
O Antes (Baseado em Módulos):
const routes: Routes = [
{
path: 'balanca',
loadChildren: () => import('./balanca/balanca.module').then(m => m.BalancaModule)
}
];
Agora que nossos componentes são independentes e gerenciam suas próprias dependências, não precisamos mais do intermediário (o módulo). O Angular introduziu o loadComponent para rotas simples e modernizou o loadChildren para carregar um arquivo de rotas filhas diretas.
O Depois (Standalone):
const routes: Routes = [
// Carregando um único componente preguiçosamente
{
path: 'dashboard',
loadComponent: () => import('./dashboard/dashboard.component').then(c => c.DashboardComponent)
},
// Carregando um grupo de rotas preguiçosamente
{
path: 'balanca',
loadChildren: () => import('./balanca/balanca.routes').then(r => r.BALANCA_ROUTES)
}
];
A mudança parece sutil, mas arquiteturalmente é brilhante. Você carrega apenas a árvore de componentes que a tela exige, potencializando o Tree-Shaking que discutimos no artigo anterior.
2. O Fim das Classes Guards: A verdadeira revolução silenciosa
Se o Lazy Loading ficou mais limpo, a segurança de rotas sofreu uma transformação radical. Em um YMS, temos dezenas de bloqueios: verificar se o usuário está logado, se ele tem permissão de "Operador de Balança" ou se a Ordem de Pesagem está no status correto para ser acessada.
Até o Angular 14/15, nós éramos obrigados a criar Classes Guards. Isso gerava um boilerplate imenso:
- Criar uma classe.
- Usar o decorator
@Injectable(). - Implementar a interface
CanActivate. - Injetar serviços no
constructor.
O Antes (Verboso e pesado):
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(): boolean {
if (this.authService.isLoggedIn()) {
return true;
}
this.router.navigate(['/login']);
return false;
}
}
No Angular 21, as classes Guards foram totalmente substituÃdas por Functional Guards.
Uma Guard agora é apenas uma função pura. Para acessar serviços dentro dessa função, o Angular nos deu a mágica função inject().
O Depois (Limpo e Direto):
export const authGuard: CanActivateFn = () => {
const authService = inject(AuthService);
const router = inject(Router);
return authService.isLoggedIn() || router.createUrlTree(['/login']);
};
3. O Impacto no Arquivo de Rotas
Quando você junta o novo Lazy Loading com as Functional Guards, o seu arquivo de definição de rotas deixa de ser uma lista de declarações de classes complexas e passa a ser altamente declarativo e compositivo.
export const APP_ROUTES: Routes = [
{
path: 'balanca/ordem-pesagem',
loadComponent: () => import('./ordem-pesagem.component').then(c => c.OrdemPesagemComponent),
canActivate: [authGuard, operadorBalancaGuard] // Funções puras, encadeadas!
}
];
Conclusão
A migração das rotas no nosso sistema exigiu refatorar dezenas de arquivos de Guards. Porém, ao transformar dezenas de linhas de classes verbosas em simples arrow functions, a base de código ficou infinitamente mais leve de ler, de dar manutenção e, principalmente, de escrever testes unitários (já que não precisamos mais instanciar classes gigantescas nos testes).
Essa limpeza extrema nas Guards só foi possÃvel graças à introdução da função inject(). E é exatamente ela que vai ser a estrela do nosso próximo artigo, onde vamos explorar como o inject() mudou a forma como compartilhamos lógica e injeção de dependências em toda a aplicação.
Você já migrou suas antigas classes Guards para funções? Sentiu diferença na facilidade de manutenção? Deixe seu relato nos comentários! 👇
Top comments (0)