Les nouveautés en Angular 16 (Partie 1)

Le 03 Mai 2023, la core team de Angular a effectué la sortie officielle de la version 16.0.0 de Angular. Aujourd'hui, nous verrons ensemble huit (08) nouveautés liées à cette version.

Signals

Si vous êtes à l'écoute de la communauté Angular, vous avez déjà certainement entendu parler du mot "Signals" qui a sucité beaucoup d'engouements. En effet, jusqu'à la version 15 de Angular c'est la bibliothèque Zone.js qui permet à Angular de détecter les changements dans l'application de manière plus efficace et de mettre à jour l'interface utilisateur de manière plus rapide, ce qui peut améliorer la réactivité de l'application. Cependant, Zone.js pose essentiellement quatre (04) problèmes qui sont :

  • Zone.js a un surcoût d'environ 100 Ko. Bien que négligeable pour les applications de grande taille, cette surcharge est rédhibitoire pour le déploiement de composants web légers.

  • Avec Zone.js, les objets du navigateur sont modifiés et les erreurs sont difficiles à diagnostiquer.

  • Zone.js n'arrive pas à interprèter async et await puisqu'il s'agit de mots-clés. Par conséquent, lors de la compilation, Angular convertit toujours ces déclarations en promesses, même si tous les navigateurs pris en charge supportent déjà async et await en mode natif.

  • Lorsque des modifications sont apportées, des composants entiers, y compris leurs prédécesseurs, sont toujours vérifiés dans l'arborescence des composants. Il n'est actuellement pas possible d'identifier directement les composants modifiés ou de mettre à jour les parties modifiées d'un composant.

Afin de résoudre ces problèmes, ils ont pensé à la création de Signals. La bibliothèque Signals nous permet de définir des valeurs réactives et d'exprimer des dépendances entre elles. Elle est souple et simple à implémenter. Voyons ensemble un exemple d'implémentation :

@Component({
  selector: 'my-app',
  standalone: true,
  template: `
    {{ fullName() }} <button (click)="setName('John')">Click</button>
  `,
})
export class App {
  firstName = signal('Jane');
  lastName = signal('Doe');
  fullName = computed(() => `${this.firstName()} ${this.lastName()}`);

  constructor() {
    effect(() => console.log('Name changed:', this.fullName()));
  }

  setName(newName: string) {
    this.firstName.set(newName);
  }
}

Rendu côté serveur (SSR) et hydratation améliorés

La core team de Angular a effectué une enquête annuelle afin d'avoir une idée des choses à améliorer dans les prochaines versions. Le résultat a démontré que les développeurs se plaignaient beaucoup du rendu côté serveur. Il y a donc eu naturellement des améliorations à ce niveau. En voici une preuve :

Création des schémas d'applications autonomes

Précédemment, dans cet article, nous avons vu ensemble ce que c'est qu'un composant autonome (standalone). Avec la version 16 de Angular, il est possible via la CLI de créer une application Angular en précisant par défaut que nous voulons créer uniquement des composants autonomes. Voici ce qu'il faut faire :

ng new --standalone

Possibilité d'ajouter la règle "required" sur des Input

Lorsque nous créons un composant réutilisable en Angular, nous utilisons le décorateur @Input() pour préciser les props de notre composant. Jusqu'à la version 15 de Angular, il n'est pas possible de rendre obligatoire nos propriétés lorsque notre composant réutilisable est appelé dans un composant parent. Pour améliorer donc cette expérience développeur, la communauté a suggéré ceci :

@Component(...)
export class App {
  @Input({ required: true }) title: string = '';
}

Utilisation de @Input() dans un Resolver

Cette nouveauté facilite l'utilisation des Resolvers en Angular. Cela consiste tout simplement en ceci :

const routes = [
  {
    path: 'about',
    loadComponent: import('./about'),
    resolve: { contact: () => getContact() }
  }
];

@Component(...)
export class About {
  // The value of "contact" is passed to the contact input
  @Input() contact?: string;
}

Nous remarquons que notre variable contact qui est un @Input() est directement liée à l'objet ayant pour clé le même nom que notre variable présent dans notre Resolver.

DestroyRef & takeUntilDestroyed

  • DestroyRef
    La classe DestroyRef a été créée pour faciliter l'utilisation de la méthode ngOnDestroy() qui fait partie du cycle de vie d'un composant Angular. L'idée ici est de pouvoir l'utiliser dans les directives, services, pipes, etc...
    Voici un exemple :
import { Injectable, DestroyRef } from '@angular/core';

@Injectable(...)
export class AppService {
  destroyRef = inject(DestroyRef);

  destroy() {
    this.destroyRef.onDestroy(() => /* cleanup */ );
  }
}
  • takeUntilDestroyed
    Avant la création de la méthode takeUntilDestroyed(), voici comment procédons-nous :
destroyed$ = new ReplaySubject<void>(1);

data$ = http.get('...').pipe(takeUntil(this.destroyed$));

ngOnDestroy() {
  this.destroyed$.next();
}

Aujourd'hui avec la version 16 de Angular, nous avons ceci :

data$ = http.get('…').pipe(takeUntilDestroyed());

NGCC, entryComponents et Node.js v14 ne sont pas supportés par Angular 16

La compilation NGCC n'est pas supportée par Angular 16. Il faudra faire attention lors de la montée en version. Il en est de même pour entryComponent qui était obsolète depuis Angular 9. Enfin, il est à souligner que Angular 16 ne supporte pas la version 14 de Node.js.

TypeScript 5.0

La version 16 de Angular supporte le TypeScript 5.0 qui inclut l'utilisation des décorateurs ECMAScript.

En somme, nous avons remarqué à travers cette première partie sur les nouveautés liées à Angular 16, qu'il y a eu beaucoup d'améliorations et que l'expérience développeur est toujours au coeur de ce dernier.

Pour plus d'informations :

👉 Angular v16 is here

👉 Angular Signals by AngularArchitects

Did you find this article valuable?

Support Ezéchiel Amen AGBLA by becoming a sponsor. Any amount is appreciated!