AngularAtlasAusg. 22.2

Kap. 12SSR & Hydration55 / 75

Hydration: Event Replay & inkrementell

Wie der Browser das Server-HTML übernimmt, ohne es neu zu rendern: vollständige Hydration, Event Replay, @defer (hydrate on …) und Mismatch-Fehler.

v22stabil ~0 Min. Lesezeit Offizielle Doku

Wenn die Seite fertig vom Server gerendert ankommt (SSR oder Prerendering), hat der Browser bereits das komplette DOM. Ohne Hydration würde Angular wie in einer CSR-Anwendung starten: Es würde dieses DOM wegwerfen und neu aufbauen — mit sichtbarem Flackern, kaputtem LCP und Layout Shift. Hydration bedeutet, dass Angular das vorhandene DOM durchläuft, mit dem Komponentenbaum abgleicht und wiederverwendet: Es verbindet die Bindings und hängt die Listener an die bereits existierenden Knoten.

Darauf aufbauend gibt es zwei Optimierungen: Event Replay — Klicks vor der Hydration gehen nicht verloren — und inkrementelle Hydration — Teile der Seite bleiben statisches HTML, ohne geladenes JS, bis sie wirklich gebraucht werden.

Kurz gesagt
  • Hydration verwendet das vom Server gesendete HTML wieder, statt es neu zu erzeugen, deshalb flackert die Seite beim Start nicht.
  • Event Replay merkt sich Klicks, bevor JavaScript geladen ist, und spielt sie danach ab.
  • Inkrementelle Hydration (@defer mit hydrate on …) lässt Teile der Seite nicht interaktiv, bis sie gebraucht werden. Ihr Code wird erst dann geladen.
  • Das HTML vom Server und das im Browser müssen identisch sein. Sonst gibt es Mismatch-Fehler mit Codes wie NG05xx.
  • ngSkipHydration ist der Notausgang für eine Komponente, die das DOM direkt verändert.
Was sich in v22 geändert hat
  • provideClientHydration() startet standardmäßig die inkrementelle Hydration und aktiviert automatisch das Event Replay.
  • withIncrementalHydration() ist deprecated (Entfernung in v24 geplant) — nimm es aus der Konfiguration, es ist bereits der Standard.
  • Die neue Opt-out-Option heißt withNoIncrementalHydration().

Was die Hydration Schritt für Schritt macht

Auf dem Server annotiert Angular nach dem Rendern das HTML, damit es später „wiedergefunden“ werden kann: das Attribut ngh auf jedem Komponenten-Host (ein Index in die Hydration-Daten), Anker-Kommentare für @if/@for/@defer, ein HTML-Kommentar nghm als Integritätsmarker, jsaction auf den Elementen mit Listenern und ein <script id="ng-state"> mit den Hydration-Daten (__nghData__) und den HTTP-Responses aus dem Transfer Cache.

@Component({
  selector: 'app-product-card',
  template: `
    <h2>{{ product().name }}</h2>
    @if (product().stock > 0) {
      <button (click)="addToCart()">In den Warenkorb</button>
    }
  `,
})
export class ProductCard {
  readonly product = input.required<Product>();
  addToCart() { /* ... */ }
}

Im Browser erzeugt Angular beim Bootstrap keine Knoten mehr: Es sucht die vorhandenen anhand der Annotationen. Für jeden Knoten prüft es Typ und Tag (nicht den Text) und hängt die Listener an. Ein abweichender Text ist kein Fehler — er wird bei der ersten Change Detection einfach überschrieben.

Sobald die Anwendung stabil ist (keine laufenden HTTP-Requests und keine PendingTasks), folgt die letzte Phase: Angular entfernt die Server-Knoten, die niemand beansprucht hat, spielt die Events aus der Warteschlange ab und schaltet den Transfer Cache aus. Deshalb hat eine Anwendung, die nie stabil wird, sichtbare Auswirkungen, selbst wenn das DOM korrekt wiederverwendet wurde.

Ohne HydrationVolle HydrationInkrementelle Hydration
Das DOM des Serversweggeworfen und neu erzeugtwiederverwendetwiederverwendet
JS beim Start nötigallesallesnur, was außerhalb der @defer (hydrate …)-Blöcke liegt
Wann ein Block interaktiv wirdnach dem erneuten Rendernbeim Bootstrap, die ganze Seite auf einmalbeim Trigger des Blocks
Klicks vor dem JSverlorennur mit withEventReplay() wiedergegebenwiedergegeben; ein Klick auf einen dehydrierten Block hydriert ihn

provideClientHydration und seine Optionen

Wenn du SSR mit ng add @angular/ssr hinzugefügt hast, steht der Provider bereits in app.config.ts. Ohne Argumente bekommst du in v22 das empfohlene Set:

import { ApplicationConfig } from '@angular/core';
import { provideClientHydration } from '@angular/platform-browser';

export const appConfig: ApplicationConfig = {
  providers: [
    // v22, ohne Argumente:
    //  ✓ nicht-destruktive Hydration (nutzt das DOM des Servers weiter)
    //  ✓ HTTP Transfer Cache (GETs/HEADs vom Server werden im Browser nicht wiederholt)
    //  ✓ inkrementelle Hydration (@defer mit hydrate …) — inklusive Event Replay
    //  ✓ im Dev-Modus: provideStabilityDebugging()
    provideClientHydration(),
  ],
};
// app.config.server.ts ruft mergeApplicationConfig(appConfig, serverConfig) auf,
// der Provider landet also auch auf dem Server — Pflicht, sonst erscheint NG0505.
FunktionWas sie machtIn v22
provideClientHydration()nicht-destruktive Hydration + HTTP Transfer Cache + inkrementelle Hydration (mit Event Replay)das Standard-Set
withNoIncrementalHydration()schaltet die inkrementelle Hydration aus (und damit das Event Replay)neu in v22
withEventReplay()Event Replay ohne inkrementelle Hydrationstandardmäßig enthalten; explizit nur mit dem Opt-out oben
withI18nSupport()hydriert auch Komponenten mit i18n-Blöcken; ohne sie werden diese komplett neu gerendertoptional
withHttpTransferCacheOptions({…})legt fest, welche Responses im HTML landen: filter, includeHeaders, includePostRequests, includeRequestsWithAuthHeaders…optional
withNoHttpTransferCache()schaltet den Transfer Cache aus: Jeder GET wird zweimal ausgeführtoptional
withIncrementalHydration()aktivierte früher die inkrementelle Hydrationdeprecated seit v22 (Entfernung in v24 geplant)

Der Provider muss auch in der Server-Konfiguration vorhanden sein — die vom CLI generierte app.config.server.ts ruft mergeApplicationConfig(appConfig, serverConfig) auf, er ist also automatisch dabei. Fehlt er, annotiert der Server das HTML nicht, und im Browser wird die Seite komplett neu gerendert (im Dev-Modus mit der Warnung NG0505). Widersprüchliche Kombinationen (zum Beispiel withNoHttpTransferCache() mit withHttpTransferCacheOptions()) werfen im Dev-Modus den Fehler NG05001.

Event Replay

Das Problem: Das HTML des Servers ist lange sichtbar, bevor das JS ankommt (in der Timeline auf der SSR-Seite ist das der gelbe Streifen). Der Nutzer sieht einen Button und drückt ihn — aber der Button hat noch keinen Listener.

Der Mechanismus basiert auf JSAction, einer in Angular integrierten Event-Delegation-Bibliothek:

  1. Markieren — bei der Serialisierung setzt der Server jsaction="click:;" auf jedes Element, das im Template einen Listener hat.
  2. Abfangen — ein kleines Inline-Skript, direkt nach <body> eingefügt (der Event Contract), lauscht auf body-Ebene auf die auf der Seite verwendeten Event-Typen und hält sie im Speicher.
  3. Wiedergeben — nach der Hydration, sobald die Anwendung stabil ist, schickt Angular die gespeicherten Events der Reihe nach an die echten Handler.

Es funktioniert für die nativen Browser-Events (click, mouseover, focusin usw.). Bei der inkrementellen Hydration bleibt der Contract auch nach der Hydration aktiv, sodass er Events in noch dehydrierten Blöcken abfangen kann.

LiveEvent Replay: Klicks vor der Hydration (Simulation)
magazin.ro/produse/42hydriert · interaktiv
Kabellose Kopfhörer Aria X2
349 RON
Warenkorb: 0Favoriten: 0
main.js · ausgeführt
Warteschlange des Event Contracts (im Speicher)
leer
  • Drücke „Seite neu laden“ und klicke dann auf die Buttons, solange der JS-Balken nicht voll ist.
Vor der Hydration: 0 Klicks · wiedergegeben 0 · verloren 0
Drücke „Seite neu laden“ und klicke dann ein paar Mal, solange der main.js-Balken nicht voll ist. Mit aktivem Replay „holen“ die Zähler nach der Hydration auf; schalte es aus und wiederhole: Die Klicks gehen verloren.
Visuelles Feedback im Hydration-Fenster

Das Replay rettet die Aktion, aber der Button reagiert bis zur Hydration nicht sichtbar. Die CSS-Zustände (:hover, :active, :focus-visible) funktionieren ohne JS — nutze sie, damit der Nutzer weiß, dass der Klick „angekommen“ ist.

Inkrementelle Hydration mit @defer

Ein normales @defer rendert auf dem Server nur den @placeholder: Die Trigger laufen auf dem Server nicht. Ein hydrate-Trigger ändert das: Der Server lädt die Abhängigkeiten des Blocks und rendert den Hauptinhalt. Im Browser bleibt der Block dehydriert — das HTML ist sichtbar, aber der JS-Chunk der darin enthaltenen Komponenten wird nicht einmal geladen —, bis der Trigger feuert. Dann lädt Angular den Chunk, hydriert den Block und spielt die gespeicherten Events ab.

Zwei praktische Folgen. Erstens: Du kannst @defer above the fold verwenden, ohne Layout Shift, weil der endgültige Inhalt bereits auf dem Bildschirm steht und nicht der Placeholder. Zweitens: Ein Event auf einem Element mit Listener in einem dehydrierten Block löst dessen Hydration aus, egal welcher Trigger deklariert ist — der Klick geht nicht verloren. Die Ausnahme ist hydrate never: Sein Teilbaum wird gar nicht annotiert, es gibt also nichts abzuspielen.

<app-header />                                    <!-- kein @defer: wird beim Bootstrap hydriert -->

@defer (hydrate on interaction) {
  <app-gallery [images]="product().images" />     <!-- JS der Galerie: erst beim ersten Klick -->
} @placeholder {
  <div class="gallery-skeleton"></div>            <!-- nur bei Client-Side-Navigation verwendet -->
}

@defer (hydrate on hover) {
  <app-recommendations [productId]="id()" />
} @placeholder {
  <div class="reco-skeleton"></div>
}

