Unsere bisherigen Beispiele sind alle davon ausgegangen das es ein zentrales Modul gibt dessen Referenzen von Webpack analysiert und in in großes JavaScript-Bundle zusammen gefasst wird. Für kleine Anwendungen mag dieses Vorgehen gut funktionieren, wird die Anwendung jedoch komplexer und lassen sich einzelne Bereiche gut voneinander abtrennen bietet es sich an die eigenen Anwendung in mehrere Module zu unterteilen und diese nur bei Bedarf zu laden.
Webpack – prepare
Wir werden, anders als bisher, nicht mehr alle Komponenten die wir per Routing ansteuern wollen in unseren Routen importieren. Damit Webpack die Deklaration von Angular 2 spezifischen asynchronen Routen erkennt benötigen wir einen zusätzlichen Loader:
npm install angular2-router-loader --save-dev
Zusätzlich registrieren wir diesen Loader für unsereTypeScript-Dateien in unserer Konfiguration:
webpack.common.js
... { test: /\.ts$/, loaders: ['ts-loader','angular2-router-loader'] } ...
Modul die Zweite
In unserem sehr einfachen Beispiel wollen wir nun die „zweite“ Seite unserer Anwendung in ein eigenes Modul verschieben, um diese später nur bei Bedarf laden zu können. Dazu erzeugen wir eine neue Modul-Defitionsdatei mit einer Route-Definition für unser Unter-Modul:
hello.module.ts
import { NgModule} from '@angular/core'; import { routing } from './hello.routing'; import {HelloComponent} from '../' @NgModule({ imports: [routing], declarations: [HelloComponent], providers: [ ], exports: [HelloComponent] }) export class HelloModule { }
hello.routing.ts
import { Routes, RouterModule } from '@angular/router'; import {HelloComponent} from '../' const appRoutes: Routes = [ { path: '', component: HelloComponent} ]; export const routing = RouterModule.forChild(appRoutes);
In großen Teilen unterscheidet sich diese Modul-Definition nicht von unserem Root-Modul. Wir geben hier lediglich kein „bootstrap“-Attribut an. Darüber hinaus referenzieren wir natürlich nur die externen Module („imports“), die eigenen Komponenten („declarations“) und Provider („providers“) die in diesem Modul gültig sind. Auch die Routing-Datei ändert sich lediglich an einer Stelle. Anstatt das Routing als Root-Navigation zu exportieren (.forRoot) geben wir lediglich an das es sich bei diesen exportierten Routen um Navigationen für ein Kind-Modul handelt (.forChild).
Laden? Später bitte
Die entscheiden Anpassung in unserem Root-Modul geschieht nun in Routen-Definition:
app.routing.ts
// -- ALT -- ... const appRoutes: Routes = [ { path: '', component: HomeComponent}, { path: 'hello', component: HelloComponent}, { path: 'animation', component: AnimationComponent}, ]; ... // -- NEU -- import { Routes, RouterModule } from '@angular/router'; import {HomeComponent} from './components' const appRoutes: Routes = [ { path: '', component: HomeComponent}, { path: 'hello', loadChildren: './components/+hello/hello.module#HelloModule' }, { path: 'animation', loadChildren: './components/+animation/animation.module#AnimationModule' } ]; export const appRoutingProviders: any[] = [ ]; export const routing = RouterModule.forRoot(appRoutes);
Anstatt direkt die Kind-Komponenten zu referenzieren verwenden wir eine spezielle URL-Syntax die dank des oben installierten und registrierten Webpack-Loaders auch beim Bundling der Anwendung funktioniert. Asynchrone Routen werden wie hier zu sehen mittels „loadChildren“ Attribut deklariert, gefolgt von einem String im Aufbau:
„[Pfad-zur-Modul-Datei]#[ModulName]“
(die hier verwendeten Bezeichnungen der Ordner mit vorangestelltem „+“ Zeichen ist nicht verpflichtend, ist aber eine allgemeine akzeptierte Konvention um asynchrone Komponenten zu markieren)
Alles zu seiner Zeit
Die oben gezeigte Konfiguration führt nun dazu das Webpack mehrere Bundles ausprägt, ein Bundle pro Module, sodass diese später geladen werden können. Dies lässt sich dann auch in der laufenden Anwendung nachvollziehen. Bei der Navigation zwischen den Seiten (/ Modulen) lädt Angular diese Kind-Komponenten erst wenn sie angesteuert werden:
Lazy-Loaded Routes ist eine optimale und einfach zu verwendete Möglichkeit die Anwendung in schneller ladbare Teile zu teilen und den Anwender bei großen Anwendungen nicht mit Programmteilen zu belasten die er vielleicht gar nicht verwendet. Das gezeigteBeispiel gibt es wie immer auch bei Github: