Melhore o desempenho do seu app usando a divisão de código no nível da rota.
Esta postagem explica como configurar a divisão de código no nível da rota em um aplicativo do Angular, o que pode reduzir o tamanho do pacote JavaScript e melhorar drasticamente o tempo de carregamento.
Os exemplos de código deste artigo estão disponíveis no GitHub. O exemplo de roteamento antecipado está disponível na ramificação eager. O exemplo de divisão de código no nível da rota está na ramificação lenta.
Por que a divisão de código é importante
A complexidade cada vez maior dos aplicativos da Web levou a um aumento significativo na quantidade de JavaScript enviado aos usuários. Arquivos JavaScript grandes podem atrasar significativamente a interatividade, o que pode ser um recurso caro, especialmente em dispositivos móveis.
A maneira mais eficiente de reduzir os pacotes JavaScript sem sacrificar recursos nos seus aplicativos é introduzir a divisão agressiva de código.
A divisão de código permite dividir o JavaScript do seu aplicativo em vários blocos associados a rotas ou recursos diferentes. Essa abordagem envia aos usuários apenas o JavaScript necessário durante o carregamento inicial do aplicativo, mantendo os tempos de carregamento baixos.
Técnicas de divisão de código
A divisão do código pode ser feita em dois níveis: o nível do componente e o nível da rota.
- Na divisão de código no nível do componente, você move os componentes para os próprios blocos JavaScript e os carrega de forma lenta quando eles são necessários.
- Na divisão de código no nível da rota, você encapsula a funcionalidade de cada rota em um bloco separado. Quando os usuários navegam pelo aplicativo, eles buscam os blocos associados às rotas individuais e recebem a funcionalidade associada quando precisam dela.
Esta postagem se concentra na configuração da divisão no nível da rota no Angular.
Exemplo de aplicativo
Antes de explicar como usar a divisão de código no nível da rota no Angular, vamos conferir um exemplo de app:
Conferir a implementação dos módulos do app. Dentro de AppModule
, duas rotas são definidas: a rota padrão associada a HomeComponent
e uma rota nyan
associada a NyanComponent
:
@NgModule({
...
imports: [
BrowserModule,
RouterModule.forRoot([
{
path: '',
component: HomeComponent,
pathMatch: 'full'
},
{
path: 'nyan',
component: NyanComponent
}
])
],
...
})
export class AppModule {}
Divisão de código no nível da rota
Para configurar a divisão de código, a rota ansiosa nyan
precisa ser refatorizada.
A versão 8.1.0 da CLI do Angular pode fazer tudo por você com este comando:
ng g module nyan --module app --route nyan
Isso vai gerar:
- Um novo módulo de roteamento chamado NyanModule
- Uma rota em AppModule
com o nome nyan
que vai carregar dinamicamente o NyanModule
- Uma rota padrão no NyanModule
- Um componente chamado NyanComponent
que será renderizado quando o usuário acessar a rota padrão
Vamos seguir estas etapas manualmente para entender melhor a implementação da divisão de código com o Angular.
Quando o usuário navega para a rota nyan
, o roteador renderiza o NyanComponent
na saída do roteador.
Para usar a divisão de código no nível da rota no Angular, defina a propriedade loadChildren
da declaração da rota e combine-a com uma importação dinâmica:
{
path: 'nyan',
loadChildren: () => import('./nyan/nyan.module').then(m => m.NyanModule)
}
Há duas diferenças importantes em relação à rota ansiosa:
- Você definiu
loadChildren
em vez decomponent
. Ao usar a divisão de código no nível da rota, é necessário apontar para módulos carregados dinamicamente, em vez de componentes. - Em
loadChildren
, depois que a promessa é resolvida, você retorna oNyanModule
em vez de apontar para oNyanComponent
.
O snippet acima especifica que, quando o usuário navega para nyan
, o Angular precisa carregar dinamicamente nyan.module
do diretório nyan
e renderizar o componente associado à rota padrão declarada no módulo.
É possível associar a rota padrão a um componente usando esta declaração:
import { NgModule } from '@angular/core';
import { NyanComponent } from './nyan.component';
import { RouterModule } from '@angular/router';
@NgModule({
declarations: [NyanComponent],
imports: [
RouterModule.forChild([{
path: '',
pathMatch: 'full',
component: NyanComponent
}])
]
})
export class NyanModule {}
Esse código renderiza NyanComponent
quando o usuário navega até https://example.com/nyan
.
Para verificar se o roteador do Angular faz o download de nyan.module
de forma lenta no ambiente local:
- Pressione "Control+Shift+J" (ou "Command+Option+J" no Mac) para abrir o DevTools.
Clique na guia Rede.
Clique em NYAN no app de exemplo.
Observe que o arquivo
nyan-nyan-module.js
aparece na guia de rede.
Confira este exemplo no GitHub (link em inglês).
Mostrar um indicador de carregamento
No momento, quando o usuário clica no botão NYAN, o aplicativo não indica que está carregando JavaScript em segundo plano. Para dar feedback ao usuário enquanto carrega o script, adicione um ícone de carregamento.
Para fazer isso, comece adicionando a marcação para o indicador dentro do elemento router-outlet
em app.component.html
:
<router-outlet>
<span class="loader" *ngIf="loading"></span>
</router-outlet>
Em seguida, adicione uma classe AppComponent
para processar eventos de roteamento. Essa classe vai definir a flag loading
como true
quando ouvir o evento RouteConfigLoadStart
e a sinalização como false
quando o evento RouteConfigLoadEnd
detectar.
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
loading: boolean;
constructor(router: Router) {
this.loading = false;
router.events.subscribe(
(event: RouterEvent): void => {
if (event instanceof NavigationStart) {
this.loading = true;
} else if (event instanceof NavigationEnd) {
this.loading = false;
}
}
);
}
}
No exemplo abaixo, introduzimos uma latência artificial de 500 ms para que você possa ver o ícone de carregamento em ação.
Conclusão
É possível reduzir o tamanho do pacote dos seus aplicativos Angular aplicando a divisão de código no nível da rota:
- Use o gerador de módulos carregados de forma lazy da CLI do Angular para criar automaticamente uma rota carregada de forma dinâmica.
- Adicione um indicador de carregamento quando o usuário navegar para um trajeto lento para mostrar que há uma ação em andamento.