Melhore o desempenho do seu app usando a divisão de código no nível da rota.
Nesta postagem, explicamos 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 JavaScript e melhorar significativamente o tempo para interação da página.
Confira os exemplos de código deste artigo no GitHub (em inglês). 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 visivelmente a interatividade, por isso, pode ser um recurso caro, especialmente em dispositivos móveis.
A maneira mais eficiente de reduzir pacotes JavaScript sem sacrificar recursos nos seus aplicativos é introduzir uma divisão de código agressiva.
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 no nível do componente, você move componentes para os próprios blocos de JavaScript e os carrega lentamente quando necessário.
- 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 seu aplicativo, eles buscam os blocos associados às rotas individuais e recebem a funcionalidade associada quando precisam.
O foco desta postagem é a configuração da divisão no nível da rota no Angular.
Exemplo de aplicativo
Antes de saber como usar a divisão de código no nível da rota no Angular, vejamos um app de exemplo:
Confira 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 do trajeto
Para configurar a divisão de código, a rota eager nyan
precisa ser refatorada.
A versão 8.1.0 da CLI 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 a NyanModule
- Uma rota padrão no NyanModule
- Um componente chamado NyanComponent
que vai 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 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 principais da rota rápida:
- Você define
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 for resolvida, você vai retornar 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 para https://example.com/nyan
.
Para verificar se o roteador do Angular faz o download lento do nyan.module
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 (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, adicione 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 definirá a sinalização loading
como true
quando detectar o evento RouteConfigLoadStart
e a sinalização como false
quando detectar o evento RouteConfigLoadEnd
.
@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 conferir o ícone de carregamento em ação.
Conclusão
Você pode reduzir o tamanho do pacote dos seus aplicativos do Angular aplicando a divisão de código no nível da rota:
- Use o gerador de módulos de carregamento lento da CLI do Angular para criar a estrutura automaticamente de uma rota com carregamento dinâmico.
- Adicione um indicador de carregamento quando o usuário navegar por uma rota lenta para mostrar que há uma ação em andamento.