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 JavaScript e melhorar drasticamente o tempo de carregamento.
Você pode encontrar os exemplos de código deste artigo no GitHub. O exemplo de roteamento imediato está disponível na ramificação imediata. 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:
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 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 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 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 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 ansiosa:
- Você definiu loadChildrenem 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 oNyanModuleem 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 as Ferramentas do desenvolvedor.
- Clique na guia Rede. 
- Clique em NYAN no app de exemplo. 
- O arquivo - nyan-nyan-module.jsaparece na guia de rede.

Encontre este exemplo no GitHub.
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 durante o carregamento do script, provavelmente você vai querer adicionar um indicador de carregamento.
Para fazer isso, comece adicionando a marcação do 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 detectar o evento RouteConfigLoadStart e definir a flag 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 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 uma rota lenta para mostrar que há uma ação em andamento.
