bhylu.com

Advertisements

Angular Hydration

Hydration reuses compatible server-rendered DOM when the browser application starts. Matching initial structure and state are essential; merely enabling a provider does not prove reuse worked.

How it works

The server and client share a deterministic initial return count. provideClientHydration with event replay belongs in the application configuration used on both sides. The review captures the paragraph before bootstrap, checks that the same DOM node survives hydration and then clicks the button to verify an interactive update. This is stronger than comparing two screenshots that could hide a full client replacement.

Run the code

Use a separate empty project folder with a compatible Node version: ^22.22.3, ^24.15.0 or a supported 26+ runtime. The review uses Node 24.22.1, Angular 22.2.4, CLI/build 22.2.5 and TypeScript 6.0.3. Node 22.15.1 is too old for Angular 22. Save every download at its displayed path; browsers may keep only the basename, so recreate the src folder. Run npm install, npm run build and npm start, then open the loopback address printed by the server. Run npm test for the supplied component tests. These are local teaching projects, not Bhylu publishing files.

This project includes a real Angular server entry. Start its generated Node server; serving only browser files does not exercise SSR. Its tests distinguish server HTML from later client rendering. Angular examples do not run in Bhylu’s current HTML or TypeScript playground. No Apache, MySQL or PHP configuration change is needed.

Example

src/app.ts

import { Component } from '@angular/core';
import { signal } from '@angular/core';

@Component({
  selector: 'bh-hydration',
  standalone: true,
  imports: [],
  template: `<button type="button" (click)="returns.update(add)">Add return</button>
    <p data-result>{{ returns() }} returns</p>`,
})
export class App {
  returns = signal(2);
  add = (value: number) => value + 1;
}

Expected result

2 returns

After hydration the paragraph is the original server node, and a click changes its text to 3 returns. Avoid non-deterministic initial values such as a fresh random number or an independently formatted timestamp on each side. The fixture validates basic hydration and interaction, not every incremental hydration or streaming scenario.

Supporting source

src/app.config.ts

import { ApplicationConfig, provideZonelessChangeDetection } from '@angular/core';
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
  providers: [
    provideZonelessChangeDetection(),
    provideClientHydration(withEventReplay()),
  ],
};

Advertisements