Aller au contenu

Rendu côté serveur (SSR)

Le SSR Angular pré-rend les pages côté serveur avant de les envoyer au navigateur, améliorant les performances de chargement initial et le SEO.

Fenêtre de terminal
ng add @angular/ssr

Fichiers générés :

  • src/app/app.config.server.ts — providers serveur
  • src/server.ts — point d’entrée Express
app.config.server.ts
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
import { provideServerRendering } from '@angular/platform-server';
import { appConfig } from './app.config';
const serverConfig: ApplicationConfig = {
providers: [provideServerRendering()],
};
export const config = mergeApplicationConfig(appConfig, serverConfig);
import { provideClientHydration } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient(),
provideClientHydration(), // Évite les scintillements lors de l'hydratation
],
};

Le serveur n’a pas accès à window, document ni localStorage. Utilisez isPlatformBrowser ou afterNextRender :

import { PLATFORM_ID, inject, afterNextRender } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
export class MyComponent {
private platformId = inject(PLATFORM_ID);
// Option A : isPlatformBrowser
ngOnInit() {
if (isPlatformBrowser(this.platformId)) {
const value = localStorage.getItem('cle');
}
}
// Option B : afterNextRender (recommandé, Angular 16+)
constructor() {
afterNextRender(() => {
// S'exécute uniquement dans le navigateur après le premier rendu
this.initBibliothequeExterne();
});
}
}

Sans transfert d’état, Angular re-récupère les données dans le navigateur que le serveur avait déjà récupérées.

import { TransferState, makeStateKey, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { of, tap } from 'rxjs';
const ALBUMS_KEY = makeStateKey<Album[]>('albums');
@Injectable({ providedIn: 'root' })
export class AlbumService {
private http = inject(HttpClient);
private transferState = inject(TransferState);
getAlbums() {
const cached = this.transferState.get(ALBUMS_KEY, null);
if (cached) {
this.transferState.remove(ALBUMS_KEY);
return of(cached);
}
return this.http.get<Album[]>('/api/albums').pipe(
tap(data => this.transferState.set(ALBUMS_KEY, data))
);
}
}
Fenêtre de terminal
# Construire les bundles navigateur + serveur
ng build
# Démarrer le serveur SSR
node dist/my-app/server/server.mjs

Structure de sortie :

dist/my-app/
├── browser/ ← Ressources statiques
└── server/
└── server.mjs ← Serveur Node
  1. Ouvrez http://localhost:4000
  2. Affichez la source de la page (Ctrl+U)
  3. Le HTML de la page doit contenir votre contenu rendu — et non juste <app-root></app-root>
Problème Solution
window is not defined Protéger avec isPlatformBrowser ou afterNextRender
Données récupérées deux fois Utiliser TransferState
Désaccord d’hydratation S’assurer que le serveur et le client rendent le même HTML
Crash localStorage Déplacer l’accès au stockage derrière une vérification de plateforme