Hydration in Angular: SSR optimieren mit @defer, Hydrate-Optionen & Transfer State

Was bedeutet Hydration?
Hydration ist der Prozess, bei dem Angular serverseitig gerendertes HTML im Browser aktiv macht – durch Anhängen der JavaScript-Logik, ohne den DOM komplett neu aufzubauen. Das Ergebnis: Schnellere initiale Ladung, SEO-freundliche Inhalte und sofortige Interaktivität.
SSR mit Angular CLI: Hydration automatisch aktiviert
Wenn dein Projekt mit:
ng new my-app --ssr
oder:
ng add @angular/ssr
erstellt wurde, ist Hydration automatisch aktiviert durch Einbindung von provideClientHydration()
. Keine zusätzliche Konfiguration nötig.
Manuelle Einrichtung von Hydration (Custom Setup)
Standalone Components:
import { bootstrapApplication, provideClientHydration } from '@angular/platform-browser';
bootstrapApplication(AppComponent, {
providers: [provideClientHydration()]
});
NgModules:
import { NgModule } from '@angular/core';
import { provideClientHydration } from '@angular/platform-browser';
@NgModule({
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [provideClientHydration()],
})
export class AppModule {}
@defer
: Feinsteuerung von Lade- & Hydratisierungsverhalten
Angular 17 führt template-basierte deferrable views über @defer
ein – perfekt zur Reduzierung des initialen Bundle-Sizes.
Grundsyntax:
@defer {
<app-heavy-component />
}
Subblöcke für UX-Fallbacks:
@defer {
<app-heavy-chart />
} @placeholder { <p>Placeholder…</p> }
@loading { <p>Lade…</p> }
@error { <p>Fehler!</p> }
Übersicht: Optionen und Trigger
Die @defer
-Direktive erlaubt verschiedene Trigger, wann Inhalte geladen und hydriert werden:
Option | Beschreibung |
---|---|
on idle |
Rendert den Block, sobald der Browser inaktiv ist (nach requestIdleCallback ) |
on viewport |
Rendert, wenn das Element in den sichtbaren Bereich gescrollt wird |
on interaction(trigger) |
Rendert, wenn ein benannter DOM-Trigger (z. B. Button) aktiviert wurde |
prefetch |
Startet das Vorladen der benötigten Komponenten, bevor sie benötigt werden |
minimum Xms |
Mindestzeit, bevor @placeholder sichtbar wird |
hydrate on [event] |
Steuert, wann die Hydration erfolgt (nur mit Incremental Hydration) |
Beispiel mit mehreren Optionen:
@defer (on idle; prefetch; minimum 500ms; hydrate on viewport) {
<heavy-widget />
} @placeholder {
<p>Lade Widget…</p>
}
Neue Hydrate-Trigger – Incremental Hydration
Neben dem Laden der Komponenten steuert Angular auch, wann die Hydration (d. h. das Anhängen der Event-Handler und das Aktivieren der Interaktivität) stattfindet.
Übersicht: Hydrate-Trigger
Trigger | Beschreibung |
---|---|
hydrate on idle |
Hydriert, sobald der Browser nichts zu tun hat |
hydrate on viewport |
Hydriert, wenn das Element sichtbar wird |
hydrate on interaction |
Hydriert, sobald ein Benutzer mit dem Inhalt interagiert (z. B. Klick) |
hydrate on hover |
Hydriert, wenn der Benutzer mit der Maus über das Element fährt |
hydrate never |
Verhindert vollständig die automatische Hydration – nur sinnvoll für statischen, nicht-interaktiven Content |
hydrate when [expr] |
Hydriert, sobald eine angegebene Ausdrucksbedingung true ergibt |
Diese Trigger werden zusammen mit @defer
im Template verwendet:
@defer (on viewport; hydrate on interaction) {
<lazy-menu />
} @placeholder {
<p>Menü lädt…</p>
}
Sie ermöglichen eine stufenweise Aktivierung der Anwendung, was die Initialisierung beschleunigt und die Benutzererfahrung verbessert.
🧠 Konsistente Daten mit Transfer State
Beispiel: Blogpost nur einmal laden
import { TransferState, makeStateKey } from '@angular/platform-browser';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators';
export class BlogPostService {
constructor(
private http: HttpClient,
private state: TransferState
) {}
getPost(slug: string): Observable<Post> {
const key = makeStateKey<Post>(`post-${slug}`);
if (this.state.hasKey(key)) {
const post = this.state.get(key, null!);
this.state.remove(key);
return of(post);
}
return this.http
.get<Post>(`/api/post/${slug}`)
.pipe(
tap(post => this.state.set(key, post))
);
}
}
Transfer State erlaubt es, Daten vom Server ins HTML zu schreiben und beim Client-Bootstrapping wieder auszulesen. Das verhindert doppelte API-Calls und sorgt für konsistente Inhalte ohne Flickern.
Häufige Fehler und Best Practices
❌ DOM-Mismatch
✅ Lösung: Einheitliches Template + TransferState verwenden.
❌ Browser-APIs im SSR
✅ Lösung: isPlatformBrowser(this.platformId)
verwenden.
❌ Zu viele @defer
-Blöcke
✅ Lösung: @defer
nur für sekundäre UI-Elemente verwenden.
Fazit
Mit Angular 17+ sind @defer
und Hydration starke Werkzeuge zur Optimierung von SSR-Apps. Incremental Hydration in Angular 19 erweitert diese Kontrolle mit präzisen Hydrate-Triggern. TransferState sorgt für konsistente Daten und saubere Hydration.
✅ TL;DR
- Hydration automatisch aktiviert bei CLI-SSR-Projekten
@defer
ermöglicht granular lazy-loading im Template- Hydrate-Trigger aktivieren Incremental Hydration
- TransferState verhindert DOM-Mismatch und doppelte API-Calls