@defer (hydrate on idle) {
  <app-support-chat />
} @placeholder {
  <button>Chat</button>
}

@defer (hydrate on viewport) {
  <app-reviews [productId]="id()" />              <!-- unterhalb des sichtbaren Bereichs: JS, sobald er im Bild erscheint -->
} @placeholder {
  <div class="reviews-skeleton"></div>
}

@defer (hydrate never) {
  <app-footer />                                  <!-- für immer statisches HTML -->
}
LiveInseln, die bei Bedarf hydriert werden (Simulation)
JS geladen: 0 KB von 218 KB · 0/6 aktive Blöcke
Headerkein @defer (main.js)dehydriert48 KB, nicht geladen
Galeriehydrate on interactiondehydriert36 KB, nicht geladen
Bild 1 / 4
Empfehlungenhydrate on hoverdehydriert22 KB, nicht geladen
Aria-Hülle · 49 RON
Support-Chathydrate on idledehydriert30 KB, nicht geladen
Fragen?
Produktbeschreibung, Spezifikationen, Lieferung…
↓ scrolle runter zu den Bewertungen ↓
Bewertungenhydrate on viewportdehydriert64 KB, nicht geladen
★★★★☆ · 3 Bewertungen angezeigt
Footerhydrate neverstatisch, ohne JS0 KB (wären 18)
Kontakt · AGB · Rückgabe · © 2026
  • Die Simulation startet, sobald die Demo im Bild erscheint (oder drücke „Neu laden“).
Klicke auf die Galerie, fahre über die Empfehlungen, scrolle runter zu den Bewertungen. Beobachte, welcher Block hydriert, warum und wie viele KB er kostet; wechsle dann auf „Komplett“ und vergleiche das beim Start geladene JS.

Die Hydration-Trigger

@defer (hydrate on idle) { … }                    <!-- requestIdleCallback -->
@defer (hydrate on idle(500)) { … }               <!-- idle, spätestens aber nach 500 ms -->
@defer (hydrate on viewport) { … }                <!-- der Inhalt des Blocks erscheint im Bild -->
@defer (hydrate on viewport({ rootMargin: '200px' })) { … }  <!-- nur literale Optionen -->
@defer (hydrate on interaction) { … }             <!-- click / keydown im Block -->
@defer (hydrate on hover) { … }                   <!-- mouseover / focusin im Block -->
@defer (hydrate on immediate) { … }               <!-- direkt nach dem Rest der Seite -->
@defer (hydrate on timer(2s)) { … }               <!-- ms oder s -->
@defer (hydrate when cartReady()) { … }           <!-- Bedingung aus der Eltern-Komponente -->
@defer (hydrate never) { … }                      <!-- nie; keine anderen Hydrate-Trigger -->
@defer (hydrate on viewport; hydrate on timer(5s)) { … }  <!-- mehrere = einer davon genügt (OR) -->

<!-- ✗ Kompilierfehler -->
@defer (hydrate on interaction(btn)) { … }        <!-- interaction/hover nehmen keine Referenz -->
@defer (hydrate on viewport({ trigger: el })) { … }
@defer (hydrate never; hydrate on idle) { … }     <!-- never schließt jeden anderen Hydrate-Trigger aus -->
TriggerFeuert, wennParameter
hydrate on idleder Browser frei ist (requestIdleCallback)optional, ein Timeout: idle(500)
hydrate on viewportder Inhalt des Blocks im Bild erscheintoptional, literale IntersectionObserver-Optionen; keine Referenz auf ein anderes Element
hydrate on interactionclick oder keydown im Blockkeine
hydrate on hovermouseover oder focusin im Blockkeine
hydrate on immediatesobald der Rest der Seite fertig gerendert ist—
hydrate on timer(…)nach einem Intervallerforderlich, in ms oder s
hydrate when exprder Ausdruck truthy wirdfunktioniert nur beim äußersten dehydrierten Block
hydrate nevernie: statisches HTML, samt dem ganzen Teilbaumnicht mit anderen hydrate-Triggern kombinierbar

Mehrere Trigger am selben Block werden mit „beliebig“ (OR) kombiniert. hydrate when hat eine Einschränkung: Der Ausdruck gehört zur Eltern-Komponente, die selbst hydriert sein muss, damit der Ausdruck ausgewertet werden kann.

Verschachtelte Blöcke

Der Komponentenbaum ist hierarchisch: Ein Kind kann nicht aktiv sein ohne seinen Elternteil. Wenn der Trigger bei einem verschachtelten Block feuert, hydriert Angular die Kette von oben nach unten — zuerst den äußersten dehydrierten Block, dann einen nach dem anderen bis zu dem, der angefragt hat.

@defer (hydrate on interaction) {
  <app-product-tabs />                <!-- 1. zuerst wird die Eltern-Komponente hydriert… -->
  @defer (hydrate on hover) {
    <app-size-guide />                <!-- 2. …dann das Kind, auch wenn der Hover darauf lag -->
  }
}

Hydrate-Trigger bei CSR und Navigation

Hydration ist eine Optimierung des Erstaufrufs von serverseitig gerendertem Inhalt. Wenn der Nutzer dieselbe Seite über Client-Side-Navigation erreicht (ein routerLink) oder die Anwendung gar kein SSR hat, werden die hydrate-Trigger ignoriert: Der Block verhält sich wie ein normales @defer, mit seinem @placeholder und den normalen Triggern. Hast du keinen normalen Trigger angegeben, fügt der Compiler on idle hinzu.

