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 Angular, o que pode reduzir o tamanho do pacote do JavaScript e melhorar muito o tempo para interação da página.
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 do 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 enviada aos usuários. Grandes arquivos JavaScript podem atrasar visivelmente a interatividade, portanto, pode ser um recurso caro, especialmente em dispositivos móveis.
A maneira mais eficiente de reduzir pacotes JavaScript sem sacrificar recursos nos aplicativos é introduzir uma divisão agressiva de código.
A divisão de código permite dividir o JavaScript do aplicativo em vários blocos associados a diferentes rotas ou recursos. 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 de código pode ser feita em dois níveis: do componente e da rota.
- Na divisão de código em nível de componente, você move os componentes para os próprios blocos JavaScript e os carrega lentamente quando 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 no aplicativo, eles buscam os blocos associados às rotas individuais e obtêm a funcionalidade associada quando necessário.
Esta postagem se concentra na configuração da divisão no nível da rota no Angular.
Exemplo de aplicativo
Antes de nos aprofundarmos em como usar a divisão de código no nível da rota no Angular, vamos analisar um app de exemplo:
Conferir a implementação dos módulos do app. Dentro de AppModule
, duas rotas são definidas: a padrão associada a HomeComponent
e uma 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 rápida nyan
precisa ser refatorada.
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
chamada 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 conferir essas etapas manualmente para entender melhor como implementar a 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 de 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 principais em relação à rota antecipada:
- Você definiu
loadChildren
em vez decomponent
. Ao usar a divisão de código no nível da rota, você precisa apontar para módulos carregados dinamicamente, em vez de componentes. - Em
loadChildren
, quando 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.
Você pode 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 para https://example.com/nyan
.
Para verificar se o roteador Angular faz o download do nyan.module
lentamente 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.
Encontre este exemplo no GitHub (link em inglês).
Mostrar um ícone 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 uma marcação para o indicador dentro do elemento router-outlet
no 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 de carregamento lento da CLI Angular para criar a estrutura automaticamente (scaffolding) de uma rota carregada dinamicamente.
- Adicione um indicador de carregamento quando o usuário navegar para um trajeto lento para mostrar que há uma ação em andamento.