Mein Icon

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

10. Juli 2025·12 Minuten zu lesen
angular-hydration-ssr-defer-hydrate-transferstate

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
© Felix Stiffel 2025 | Alle Rechte vorbehalten