Mit der Codeaufteilung auf Routing-Ebene können Sie die Leistung Ihrer App verbessern.
In diesem Beitrag wird beschrieben, wie Sie die Codeaufteilung auf Routing-Ebene in einer Angular-Anwendung einrichten. Dadurch kann die Größe von JavaScript-Bundles reduziert und die Time to Interactive erheblich verbessert werden.
Die Codebeispiele aus diesem Artikel finden Sie auf GitHub. Das Beispiel für das Eager Routing ist im Eager-Branch verfügbar. Das Beispiel für die Codeaufteilung auf Routenebene befindet sich im Lazy-Branch.
Warum Code-Splitting wichtig ist
Die stetig wachsende Komplexität von Webanwendungen hat zu einer deutlichen Zunahme der Menge an JavaScript geführt, die an Nutzer gesendet wird. Große JavaScript-Dateien können die Interaktivität spürbar verzögern. Sie können daher eine kostspielige Ressource sein, insbesondere auf Mobilgeräten.
Die effizienteste Methode, JavaScript-Bundles zu verkleinern, ohne auf Funktionen in Ihren Anwendungen zu verzichten, ist die Einführung einer aggressiven Codeaufteilung.
Mit der Codeaufteilung können Sie das JavaScript Ihrer Anwendung in mehrere Chunks aufteilen, die verschiedenen Routen oder Funktionen zugeordnet sind. Bei diesem Ansatz wird Nutzern nur das JavaScript gesendet, das sie beim ersten Laden der Anwendung benötigen. So bleiben die Ladezeiten niedrig.
Techniken für Code-Splitting
Code-Splitting kann auf zwei Ebenen erfolgen: auf Komponentenebene und auf Routenebene.
- Beim Code-Splitting auf Komponentenebene werden Komponenten in eigene JavaScript-Chunks verschoben und verzögert geladen, wenn sie benötigt werden.
- Beim Code-Splitting auf Routenebene kapseln Sie die Funktionalität jeder Route in einem separaten Chunk. Wenn Nutzer in Ihrer Anwendung navigieren, werden die mit den einzelnen Routen verknüpften Chunks abgerufen und die zugehörige Funktion bei Bedarf bereitgestellt.
In diesem Beitrag geht es um die Einrichtung der Aufteilung auf Routenebene in Angular.
Beispielanwendung
Bevor wir uns ansehen, wie die Codeaufteilung auf Routenebene in Angular funktioniert, sehen wir uns eine Beispiel-App an:
Sehen Sie sich die Implementierung der Module der App an. In AppModule
sind zwei Routen definiert: die Standardroute, die mit HomeComponent
verknüpft ist, und eine nyan
-Route, die mit NyanComponent
verknüpft ist:
@NgModule({
...
imports: [
BrowserModule,
RouterModule.forRoot([
{
path: '',
component: HomeComponent,
pathMatch: 'full'
},
{
path: 'nyan',
component: NyanComponent
}
])
],
...
})
export class AppModule {}
Codeaufteilung auf Routing-Ebene
Um Code-Splitting einzurichten, muss die nyan
-Route umgestaltet werden.
Mit Version 8.1.0 der Angular CLI können Sie alles mit diesem Befehl erledigen:
ng g module nyan --module app --route nyan
Dadurch wird Folgendes generiert:
- Ein neues Routingmodul namens NyanModule
- Eine Route in AppModule
namens nyan
, die NyanModule
dynamisch lädt
- Eine Standardroute in NyanModule
- Eine Komponente namens NyanComponent
, die gerendert wird, wenn der Nutzer die Standardroute aufruft
Wir gehen diese Schritte manuell durch, um besser zu verstehen, wie Code-Splitting mit Angular implementiert wird.
Wenn der Nutzer zur Route nyan
navigiert, rendert der Router die Komponente NyanComponent
im Router-Outlet.
Wenn Sie in Angular Code-Splitting auf Routenebene verwenden möchten, legen Sie die loadChildren
-Eigenschaft der Routendeklaration fest und kombinieren Sie sie mit einem dynamischen Import:
{
path: 'nyan',
loadChildren: () => import('./nyan/nyan.module').then(m => m.NyanModule)
}
Es gibt zwei Hauptunterschiede zum Eager-Ansatz:
- Sie haben
loadChildren
anstelle voncomponent
festgelegt. Wenn Sie Code-Splitting auf Routenebene verwenden, müssen Sie auf dynamisch geladene Module statt auf Komponenten verweisen. - In
loadChildren
geben Sie nach der Auflösung des VersprechensNyanModule
zurück, anstatt aufNyanComponent
zu verweisen.
Im Snippet oben wird angegeben, dass Angular beim Aufrufen von nyan
die Datei nyan.module
dynamisch aus dem Verzeichnis nyan
laden und die Komponente rendern soll, die der im Modul deklarierten Standardroute zugeordnet ist.
Sie können die Standardroute mit einer Komponente verknüpfen, indem Sie sie so deklarieren:
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 {}
Mit diesem Code wird NyanComponent
gerendert, wenn der Nutzer zu https://example.com/nyan
navigiert.
So prüfen Sie, ob der Angular-Router nyan.module
in Ihrer lokalen Umgebung verzögert herunterlädt:
- Drücken Sie „Strg + Umschalttaste + J“ (oder „Befehlstaste + Optionstaste + J“ auf einem Mac), um die Entwicklertools zu öffnen.
Klicken Sie auf den Tab Netzwerk.
Klicken Sie in der Beispiel-App auf NYAN.
Die Datei
nyan-nyan-module.js
wird auf dem Tab „Netzwerk“ angezeigt.
Dieses Beispiel finden Sie auf GitHub.
Spinner anzeigen
Wenn der Nutzer derzeit auf die Schaltfläche NYAN klickt, wird in der Anwendung nicht angezeigt, dass JavaScript im Hintergrund geladen wird. Um dem Nutzer Feedback während des Ladens des Skripts zu geben, sollten Sie wahrscheinlich einen Spinner hinzufügen.
Fügen Sie dazu zuerst Markup für den Indikator in das router-outlet
-Element in app.component.html
ein:
<router-outlet>
<span class="loader" *ngIf="loading"></span>
</router-outlet>
Fügen Sie dann eine AppComponent
-Klasse hinzu, um Routing-Ereignisse zu verarbeiten. In dieser Klasse wird das Flag loading
auf true
gesetzt, wenn das Ereignis RouteConfigLoadStart
empfangen wird, und auf false
, wenn das Ereignis RouteConfigLoadEnd
empfangen wird.
@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;
}
}
);
}
}
Im Beispiel unten haben wir eine künstliche Latenz von 500 ms eingeführt, damit Sie den Spinner in Aktion sehen können.
Fazit
Sie können die Bundle-Größe Ihrer Angular-Anwendungen reduzieren, indem Sie die Codeaufteilung auf Routing-Ebene anwenden:
- Verwenden Sie den Generator für Lazy-Loaded-Module der Angular CLI, um automatisch eine dynamisch geladene Route zu erstellen.
- Fügen Sie eine Fortschrittsanzeige hinzu, wenn der Nutzer zu einer verzögert geladenen Route navigiert, um anzuzeigen, dass ein Vorgang läuft.