Mit der Codeaufteilung auf Routingebene lässt sich die Leistung Ihrer App verbessern.
In diesem Beitrag wird beschrieben, wie Sie die Codeaufteilung auf Routingebene in einer Angular-Anwendung einrichten. Dadurch lässt sich die Größe des JavaScript-Bundles reduzieren und die Time to Interactive erheblich verbessern.
Die Codebeispiele aus diesem Artikel finden Sie auf GitHub. Das Beispiel für das vorzeitige Routing ist im Vorab-Branch verfügbar. Das Beispiel für die Code-Spaltung auf Routenebene befindet sich im lazy-Branch.
Warum Code-Splitting wichtig ist
Die ständig wachsende Komplexität von Webanwendungen hat zu einem deutlichen Anstieg der Menge an JavaScript geführt, die an Nutzer gesendet wird. Große JavaScript-Dateien können die Interaktivität erheblich verzögern und sind daher eine kostspielige Ressource, insbesondere auf Mobilgeräten.
Die effizienteste Methode, JavaScript-Bundles zu verkleinern, ohne Funktionen in Ihren Anwendungen zu opfern, ist die aggressive Codeaufteilung.
Mit der Codeaufteilung können Sie das JavaScript Ihrer Anwendung in mehrere Code-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 zum Code-Splitting
Das Code-Splitting kann auf zwei Ebenen erfolgen: auf Komponentenebene und auf Wegeebene.
- Beim Code-Splitting auf Komponentenebene verschieben Sie Komponenten in eigene JavaScript-Chunks und laden sie bei Bedarf verzögert.
- Beim Code-Splitting auf Routenebene kapseln Sie die Funktionen jeder Route in einem separaten Chunk ein. Wenn Nutzer in Ihrer Anwendung navigieren, werden die mit den einzelnen Routen verknüpften Chunks abgerufen und die zugehörigen Funktionen werden bei Bedarf abgerufen.
In diesem Beitrag geht es vorrangig um die Einrichtung der Aufteilung auf Routenebene in Angular.
Beispielanwendung
Bevor wir uns damit befassen, wie Sie die Code-Spaltung auf Routenebene in Angular verwenden, sehen wir uns eine Beispiel-App an:
Sehen Sie sich die Implementierung der App-Module an. Innerhalb von 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
-Eager-Route umgeschrieben 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 werden folgende Elemente generiert:
- Ein neues Routing-Modul namens NyanModule
- Eine Route in AppModule
namens nyan
, über die NyanModule
dynamisch geladen wird
- Eine Standardroute in NyanModule
- Eine Komponente namens NyanComponent
, die gerendert wird, wenn der Nutzer die Standardroute aufruft
Gehen wir diese Schritte manuell durch, um das Implementieren des Code-Splittings mit Angular besser zu verstehen.
Wenn der Nutzer die Route nyan
aufruft, rendert der Router die NyanComponent
im Router-Outlet.
Wenn Sie das Code-Splitting auf Routenebene in Angular verwenden möchten, legen Sie die Property loadChildren
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 wichtige Unterschiede zum eager-Pfad:
- Sie haben
loadChildren
anstelle voncomponent
festgelegt. Wenn Sie die Code-Spaltung auf Routenebene verwenden, müssen Sie auf dynamisch geladene Module statt auf Komponenten verweisen. - In
loadChildren
geben Sie nach der Auflösung des Versprechens dieNyanModule
zurück, anstatt auf dieNyanComponent
zu verweisen.
Im obigen Snippet wird angegeben, dass Angular nyan.module
dynamisch aus dem Verzeichnis nyan
laden und die Komponente rendern soll, die mit der im Modul deklarierten Standardroute verknüpft ist, wenn der Nutzer zu nyan
navigiert.
Sie können die Standardroute mit einer Komponente mithilfe dieser Deklaration verknüpfen:
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
wechselt.
So prüfen Sie, ob der Angular-Router die 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 Beispielanwendung auf NYAN.
Die
nyan-nyan-module.js
-Datei wird auf dem Tab „Netzwerk“ angezeigt.
Dieses Beispiel finden Sie auf GitHub.
Ladesymbol anzeigen
Derzeit wird in der Anwendung nicht angezeigt, dass im Hintergrund JavaScript geladen wird, wenn der Nutzer auf die Schaltfläche NYAN klickt. Um dem Nutzer während des Ladens des Scripts Feedback zu geben, sollten Sie wahrscheinlich einen Ladebalken hinzufügen.
Fügen Sie dazu zuerst das 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. Diese Klasse setzt das Flag loading
auf true
, wenn das Ereignis RouteConfigLoadStart
erkannt wird, und auf false
, wenn das Ereignis RouteConfigLoadEnd
erkannt 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 folgenden Beispiel haben wir eine künstliche Latenz von 500 ms eingeführt, damit Sie den Fortschrittsbalken in Aktion sehen können.
Fazit
Sie können die Bundle-Größe Ihrer Angular-Anwendungen reduzieren, indem Sie die Codeaufteilung auf Routingebene anwenden:
- Verwenden Sie den Lazy-Loaded-Modulgenerator der Angular-Befehlszeile, um eine dynamisch geladene Route automatisch zu erstellen.
- Fügen Sie eine Ladeanzeige hinzu, wenn der Nutzer zu einer Lazy-Route wechselt, um anzuzeigen, dass eine Aktion ausgeführt wird.