Konfiguration von Lazy Loaded Angular Modulen

Die Konfigurierbarkeit unserer Angular-Module ist für den Aufbau einer wiederverwendbaren Architektur unerlässlich. Aber in der jüngsten Vergangenheit hat uns Angular seine neue modullose Zukunft präsentiert. Wie sieht das Ganze jetzt aus? Wie konfigurieren wir jetzt unsere Lazy-Komponenten? Lasst uns gemeinsam einen Blick darauf werfen.

In diesem Artikel:

SL-rund
Sascha Lehmann ist Developer bei Thinktecture. Sein Fokus liegt auf Angular und der Verbesserung von User Experience.

Alle Code-Referenzen und Beispiele beziehen sich auf Angular 16.0.0. 

In der Vergangenheit waren wir es gewohnt die forRoot oder forChild Funktionen zu verwenden, um Module mit bestimmten Providern zu initialisieren, oder darüber hinausgehende Konfigurierbarkeit zu erreichen. Mit der neuen Standalone-API von Angular und dem Wegfall der NgModules wird das ganze Prozedere nochmal ein ganzes Stückchen einfacher.

Lazy Loaded Components

In unserem Beispiel haben wir ein einfaches Konfigurationsobjekt SomeConfig, das wir unter einem bestimmten Injectiontoken COMPONENT_CONFIG bereitstellen wollen. Außerdem exportieren wir auch eine Standardkonfiguartion für unsere Eager-Loaded-Components.

				
					// config.model.ts

export interface SomeConfig {
  debug: boolean;
  text: string;
}

export const COMPONENT_CONFIG = new InjectionToken<SomeConfig>('Component Config');

export const DEFAULT_CONFIG: SomeConfig = { debug: false, text: 'Eager Component' };
				
			

Damit wir unsere Standardkonfiguration unter dem Token COMPONENT_CONFIG bereitstellen können, müssen wir es auf Applikationsebene bereitstellen. In der neuen Standalone Projektstruktur sieht das folgendermaßen aus:

				
					//app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [provideRouter(routes), {provide: COMPONENT_CONFIG, useValue:DEFAULT_CONFIG}]
};

//main.ts
bootstrapApplication(AppComponent, appConfig)
  .catch((err) => console.error(err));


				
			

Wir erstellen nun eine HomeComponent die beim Start der Anwendung eager geladen wird, weisen ihr eine Route zu und starten unsere Anwendung.

Et voilà!

Alles funktioniert erwartungsgemäß und die Komponente zeigt unsere Konfiguration an.

Soweit, so gut. Aber jetzt wird es Zeit, dass wir mal ein bisschen „Lazyness“ in die ganze Sache reinbringen, oder?

Gesagt, getan. Wir erstellen uns dazu eine Kopie der HomeComponent und nennen sie (wie solle es auch anders sein) LazyHomeComponent. Um in der Vergangenheit ein Modul lazy zu laden, haben wir dessen Route wie folgt konfiguriert.

				
					const routes: Routes = [
  {
    path: 'lazy',
    loadChildren: () =>
      import('../app/lazy-loaded-configurable/lazy-loaded-configurable.module').then(
        (m) => m.LazyLoadedConfigurableModule),
  },
];
				
			

Mit Hilfe von loadChildren importierten wir das Modul erst wenn auf die Route navigiert wurde. In unserer modullosen Gegenwart rufen wir stattdessen einfach loadComponent auf. Es funktioniert genau so wie loadChildren, nur mit dem kleinen Unterschied, dass es anstelle eines Moduls eine Komponente zurück liefert. Aber wie stellen wir nun unsere Konfiguration bereit? Keine Angst, Angular hat da was für uns in petto. Mit Angular 14 wurde bereits die Möglichkeit eingeführt Provider auf Route-Ebene zu definieren. Das bedeutet, dass Angular einen neuen EnvironmentInjector für diese Route erzeugt. Damit können wir Services (oder Konfigurationen) bereitstellen, die nur auf Route- bzw. Child-Route-Ebene verfügbar sind. Lasst uns einmal das Providers-Array hinzufügen und uns das Endergebnis anschauen.

				
					//app.routes.ts

export const routes: Routes = [
  { path: '', component: HomeComponent },
  {
    path: 'lazy',
    loadComponent: () => import('./lazy-home/lazy-home.component'),
    providers: [{ provide: COMPONENT_CONFIG, useValue: LAZY_CONFIG }],
  }
];
				
			

Tada! Wir haben erfolgreich unsere „Lazy-Konfiguration“ der LazyHomeComponent zu Verfügung gestellt.

Ihr habt vielleicht bemerkt, dass der Komponentenimport oben kein .then(c => c.LazyHomeComponent) beinhaltet. Ihr könnt euch diesen Teil sparen indem ihr am Ende eures Komponenten-Files einen  default export macht. In unserem Fall also export default LazyHomeComponent. Das gleiche Prinzip könnt ihr auch auf Files anwenden die Routen beinhalten.

Lazy Loaded Routes

Aber es ist in unseren Anwendungen nicht immer der Fall, dass wir alle lazy geladenen Komponenten individuell konfigurieren wollen. Wie mit Modulen, wollen wir bspw. eine Konfiguration für ein ganzes Routensegment bereitstellen können. Kein Problem. Lasst uns einen neuen Ordner mit zwei weiteren Lazy-Komponenten erstellen. Die dazugehörige Routenkonfiguration sieht so aus.

				
					//more-lazy.routes.ts

