Angular est-il vraiment plus compliqué que React ?

Quand on débute avec Angular, il est facile de se sentir découragé face à la multitude de concepts à assimiler. Cette complexité peut inciter à se tourner vers des frameworks comme React, qui semblent plus simples à première vue. Mais est-ce vraiment le cas ?

Abonnez-vous à notre chaîne

Pour profiter des prochaines vidéos sur Angular, abonnez-vous à la nouvelle chaîne YouTube !

Skip to content

Vous souhaitez recevoir de l'aide sur ce sujet ? rejoignez la communauté Angular.fr sur Discord.

Gérer la Compatibilité Client/Serveur en SSR avec Angular

Le Server-Side Rendering (SSR) dans Angular permet d'améliorer les performances et le SEO de votre application. Cependant, certaines fonctionnalités qui fonctionnent parfaitement côté client peuvent poser problème lors du rendu côté serveur.

Les erreurs les plus communes en SSR sont liées à l'accès aux API du navigateur qui n'existent pas côté serveur :

  • ReferenceError: localStorage is not defined
  • ReferenceError: document is not defined
  • ReferenceError: window is not defined

Solution avec PLATFORM_ID

PLATFORM_ID est un token d'injection fourni par Angular qui permet d'identifier la plateforme sur laquelle votre application s'exécute. En combinaison avec la fonction isPlatformBrowser(), il devient un outil essentiel pour gérer le code spécifique au navigateur.

Comprendre PLATFORM_ID

  • En mode navigateur (client-side), PLATFORM_ID a la valeur 'browser'
  • En mode serveur (SSR), PLATFORM_ID a la valeur 'server'

La fonction isPlatformBrowser()

isPlatformBrowser() est une fonction utilitaire qui :

  • Prend PLATFORM_ID en paramètre
  • Retourne true si le code s'exécute dans le navigateur
  • Retourne false si le code s'exécute côté serveur

UTILISATION

C'est la méthode recommandée par Angular pour détecter l'environnement d'exécution de manière sûre et typée.

Autre approche

Une autre approche consiste à vérifier directement l'existence de l'objet window :

ts
export class BrowserCheckService {
  isBrowser(): boolean {
    return typeof window !== 'undefined';
  }
}

Voici comment gérer correctement ces cas :

ts
import { inject, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { User } from './user.interface';

export class UserStorageService {
  private platformId = inject(PLATFORM_ID);

  saveUser(user: User): void {
    if (isPlatformBrowser(this.platformId)) {
      localStorage.setItem('currentUser', JSON.stringify(user));
    }
  }

  getUser(): User | null {
    if (isPlatformBrowser(this.platformId)) {
      const userData = localStorage.getItem('currentUser');
      return userData ? JSON.parse(userData) : null;
    }
    return null;
  }
}
ts
import { Component, inject, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

@Component({
  selector: 'app-user',
  standalone: true,
  template: `
    @if (showUserProfile) {
      <div>
        {{ user.name }}
      </div>
    }
  `
})
export class UserComponent {
  private platformId = inject(PLATFORM_ID);
  
  checkBrowser(): void {
    if (isPlatformBrowser(this.platformId)) {
      // Code spécifique au navigateur
      document.title = 'Profil Utilisateur';
    }
  }
}

Gestion des Librairies Tierces

CHARGEMENT DYNAMIQUE

Pour les librairies qui ne sont pas compatibles SSR, utilisez l'import dynamique :

ts
export class ChartComponent {
  async loadChartLibrary() {
    if (isPlatformBrowser(this.platformId)) {
      const chartModule = await import('chart.js');
      // Utilisation de la librairie
    }
  }
}

IMPORTANT

Assurez-vous toujours de tester votre application en mode SSR avant la mise en production pour détecter les problèmes de compatibilité client/serveur.

Bonus : Service de gestion de localStorage compatible SSR

Voici un service de gestion de localStorage compatible SSR, vous pouvez le réutiliser dans vos projets :

ts
import { Injectable, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { inject } from '@angular/core';

/**
 * LocalStorageService
 * Service to manage localStorage, SSR compatible
 * 
 * @example
 * const localStorage = inject(LocalStorageService);
 * localStorage.setItem('key', 'value');
 * localStorage.getItem<string>('key');
 * localStorage.removeItem('key');
 * localStorage.clear();
 */
@Injectable({
  providedIn: 'root'
})
export class LocalStorageService {
  private platformId = inject(PLATFORM_ID);

  /**
   * Set an item in localStorage
   * @param key Storage key
   * @param value Value to store
   */
  setItem(key: string, value: unknown): void {
    if (isPlatformBrowser(this.platformId)) {
      localStorage.setItem(key, JSON.stringify(value));
    }
  }

  /**
   * Get an item from localStorage
   * @param key Storage key
   * @returns The stored value or null if not found
   */
  getItem<T>(key: string): T | null {
    if (isPlatformBrowser(this.platformId)) {
      const item = localStorage.getItem(key);
      return item ? JSON.parse(item) : null;
    }
    return null;
  }

  /**
   * Remove an item from localStorage
   * @param key Storage key
   */
  removeItem(key: string): void {
    if (isPlatformBrowser(this.platformId)) {
      localStorage.removeItem(key);
    }
  }

  /**
   * Clear all items from localStorage
   */
  clear(): void {
    if (isPlatformBrowser(this.platformId)) {
      localStorage.clear();
    }
  }
}

Chaque mois, recevez en avant-première notre newsletter avec les dernières actualités, tutoriels, astuces et ressources Angular directement par email !