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.
Ajouter le SSR
ng add @angular/ssr
Fichiers générés :
src/app/app.config.server.ts— providers serveursrc/server.ts— point d'entrée Express
Configuration serveur
// 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);
Activer l'hydratation (app.config.ts)
import { provideClientHydration } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient(),
provideClientHydration(), // Évite les scintillements lors de l'hydratation
],
};
Protéger les API réservées au navigateur
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();
});
}
}
Transfert d'état (éviter le double fetch)
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))
);
}
}
Construire et exécuter
# 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
Vérifier que le SSR fonctionne
- Ouvrez
http://localhost:4000 - Affichez la source de la page (Ctrl+U)
- Le HTML de la page doit contenir votre contenu rendu — et non juste
<app-root></app-root>
Erreurs courantes
| 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 |