export const MORE_LAZINESS_CONFIG: SomeConfig = { debug: false, text: 'More Laziness' };

export const MORE_LAZINESS_ROUTES: Routes = [
  {
    path: '', 
    pathMatch: 'prefix', 
    providers: [{ provide: COMPONENT_CONFIG, useValue: MORE_LAZINESS_CONFIG }],
    children: [
      { path: 'lazy-1', component: LazyOneComponent },
      { path: 'lazy-2', component: LazyTwoComponent },
    ],
  },
];
				
			

Wie früher definieren wir eine leere Route, die zwei Kindrouten beinhaltet. Zum Bereitstellen unserer Konfiguration befolgen wir den selben Ansatz wie zu vor und fügen das Providers-Array mit der Konfiguration hinzu.

Jetzt müssen wir nur noch diese Routen lazy laden.

				
					export const routes: Routes = [
  { path: '', component: HomeComponent },
  {
    path: 'lazy',
    loadComponent: () => import('./lazy-home/lazy-home.component'),
    providers: [{ provide: COMPONENT_CONFIG, useValue: LAZY_CONFIG }],
  },
  {
    path: 'more-laziness',
    loadChildren: () => import('./more-laziness/more-lazy.routes'),
  },
];
				
			

Wir sehen, dass wir hierzu unsere altbekannte loadChildren Funktion nutzen können. Allerdings funktioniert sie ein bisschen anders als früher. Statt eines Moduls gib sie nun ein Routes Objekt zurück. So müssen wir nur unsere „gebündelten“ Routen referenzieren.

Und nach dem Start unserer Applikation sehen wir auch, dass alles erwartungsgemäß funktioniert.

Zusammenfassung

Wir haben uns angeschaut wie wir lazy geladene Komponenten und Routen innerhalb von Standalone Angular Applikationen konfigurieren können und haben gelernt, dass es nun sogar noch einfacher möglich ist. Der Standalone-Ansatz und die Möglichkeit Services / Konfigurationen auf Routenebene bereitzustellen sind eine großartige Ergänzung des Frameworks, und gewährleisten es wiederverwendbare Architekturen in Kombination mit einer angenehmen Developer-Experience kombinieren zu können.

Kostenloser
Newsletter

Aktuelle Artikel, Screencasts, Webinare und Interviews unserer Experten für Sie

Verpassen Sie keine Inhalte zu Angular, .NET Core, Blazor, Azure und Kubernetes und melden Sie sich zu unserem kostenlosen monatlichen Dev-Newsletter an.

Newsletter Anmeldung
Diese Artikel könnten Sie interessieren
Low-angle photography of metal structure
AI
cl-neu

AI-Funktionen zu Angular-Apps hinzufügen: lokal und offlinefähig

Künstliche Intelligenz (KI) ist spätestens seit der Veröffentlichung von ChatGPT in aller Munde. Wit WebLLM können Sie einen KI-Chatbot in Ihre eigenen Angular-Anwendungen integrieren. Wie das funktioniert und welche Vor- und Nachteile WebLLM hat, lesen Sie hier.
26.02.2024
Angular
yb

Using EntityAdapter with ComponentStore: @ngrx/entity Series – Part 3

As someone who enjoys the ComponentStore on an average level, I have written simple reactive CRUD logic several times. While storing a vast number of entities in the component state might not be a frequent use case, I will briefly illustrate the usage of the EntityAdapter with the @ngrx/component-store.
14.02.2023
Angular
yb

Multiple Entity Collections in the Same Feature State: @ngrx/entity-Series – Part 2

After introducing the @ngrx/entity package, I am often asked how to manage multiple entity types in the same feature state. While I hope that the previous part of this article series has made this more apparent, I will further focus on this question in the following.
07.02.2023
Angular
yb

Managing Your Collections With the EntityAdapter: @ngrx/entity-Series – Part 1

This three-part series of blogposts is targeted at developers who have already gained experience with NgRx but still manage their collections themselves. In the first part I introduce the Entity Adapter, in the second part I show you how to connect it to NgRx and in the third part how to do it with the Component Store as well.
31.01.2023
Angular
MS-rund

Implementing Smart and Presentational Components with Angular: Condensed Angular Experiences – Part 4

In this article, we will explore how to apply the concept of smart and presentational components with Angular. We will choose a complex-enough target to see all aspects in action, yet understandable and within the scope of this article. The goal is to teach you how to use this architecture in your way. For that, we will iterate through different development stages, starting with the target selection and implementing it in a naive way. After the first development, we will refactor that naive solution into smart and presentational components that are reusable, refactor-friendly, and testable.
23.01.2023
Angular
SL-rund

Angular OnPush – A Change Detection Strategy Revealing Mistakes in Your Code

When optimizing the performance of Angular applications, many developers directly associate Angular's OnPush change detection strategy with it. But, if you don't know exactly how OnPush works under the hood, it will quickly teach you what you are doing wrong the hard way. In this article, we'll look deeper into how the OnPush strategy affects Angular's change detection mechanism and which pitfalls we should avoid at all costs.
24.10.2022