Angular 2 – Lazy Load Modules

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:

angular2_lazy_routing_network

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:

https://github.com/dominikmathmann/angular-webpack-starter/tree/lazy-loaded-routes

Advertisements

Über Dominik Mathmann
Dominik Mathmann arbeitet als Berater, Entwickler und Trainer bei der GEDOPLAN GmbH. Auf Basis seiner langjährigen Erfahrung in der Implementierung von Java-EE-Anwendungen leitet er Seminare, hält Vorträge und unterstützt Kunden bei der Konzeption und Realisierung von Webanwendungen vom Backend bis zum Frontend. Sein derzeitiger Schwerpunkt liegt dabei auf der Entwicklung von JSF-Anwendungen. Er sieht die stärker werdende Position von JavaScript-Frameworks jedoch positiv und beschäftigt sich darüber hinaus mit Webframeworks wie AngularJS.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: