Codeaufteilung auf Routenebene in Angular

Verbessern Sie die Leistung Ihrer App durch Codeaufteilung auf Routenebene.

In diesem Beitrag wird erläutert, wie Sie die Codeaufteilung auf Routenebene in einer Angular-Anwendung einrichten. Damit lässt sich die Größe des JavaScript-Bundles reduzieren und die Zeit bis Interaktivität erheblich verbessern.

Die Codebeispiele aus diesem Artikel finden Sie auf GitHub. Das Beispiel für Eager-Routing ist im Eager-Zweig verfügbar. Das Beispiel für die Codeaufteilung auf Routenebene finden Sie im Lazy Branch.

Warum die Codeaufteilung 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 merklich verzögern, was insbesondere auf Mobilgeräten eine kostspielige Ressource sein kann.

Die effizienteste Methode zum Verkleinern von JavaScript-Bundles, ohne auf Funktionen in Ihren Anwendungen zu verzichten, ist die Einführung einer aggressiven Codeaufteilung.

Mit der Codeaufteilung können Sie den JavaScript-Code Ihrer Anwendung in mehrere Blöcke aufteilen, die verschiedenen Routen oder Funktionen zugeordnet sind. Bei diesem Ansatz wird den Nutzern nur das JavaScript gesendet, das sie während des anfänglichen Ladevorgangs der Anwendung benötigen, sodass die Ladezeiten niedrig sind.

Verfahren zur Codeaufteilung

Codeaufteilung kann auf zwei Ebenen erfolgen: auf der Komponentenebene und auf der Routenebene.

  • Bei der Codeaufteilung auf Komponentenebene verschieben Sie Komponenten in eigene JavaScript-Blöcke und laden sie verzögert, wenn sie benötigt werden.
  • Bei der Codeaufteilung auf Routenebene kapseln Sie die Funktionalität jeder Route in einen separaten Block. Wenn Nutzer durch Ihre Anwendung navigieren, rufen sie die mit den einzelnen Routen verknüpften Blöcke ab und erhalten bei Bedarf die zugehörigen Funktionen.

In diesem Beitrag geht es um das Einrichten einer Teilung auf Routenebene in Angular.

Beispielanwendung

Bevor wir uns damit befassen, wie die Codeaufteilung auf Routenebene in Angular verwendet wird, sollten wir uns eine Beispielanwendung ansehen:

Überprüfen Sie die Implementierung der Module der App. In AppModule sind zwei Routen definiert: die Standardroute, die HomeComponent zugeordnet ist, und eine nyan-Route, die NyanComponent zugeordnet ist:

@NgModule({
  ...
  imports: [
    BrowserModule,
    RouterModule.forRoot([
      {
        path: '',
        component: HomeComponent,
        pathMatch: 'full'
      },
      {
        path: 'nyan',
        component: NyanComponent
      }
    ])
  ],
  ...
})
export class AppModule {}

Codeaufteilung auf Routenebene

Zum Einrichten der Codeaufteilung muss die Eager-Route nyan refaktoriert werden.

Version 8.1.0 der Angular-Befehlszeile kann mit diesem Befehl alles für Sie tun:

ng g module nyan --module app --route nyan

Dadurch wird Folgendes generiert: - Ein neues Routingmodul namens NyanModule – Eine Route in AppModule mit dem Namen nyan, die die NyanModule dynamisch lädt - Eine Standardroute im NyanModule - Eine Komponente namens NyanComponent, die gerendert wird, wenn der Nutzer die Standardroute erreicht

Gehen wir diese Schritte manuell durch, damit wir die Implementierung der Codeaufteilung mit Angular besser verstehen.

Wenn der Nutzer die Route nyan aufruft, rendert der Router NyanComponent in der Routersteckdose.

Wenn Sie die Codeaufteilung auf Routenebene in Angular verwenden möchten, legen Sie das Attribut loadChildren der Routendeklaration fest und kombinieren Sie es mit einem dynamischen Import:

{
  path: 'nyan',
  loadChildren: () => import('./nyan/nyan.module').then(m => m.NyanModule)
}

Es gibt zwei wichtige Unterschiede gegenüber der eifrigen Route:

  1. Du hast loadChildren anstelle von component festgelegt. Bei der Codeaufteilung auf Routenebene müssen Sie auf dynamisch geladene Module statt auf Komponenten verweisen.
  2. Sobald das Versprechen aufgelöst wurde, wird in loadChildren das NyanModule zurückgegeben, anstatt auf das NyanComponent zu verweisen.

Das obige Snippet gibt an, dass Angular nyan.module dynamisch aus dem Verzeichnis nyan laden und die mit der im Modul deklarierten Standardroute verknüpfte Komponente rendern soll, wenn der Nutzer nyan aufruft.

Sie können die Standardroute mithilfe dieser Deklaration mit einer Komponente 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 https://example.com/nyan aufruft.

So prüfen Sie, ob der Angular-Router das nyan.module in Ihrer lokalen Umgebung verzögert herunterlädt:

  1. Drücken Sie „Strg + Umschalttaste + J“ (oder „Befehlstaste + Option + J“ auf einem Mac), um die Entwicklertools zu öffnen.
  2. Klicken Sie auf den Tab Netzwerk.

  3. Klicken Sie in der Beispiel-App auf NYAN.

  4. Die Datei nyan-nyan-module.js wird auf dem Tab „Netzwerk“ angezeigt.

Lazy Loading von JavaScript-Bundles mit Codeaufteilung auf Routenebene

Dieses Beispiel finden Sie auf GitHub.

Rotierendes Ladesymbol anzeigen

Wenn der Nutzer derzeit auf die NYAN-Schaltfläche klickt, gibt die Anwendung nicht an, dass JavaScript im Hintergrund geladen wird. Um dem Nutzer beim Laden des Skripts Feedback zu geben, können Sie ein rotierendes Ladesymbol hinzufügen.

Dazu musst du zuerst Markup für den Indikator im router-outlet-Element in app.component.html hinzufügen:

<router-outlet>
  <span class="loader" *ngIf="loading"></span>
</router-outlet>

Fügen Sie dann eine AppComponent-Klasse hinzu, um Routingereignisse zu verarbeiten. Diese Klasse setzt das Flag loading auf true, wenn das RouteConfigLoadStart-Ereignis erkannt wird, und das Flag auf false, wenn das RouteConfigLoadEnd-Ereignis 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 das Kreiselsymbol in Aktion sehen können.

Fazit

Sie können die Paketgröße Ihrer Angular-Anwendungen verringern, indem Sie Codeaufteilung auf Routenebene anwenden:

  1. Verwenden Sie den Lazy-Loading-Modulgenerator von Angular CLI, um automatisch das Gerüst einer dynamisch geladenen Route zu erstellen.
  2. Eine Ladeanzeige hinzufügen, wenn der Nutzer zu einer Lazy Route wechselt, um auf eine laufende Aktion hinzuweisen.