@defer (on interaction; hydrate on viewport) {
  <app-reviews />
} @placeholder {
  <button>Bewertungen anzeigen</button>
}

<!--
  Erstaufruf, auf dem Server gerenderte Seite:
    → der Server rendert <app-reviews /> (nicht den Placeholder)
    → im Browser bleibt es statisches HTML, bis es den Viewport erreicht (hydrate on viewport)

  Client-Side-Navigation (routerLink) oder Anwendung ohne SSR:
    → hydrate on viewport wird ignoriert
    → der @placeholder wird angezeigt, der Block lädt beim Klick (on interaction)
    → ohne normalen Trigger wäre der Standard on idle gewesen
-->
  • @placeholder bleibt nötig — beim Erstaufruf mit SSR wird er nicht angezeigt, bei jeder Client-Side-Navigation zur Seite aber schon.
  • hydrate never bedeutet „beim Erstaufruf nie JS“. Beim späteren Client-Side-Rendering lädt der Block seine Abhängigkeiten trotzdem, mit dem normalen Trigger.
  • In einer Anwendung ohne provideClientHydration() (oder mit withNoIncrementalHydration()) erzeugen Blöcke mit hydrate-Triggern im Dev-Modus die Warnung NG0508.

Mismatch-Fehler

Die Hydration beginnt mit einem Versprechen: Das DOM im Browser ist exakt das, das der Server erzeugt hat, einschließlich Kommentaren und Leerzeichen. Alles, was das Versprechen bricht — der HTML-Parser des Browsers, ein Drittanbieter-Skript, ein CDN, ein anderer Template-Zweig —, endet in einer von drei Situationen: ein Fehler, eine Warnung oder, am heimtückischsten, kein Fehler, aber ein sichtbares erneutes Rendern.

CodeBedeutetTypische Ursache
NG0500der gefundene Knoten ist nicht der erwartete (anderer Tag oder Typ) oder fehltungültiges HTML, direkte DOM-Manipulation, ein Drittanbieter-Skript
NG0501Geschwisterknoten fehlenKnoten von außerhalb von Angular entfernt
NG0502der Knoten wird an der erwarteten Position nicht gefundenStruktur nach dem Server verändert
NG0503projizierte Knoten außerhalb von Angular erzeugtcreateComponent mit projectableNodes aus dem nativen DOM
NG0504ngSkipHydration auf einem Element, das kein Komponenten-Host istdas Attribut auf einem div
NG0505(Warnung) die Annotationen vom Server fehlenprovideClientHydration() fehlt in der Server-Konfiguration
NG0506(Warnung) die Anwendung wird nicht innerhalb von 10 s stabilunbeendete PendingTasks; mit Zone.js Timer in der Angular-Zone
NG0507das HTML wurde nach dem Server verändertein CDN, das die Kommentare entfernt
LiveMismatch-Explorer (Simulation)
Dein Code
<p class="promo">
  <div>Heute kostenlose Lieferung</div>
</p>
Vom Server gesendetes HTML
<p class="promo"><div>Heute kostenlose Lieferung</div></p>
DOM im Browser, vor der Hydration
<p class="promo"></p><div>Heute kostenlose Lieferung</div><p></p>
Fehler · NG0500
Konsole
NG0500: During hydration Angular expected <div> but the node was not found.

Angular expected this DOM:

  <p class="promo">
    <div>…</div>  <-- AT THIS LOCATION
    …
  </p>

To fix this problem:
  * check the "PromoBanner" component for hydration-related issues
  * check to see if your template has valid HTML structure
  …

Was passiert: Der Server baut das DOM über APIs auf, daher übersteht die ungültige Verschachtelung bis zur Serialisierung. Der HTML-Parser des Browsers schließt das <p> jedoch, sobald er das <div> sieht, und Angular findet den erwarteten Knoten nicht mehr.

Lösung: Gültiges HTML: <p> akzeptiert nur Inline-Inhalt. Nimm ein <div class="promo"> als Elternelement oder ein <span> im Inneren.

Wähle ein Muster: Du siehst den Code, das vom Server gesendete HTML, das DOM, das Angular im Browser findet, und das Ergebnis. Die Konsolenmeldungen sind (gekürzt) aus den Angular-22-Quellen zitiert.
Unterschiedliche Zweige auf Server und im Browser

@if (isPlatformBrowser(…)) in einem Template wirft keinen Fehler, ist aber einer der teuersten Fehler: Angular wirft das DOM des Servers für den Block weg und baut es neu auf, mit Layout Shift. Halte die Ausgabe auf beiden Plattformen identisch und verlege die Browser-only-Initialisierung in afterNextRender — oder nutze @defer, das auf dem Server den Placeholder rendert. Die Varianten findest du auf der Seite Server-kompatibler Code.

ngSkipHydration: der Notausgang

Für eine Komponente, die sich nicht sofort reparieren lässt (typischerweise eine Bibliothek, die direkt ins DOM zeichnet, wie D3), nimmt das Attribut ngSkipHydration auf ihrem Host sie aus der Hydration heraus: Die Komponente und ihre Kinder werden zerstört und neu gerendert, genau wie ohne Hydration. Es funktioniert nur auf Komponenten-Hosts (sonst NG0504), und auf der Root-Komponente deaktiviert es die Hydration für die ganze Anwendung.

<!-- auf dem Host der Komponente, die das DOM direkt manipuliert (z. B. ein D3-Diagramm) -->
<app-sales-chart ngSkipHydration [data]="sales()" />

