Opóźnione ładowanie modułu

Kolejną zaletą wykorzystania modułów do grupowania powiązanych elementów funkcjonalności naszej aplikacji jest możliwość ładowania tych elementów na żądanie. Opóźnione ładowanie modułów pomaga nam skrócić czas uruchamiania. Dzięki takiemu ładowaniu nasza aplikacja nie musi pobierać wszystkiego naraz, wystarczy załadować to, czego użytkownik oczekuje, gdy aplikacja zostanie załadowana po raz pierwszy. Moduły ładowane z opóźnieniem (lazy) zostaną załadowane tylko wtedy, gdy użytkownik przejdzie do ich tras.

Aby pokazać tę relację, zacznijmy od zdefiniowania prostego modułu, który będzie działał jako główny moduł naszej przykładowej aplikacji.

app/app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule  } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { EagerComponent } from './eager.component';
import { routing } from './app.routing';

@NgModule({
  imports: [
    BrowserModule,
    routing
  ],
  declarations: [
    AppComponent,
    EagerComponent
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Jak dotąd jest to elementarny moduł, który opiera się na BrowserModule, ma mechanizmroutingu i dwa komponenty: AppComponent iEagerComponent. Na razie skupmy się na głównym komponencie naszej aplikacji (AppComponent), w którym zdefiniowana jest nawigacja.

app/app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <h1>My App</h1>
    <nav>
      <a routerLink="eager">Eager</a>
      <a routerLink="lazy">Lazy</a>
    </nav>
    <router-outlet></router-outlet>
  `
})
export class AppComponent {}

Nasz system nawigacji ma tylko dwie ścieżki: eager i lazy. Aby dowiedzieć się, jakie ścieżki ładują się po kliknięciu, musimy rzucić okiem na obiekt routing, który przekazaliśmy do modułu głównego.

app/app.routing.ts

import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { EagerComponent } from './eager.component';

const routes: Routes = [
  { path: '', redirectTo: 'eager', pathMatch: 'full' },
  { path: 'eager', component: EagerComponent },
  { path: 'lazy', loadChildren: 'lazy/lazy.module#LazyModule' }
];

export const routing: ModuleWithProviders = RouterModule.forRoot(routes);

Tutaj widzimy, że domyślna ścieżka w naszej aplikacji nazywa się eager i ładujeEagerComponent.

app/eager.component.ts

import { Component } from '@angular/core';

@Component({
  template: '<p>Eager Component</p>'
})
export class EagerComponent {}

Ale co ważniejsze, widzimy, że za każdym razem gdy próbujemy wejść na ścieżkę lazy, będziemy ładować z opóźnieniem moduł nazwanyLazyModule. Przyjrzyj się bliżej definicji tej trasy:

{ path: 'lazy', loadChildren: 'lazy/lazy.module#LazyModule' }

Jest tu kilka ważnych rzeczy do zauważenia:

  1. Używamy właściwości loadChildren zamiastcomponent.
  2. Przekazujemy ciąg zamiast symbolu, aby nie ładować modułu o razu.
  3. Definiujemy nie tylko ścieżkę do modułu, ale także nazwę klasy.

Nie ma nic szczególnego w LazyModule. Ma on własnyrouting i komponent o nazwie LazyComponent.

app/lazy/lazy.module.ts

import { NgModule } from '@angular/core';

import { LazyComponent }   from './lazy.component';
import { routing } from './lazy.routing';

@NgModule({
  imports: [routing],
  declarations: [LazyComponent]
})
export class LazyModule {}

Jeśli zdefiniujemy klasę LazyModule jakodomyślnyeksport pliku, nie musimy definiować nazwy klasy we właściwościloadChildren, jak pokazano powyżej.

Obiekt routing jest bardzo prosty i definiuje tylko domyślny komponent do załadowania podczas nawigacji do ścieżki lazy.

app/lazy/lazy.routing.ts

import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { LazyComponent } from './lazy.component';

const routes: Routes = [
  { path: '', component: LazyComponent }
];

export const routing: ModuleWithProviders = RouterModule.forChild(routes);

Zauważ, że używamy wywołania metody forChild zamiastforRoot w celu utworzenia obiektu routingu. Zawsze należy to robić podczas tworzenia obiektu routingu dla modułu funkcjonalnego, bez względu na to, czy moduł ma być ładowany normalnie, czy z opóźnieniem.

Wreszcie, nasz LazyComponent jest bardzo podobny doEagerComponent i jest tylko symbolem zastępczym dla jakiegoś tekstu.

app/lazy/lazy.component.ts

import { Component } from '@angular/core';

@Component({
  template: '<p>Lazy Component</p>'
})
export class LazyComponent {}

Zobacz przykład [017]

Kiedy ładujemy naszą aplikację po raz pierwszy, AppModule wraz zAppComponent zostanie załadowany do przeglądarki i powinniśmy zobaczyć system nawigacji i tekst Eager Component. Do tego momentu LazyModule nie jest pobierany, tylko wtedy, gdy klikniemy na linkLazy, pobrany kod zostanie pobrany, a my zobaczymy komunikatLazy Componentw przeglądarce.