<!-- ✗ NG0504: nur auf Komponenten-Hosts, nicht auf normalen Elementen -->
<div ngSkipHydration><app-sales-chart [data]="sales()" /></div>

Debugging

  • Die Konsole im Dev-Modus: Sobald die Anwendung stabil ist, erscheint eine Zusammenfassung. Siehst du sie nicht, hat die Hydration nicht gestartet (prüfe NG0505).
  • Angular DevTools zeigt den Hydration-Zustand jeder Komponente und kann ein Overlay über den hydrierten Teilen einblenden; bei einem Mismatch-Fehler hebt es die verantwortliche Komponente hervor.
  • Seitenquelltext vs. Elements: Der Seitenquelltext ist das HTML des Servers, Elements ist das aktuelle DOM. Die Unterschiede zwischen beiden (ein zusätzliches tbody, ein eingeschleustes Banner) sind genau die Ursachen von NG0500.
  • JavaScript ausschalten in den DevTools und neu laden: Du siehst genau, was der Nutzer vor der Hydration bekommt.
  • NG0506: provideStabilityDebugging() listet die Tasks auf, die die Anwendung instabil halten (mit Zone.js zusätzlich zone.js/plugins/task-tracking importieren).
  • preserveWhitespaces muss in tsconfig.app.json und tsconfig.server.json denselben Wert haben; der Standard (false) ist der empfohlene.
Angular hydrated 14 component(s) and 212 node(s), 0 component(s) were skipped.
5 defer block(s) were configured to use incremental hydration.
Learn more at https://angular.dev/guide/hydration.

Wann ja, wann nein

Einsetzen
  • Hydration: immer, wenn du SSR oder Prerendering hast. Ohne sie verliert SSR den halben Sinn (das DOM wird neu aufgebaut).
  • Event Replay: standardmäßig aktiv; am wichtigsten auf Seiten mit schnellen Aktionen (Warenkorb, Like, Menü) und bei langsamen Netzen.
  • hydrate on viewport für alles unterhalb des sichtbaren Bereichs: Bewertungen, ähnliche Produkte, ein umfangreicher Footer.
  • hydrate on interaction / hover für schwere Widgets, die bis zur ersten Berührung brachliegen: Galerien, Filter, Größenauswahl.
  • hydrate never für wirklich statischen Inhalt: einen Artikel, AGB, einen Footer ohne Logik.
Vermeiden / die Alternative
  • Anwendungen ohne SSR: Die hydrate-Trigger bewirken nichts. Nutze @defer mit normalen Triggern.
  • @defer (hydrate …) bei Komponenten von wenigen KB: Der zusätzliche Chunk und Request kosten mehr, als du sparst.
  • hydrate never bei etwas mit Listenern oder Zustand: Es funktioniert beim Erstaufruf nie.
  • ngSkipHydration als dauerhafter „Fix“: Behebe die Ursache (gültiges HTML, afterNextRender, über Angular manipuliertes DOM).
  • isPlatformBrowser-Zweige im Template, um Probleme zu verstecken: Die Alternative ist @defer oder afterNextRender.

Häufige Stolperfallen

Direkte DOM-Manipulation

nativeElement.appendChild, innerHTML, document.querySelector(…).remove() in Komponenten, die auch auf dem Server laufen, erzeugen Strukturen, die die Hydration nicht abgleichen kann. Nutze das Template (@if, @for, Bindings, Renderer2) und verschiebe reinen Browser-Code in afterNextRender.

  • Ungültiges HTML: ein <div> in einem <p>, ein <a> in einem <a>, eine Tabelle ohne <tbody>. Validiere das Template; der Browser „repariert“ HTML anders, als der Server es geschrieben hat.
  • Unterschiedliche Werte auf Server und Client (Date.now(), Math.random(), generierte IDs, Zeitzonen): kein Fehler, aber der Text ändert sich vor den Augen des Nutzers. Übertrage den Wert mit TransferState.
  • Drittanbieter-Skripte (Analytics, Consent, Chat), die das DOM vor der Hydration verändern: Lade sie danach, mit afterNextRender.
  • withEventReplay() und withIncrementalHydration() „sicherheitshalber“ stehen gelassen in v22: Das erste ist überflüssig, das zweite deprecated. Ein schlichtes provideClientHydration() reicht.
  • Ein entfernter @placeholder bei den Blöcken mit hydrate, weil „man ihn ja eh nicht sieht“: Bei Client-Side-Navigation sieht man ihn.
  • Personenbezogene Daten im Transfer Cache: Responses landen im HTML. Requests mit Authorization/Cookie sind standardmäßig ausgeschlossen — nimm sie nicht ohne Grund mit includeRequestsWithAuthHeaders auf; nutze filter oder transferCache: false.
  • Ein CDN mit HTML-Minifizierung, das die Kommentare entfernt → NG0507 auf jeder Seite.

Spickzettel

// ── Config (app.config.ts; landet über mergeApplicationConfig auch auf dem Server)
provideClientHydration();                                     // v22: DOM + Transfer Cache + inkrementell + Replay
provideClientHydration(withNoIncrementalHydration(), withEventReplay());
provideClientHydration(withI18nSupport());
provideClientHydration(withHttpTransferCacheOptions({ filter, includeHeaders, includePostRequests }));
provideClientHydration(withNoHttpTransferCache());
http.get(url, { transferCache: false });                      // Opt-out pro Request

// ── Template
// @defer (hydrate on idle | idle(ms) | viewport | viewport({ rootMargin }) | interaction | hover | immediate | timer(2s))
// @defer (hydrate when cond)      @defer (hydrate never)      @defer (on idle; hydrate on viewport)
// <app-chart ngSkipHydration />   host: { ngSkipHydration: 'true' }   ← letzter Ausweg

// ── Fehler
// NG0500 anderer Knoten   NG0501 Geschwisterknoten fehlen   NG0502 Knoten fehlt   NG0503 projizierte Knoten außerhalb von Angular erzeugt
// NG0504 ngSkipHydration auf Nicht-Komponente   NG0505 Annotationen fehlen (Provider fehlt auf dem Server)
// NG0506 die Anwendung wird nicht innerhalb von 10 s stabil   NG0507 HTML nach dem Server verändert (Kommentare entfernt)
// NG0508 Hydrate-Trigger ohne aktive inkrementelle Hydration

Kap. 12 · 0 von 3 abgeschlossen

Lektion abgeschlossen?

Markiere sie, dann erscheint sie auf deiner Karte: im Inhaltsverzeichnis und auf der Startseite.

Wird automatisch markiert, sobald du die ganze Lektion gelesen hast.

  1. SSR, Prerendering & Render Modes
  2. Hydration: Event Replay & inkrementell
  3. Servertauglicher Code
Deine ganze Karte ansehen

Alle 75 Seiten · tippen zum Filtern

  • 01Was ist neu in Angular 21 & 22Alle wichtigen Änderungen in v21 und v22 in Kürze, mit Link zur Seite, die sie jeweils erklärt.Start
  • 01Deine erste App, Schritt für SchrittEine Leseliste, von einer leeren Komponente bis zur fertigen App — Signals, @for, Inputs und Outputs, ein Service und ein Formular, Schritt für Schritt.Start
  • 01Schnelle Entscheidungen„Wohin damit?“, „Signal oder Observable?“, „Shared oder Feature?“ — kurze Antworten auf Alltagsfragen.Start
  • 01Angular-Interviewfragen60 echte Interviewfragen für Junior, Mid und Senior, mit der passenden Antwort, der Nachfrage und den Warnsignalen. Dazu ein Probeinterview.Start
  • 02Standalone & BootstrapWie eine App ohne NgModule startet: bootstrapApplication, app.config.ts, imports in der Komponente.Moderne Grundlagen
  • 02Data Binding & EventsInterpolation, Property- und Attribut-Bindings, Events mit $event und Tastenfiltern und wie [( )] aufgebaut ist — was in das DOM geht und was zurückkommt.Moderne Grundlagen
  • 02Control Flow: @if, @for, @switchDie Block-Syntax, die *ngIf/*ngFor/ngSwitch ersetzt, mit track, @empty und Exhaustive Checks.Moderne Grundlagen
  • 02@let und die neuen Template-AusdrückeLokale Variablen mit @let, Arrow Functions, Spread, Regex, instanceof, Kommentare in Tags.Moderne Grundlagen
  • 02@defer — Lazy Loading in TemplatesSchwere Komponenten nur laden, wenn sie gebraucht werden: Trigger, Prefetch, Placeholder, Loading, Error.Moderne Grundlagen
  • 02Class- & Style-BindingsWarum [class.x] und [style.x] ngClass und ngStyle abgelöst haben (mit automatischer Migration ab v21).Moderne Grundlagen
  • 02Komponenten-Styles & Kapselung:host, die drei Kapselungsmodi, Theming mit CSS-Variablen und warum ::ng-deep der letzte Ausweg ist.Moderne Grundlagen
  • 02Pipes: wann und wiePure vs. Impure Pipes, eigene Pipes und wie du zwischen Pipe, computed() und Methode wählst.Moderne Grundlagen
  • 03signal() und computed()Die reaktiven Grundbausteine: beschreibbarer Zustand, abgeleiteter Zustand, Gleichheit, untracked und Regeln zur Immutability.Signals & Reaktivität
  • 03effect() — wann ja, wann neinMit Signals synchronisierte Seiteneffekte: localStorage, Logging, imperative APIs. Und ihre Stolperfallen.Signals & Reaktivität
  • 03linkedSignal() — editierbarer abgeleiteter ZustandEin Signal, das sich zurücksetzt, wenn sich seine Quelle ändert, das du aber auch manuell setzen kannst.Signals & Reaktivität
  • 03resource, rxResource, httpResourceAsynchrone Daten als Signals: status, value, error, reload, automatischer Abbruch. Stabil seit v22.Signals & Reaktivität
  • 03debounced() — verzögerte SignalsDie „Debounce“-Variante eines Signals, ohne RxJS. Perfekt für die Suche.Signals & Reaktivität
  • 03Listen: suchen, filtern, sortieren, blätternEine Kette von computed-Signals, die nur neu berechnet, was sich geändert hat — mit den Filtern in der URL, damit ein Link dieselbe Ansicht öffnet.Signals & Reaktivität
  • 03Observables von null anWas ein Observable ist, subscribe und unsubscribe, die Operatoren, die du jede Woche brauchst, cold vs. hot — und wann ein Signal reicht.Signals & Reaktivität
  • 03Signals ↔ RxJStoSignal, toObservable, takeUntilDestroyed, outputFromObservable — und wann RxJS weiterhin die richtige Wahl bleibt.Signals & Reaktivität
  • 04input() und output()Inputs als Signals (required, transform, alias) und typisierte Outputs. Daten nach unten, Events nach oben.Komponenten: Kommunikation
  • 04model() — Two-Way-BindingBanana-in-a-Box [( )] mit einer einzigen API. Wann du es nutzt und wann input + output besser ist.Komponenten: Kommunikation
  • 04viewChild & contentChildQueries als Signals: viewChild, viewChildren, contentChild, contentChildren, die Option read.Komponenten: Kommunikation
  • 04Lifecycle & DestroyRefWelche Hooks in der Signals-Ära noch zählen, afterNextRender, DestroyRef und typisiertes ngOnChanges.Komponenten: Kommunikation
  • 04Content Projectionng-content mit select, mehrere Slots, Standardinhalt und die Falle der bedingten Projektion.Komponenten: Kommunikation
  • 04ng-template & ngTemplateOutletTemplates als Werte: Render Props in Angular, typisierter Kontext und Anpassen von Komponenten.Komponenten: Kommunikation
  • 05Smart vs. DumbContainer vs. Presentational: wer den Zustand hält, wer nur anzeigt und wie du die beiden sauber trennst.Komponenten-Design
  • 05Generische Komponenten <T>Eine korrekt typisierte DataTable<T> oder Select<T>, mit Templates für Zellen.Komponenten-Design
  • 05Dynamische KomponentenNgComponentOutlet, createComponent mit inputBinding/outputBinding und ein Dashboard, das aus einer Konfiguration gebaut wird.Komponenten-Design
  • 05Direktiven & Host-KompositionAttribut-Direktiven, die host: {}-Metadaten und die Directive Composition API (hostDirectives).Komponenten-Design
  • 05Eigene Formular-ControlsFormValueControl (Signal Forms) vs. ControlValueAccessor: eine Sternebewertung, in beiden Varianten.Komponenten-Design
  • 05Change DetectionOnPush ist ab v22 der Standard, zone.js entfällt ab v21. Was das Rendering auslöst und wie du dir nicht die Finger verbrennst.Komponenten-Design
  • 06inject() & @Service()Der neue @Service()-Decorator ab v22, inject() vs. Konstruktor und der Injection-Kontext.Dependency Injection
  • 06Provider & die Injector-HierarchieRoot vs. Route vs. Komponente, useClass/useValue/useFactory/useExisting und die Modifier optional/self/skipSelf.Dependency Injection
  • 06InjectionToken & provideX()Typisierte Konfiguration, provideFeature()-Funktionen, makeEnvironmentProviders und Initializer.Dependency Injection
  • 06injectAsync() — Lazy ServicesLade einen schweren Service erst, wenn du ihn brauchst, mit Prefetch im Leerlauf.Dependency Injection
  • 07Ordnerstrukturcore / shared / features, was in welchen Ordner gehört und wie ein Feature von innen aussieht.Architektur der Anwendung
  • 07Shared vs. FeatureWann du eine Komponente nach Shared verschiebst und (vor allem) wann NICHT. Eine konkrete Checkliste.Architektur der Anwendung
  • 07Interfaces & ModelleInline-Interface oder eigene Datei? DTO vs. Domänenmodell, type vs. interface, wohin damit.Architektur der Anwendung
  • 07State Management mit SignalsEinfache Signal-Stores, Fassaden, lokaler vs. globaler Zustand und wann du NgRx brauchst.Architektur der Anwendung
  • 07Styleguide & NamensgebungDie aktuellen offiziellen Konventionen: Dateinamen ohne Suffixe, protected, readonly, Reihenfolge der Member.Architektur der Anwendung
  • 07Barrels, Aliase & Grenzenindex.ts, Pfad-Aliase, die öffentliche API eines Features und Abhängigkeitsregeln, die sich automatisch prüfen lassen.Architektur der Anwendung
  • 07Fehler: @boundary & ErrorHandlerDer neue @boundary-Block ab v22.2, der globale ErrorHandler, HTTP-Fehler und Fehler aus resource.Architektur der Anwendung
  • 08Modernes Routing & Lazy LoadingloadComponent, Child Routes, Parameter als Inputs und Parameter-Vererbung (neuer Standard in v22).Routing
  • 08Guards & ResolvercanActivate, canMatch, canDeactivate und resolve als Funktionen, mit Redirects über UrlTree / RedirectCommand.Routing
  • 09Signal Forms — die GrundlagenFormulare auf Basis von Signals: form(), [formField], schemabasierte Validierung. Stabil seit v22.Formulare
  • 09Signal Forms — fortgeschrittenEigene und feldübergreifende Validierung, async/HTTP mit Debounce, dynamische Listen, disabled/hidden, wiederverwendbare Schemas.Formulare
  • 09Typisierte Reactive FormsTypisierte FormGroup, nonNullable, FormArray — und wie sie neben Signal Forms bestehen.Formulare
  • 10HttpClient, Interceptors & die API-SchichtHttpClient ohne Setup (v21), Fetch als Standard (v22), funktionale Interceptors und eine API-Schicht mit DTO-Mapping.HTTP & Daten
  • 11Performance — eine ChecklisteWas wirklich zählt: OnPush + Signals, track, @defer, Lazy Routes, Bilder, Bundles und Hydration.Qualität & Performance
  • 11Testen mit VitestVitest ist ab v21 der Standard-Runner. TestBed, Komponenten mit Signals, Services, HTTP und Harnesses.Qualität & Performance
  • 11DevTools: ein Blick in deine AppChrome DevTools und Angular DevTools Schritt für Schritt: was jedes Panel zeigt, mit Übungen, die auf dieser Website funktionieren.Qualität & Performance
  • 11Angular AriaHeadless, barrierefreie Komponenten, die du nach Belieben stylst: Tabs, Accordion, Menü, Listbox...Qualität & Performance
  • 12SSR, Prerendering & Render ModesWann auf dem Server gerendert wird, wann beim Build und wann nur im Browser: RenderMode pro Route, app.routes.server.ts und die echten Kosten.SSR & Hydration
  • 12Hydration: Event Replay & inkrementellWie der Browser das Server-HTML übernimmt, ohne es neu zu rendern: vollständige Hydration, Event Replay, @defer (hydrate on …) und Mismatch-Fehler.SSR & Hydration
  • 12Servertauglicher Codewindow gibt es auf dem Server nicht: PLATFORM_ID, afterNextRender, DOCUMENT, TransferState, der HTTP-Cache und PendingTasks.SSR & Hydration
  • 13Micro FrontendsWann es sich lohnt, eine App in mehrere Deployments aufzuteilen und wann es nur Komplexität ist: Native Federation, Module Federation, iframes, Web Components.Architektur im großen Maßstab
  • 13Web Components mit Angular ElementscreateCustomElement: eine Angular-Komponente, die überall als HTML-Tag nutzbar ist, plus Kommunikation zwischen Apps über Events und BroadcastChannel.Architektur im großen Maßstab
  • 13Monorepo, Bibliotheken & GrenzenEin Workspace mit mehreren Apps und Bibliotheken: ng generate library, Nx, Secondary Entry Points, Publishing und Abhängigkeitsregeln.Architektur im großen Maßstab
  • 13Hexagonale Architektur (Ports & Adapters)Eine Domäne ohne Angular, Ports als abstrakte Klassen und austauschbare Adapter: HTTP, localStorage oder In-Memory, ohne die UI anzufassen.Architektur im großen Maßstab
  • 14Signals unter der HaubeDer reaktive Graph: Producer und Consumer, Push-Pull, warum computed lazy und glitch-frei ist, das Diamond-Problem und wann Effects laufen.Fortgeschrittene Reaktivität
  • 14Fortgeschrittenes RxJS: Operatoren höherer OrdnungswitchMap, mergeMap, concatMap und exhaustMap an einem Live-Diagramm, dazu Retry mit Backoff, shareReplay und wie du Leaks vermeidest.Fortgeschrittene Reaktivität
  • 14NgRx SignalStoreState Management im großen Stil auf Signals: withState, withComputed, withMethods, rxMethod, Entities und Hooks — und wann ein einfacher Store reicht.Fortgeschrittene Reaktivität
  • 14Zustandsautomaten mit SignalsKeine unmöglichen Zustände mehr: ein typisierter Automat auf Signals, mit Übergängen, Guards und einem Live-Zustandsdiagramm.Fortgeschrittene Reaktivität
  • 15WebSockets: Echtzeit, die das Netz überstehtEin typisierter Socket als Signals: Reconnect mit Backoff und Jitter, Heartbeat, ein Postausgang im Offline-Modus und SSR-Sicherheit.Echtzeit & offline
  • 15Optimistische Updates & RollbackEine sofortige UI, die ehrlich bleibt: Snapshot und Rollback, Antworten in falscher Reihenfolge, Idempotenzschlüssel.Echtzeit & offline
  • 15Offline-first: Service Worker & CachingDer Angular Service Worker: Caching-Strategien, Update-Hinweise und ein Postausgang für Änderungen, die offline entstehen.Echtzeit & offline
  • 16Web WorkersSchwere Berechnungen, ohne die UI zu blockieren: ein echter Worker in der Seite, Message Passing und wann es sich nicht lohnt.Fortgeschrittene UI & Performance
  • 16Riesige Listen: Virtual Scroll100.000 Zeilen ohne Ruckeln: CDK Virtual Scroll, itemSize, trackBy und die Alternativen (Paginierung, Infinite Scroll).Fortgeschrittene UI & Performance
  • 16Moderne Animationen & View Transitionsanimate.enter und animate.leave statt des veralteten @angular/animations, CSS-Transitions und View Transitions bei der Navigation.Fortgeschrittene UI & Performance
  • 16Memory Leaks finden und behebenSubscriptions, Timer und Listener, die ihre Komponente überleben – wie du sie in den DevTools findest und schließt.Fortgeschrittene UI & Performance
  • 17Sicherheit: XSS, Sanitizing & CSPWas Angular automatisch gegen XSS tut, wann bypassSecurityTrust gefährlich wird, dazu CSP mit Nonce, Trusted Types und XSRF.Sicherheit & Globalisierung
  • 17Authentifizierung: Tokens & RefreshEin Interceptor, der das Token anhängt, bei 401 einmal erneuert und die wartenden Requests wiederholt — dazu, wo du das Token aufbewahrst.Sicherheit & Globalisierung
  • 17OAuth 2.1 & OpenID Connect mit PKCEDer Authorization-Code-Flow mit PKCE Schritt für Schritt: Verifier und Challenge, State und Nonce, das ID-Token und warum ein BFF sicherer ist.Sicherheit & Globalisierung
  • 17Internationalisierung (i18n)$localize, das i18n-Attribut, ICU plural/select, ein Build pro Sprache vs. Übersetzungen zur Laufzeit und Formatierung nach Locale.Sicherheit & Globalisierung