Skip to content

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

Les nouveautés d'Angular 20.2 (28 août 2025) ​

1. Zoneless : la détection de changements sans Zone.js désormais stable ​

Depuis ses débuts, Angular repose sur Zone.js, une librairie qui « monkey-patche » l’API du navigateur (setTimeout, addEventListener, Promises, etc.) afin de savoir quand relancer la détection de changements. Cette approche, bien que pratique, avait plusieurs inconvénients :

  • une surcharge en performances (chaque API patchée a un coût),
  • une complexité accrue (il fallait parfois désactiver manuellement Zone.js dans certains cas),
  • une taille de bundle plus importante,
  • et une détection de changements difficile à prédire pour les développeurs.

Avec Angular 20.2, la fonctionnalité Zoneless devient enfin stable 🎉. Désormais, on peut se passer totalement de Zone.js et utiliser une approche plus déclarative et prévisible, en s’appuyant sur :

  • les Signals introduits dans Angular 16,
  • la stratégie de détection OnPush (qui est compatible par défaut),
  • et des APIs réactives claires pour notifier Angular des changements.

Comment l’activer ? ​

Il suffit d’utiliser le nouveau provider officiel :

ts
import { bootstrapApplication, provideZonelessChangeDetection } from '@angular/core';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, {
  providers: [
    provideZonelessChangeDetection()
  ]
});

À partir de là, Angular n’utilise plus Zone.js. Chaque changement d’état doit être déclenché via :

  • une mise à jour d’un Signal (signal(), computed(), effect()),
  • ou un event handler explicite (click, input, etc.).

Avantages concrets ​

  • ✅ Performances accrues : plus besoin de patcher tout le runtime du navigateur.
  • ✅ Bundles plus légers : Zone.js n’est plus embarqué.
  • ✅ Moins de magie : la logique de rendu est claire, prévisible et maîtrisée par le développeur.
  • ✅ Compatibilité progressive : on peut activer Zoneless sur une app qui respecte déjà OnPush et les bonnes pratiques Angular.

Exemple pratique ​

Avant, avec Zone.js :

ts
count = 0;

ngOnInit() {
  setTimeout(() => {
    this.count++; // Angular le détecte grâce à Zone.js
  }, 1000);
}

Avec Zoneless, Angular ne « surveille » plus les timers. Il faut utiliser un Signal :

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

count = signal(0);

ngOnInit() {
  setTimeout(() => {
    this.count.update(v => v + 1); // Angular détecte le changement via le Signal
  }, 1000);
}

2. Révolution dans les animations : une nouvelle API plus simple et performante ​

Historiquement, Angular proposait un module dédié @angular/animations et BrowserAnimationsModule. Bien qu’il ait permis de gérer des scénarios avancés, ce système était jugé :

  • verbeux et complexe (déclaration de trigger, state, transition, animate, style…),
  • lourd en runtime, puisqu’il nécessitait un moteur d’animation Angular séparé,
  • et peu naturel par rapport à ce que les développeurs front-end ont l’habitude d’utiliser (classes CSS, transitions natives, etc.).

Avec Angular 20.2, ce package est déprécié et remplacé par une nouvelle approche plus native et déclarative : les attributs animate.enter et animate.leave.

Exemple d’utilisation ​

Avant (ancienne API, verbeuse) :

ts
@Component({
  selector: 'my-app',
  imports: [CommonModule],
  template: `
    <div *ngIf="show" @fadeInOut>Contenu</div>
  `,
  animations: [
    trigger('fadeInOut', [
      transition(':enter', [
        style({ opacity: 0 }),
        animate('300ms ease-in', style({ opacity: 1 }))
      ]),
      transition(':leave', [
        animate('300ms ease-out', style({ opacity: 0 }))
      ])
    ])
  ]
})
export class AppComponent {
  show = true;
}

Nouvelle API avec Angular 20.2 :

angular-html
@if (show()) {
  <div animate.enter="fade-in" animate.leave="fade-out">
    Contenu
  </div>
}

Et dans le CSS :

css
.fade-in {
  animation: fadeIn 300ms ease-in forwards;
}

.fade-out {
  animation: fadeOut 300ms ease-out forwards;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes fadeOut {
  from { opacity: 1; }
  to   { opacity: 0; }
}

👉 Angular applique et retire automatiquement les classes lors de l’entrée/sortie de l’élément. Pas besoin de déclarer un trigger, ni de gérer manuellement la synchronisation.

3. Diagnostics améliorés : détection des fonctions non invoquées dans l’interpolation ​

Un nouveau diagnostic, uninvokedFunctionInTextInterpolation, alerte les développeurs lorsqu’une méthode est référencée dans un template sans appeler la fonction (oubli des parenthèses), évitant ainsi des bugs subtils.

4. Alias dans @else if ​

Vous pouvez désormais utiliser as alias non seulement dans @if, mais aussi dans les blocs @else if :

angular-html
@if (user(); as u) {
  Bonjour {{ u.name }}
} @else if (admin(); as a) {
  Admin : {{ a.name }}
}

Ce qui améliore la lisibilité et tire parti du narrowing des types .

5. Liaison directe des attributs ARIA ​

Fini le préfixe attr. pour les attributs ARIA :

html
<div role="progressbar" [aria-valuenow]="value()"></div>
<!-- ou -->
<div role="progressbar" [ariaValueNow]="value()"></div>

6. Support de TypeScript 5.9 ​

Angular 20.2 intègre officiellement le support de TypeScript 5.9, permettant une meilleure vérification des types, notamment grâce à l’opérateur satisfies :

ts
const config = { title: 'Hello', enabled: true } satisfies Config;

Cela renforce la sécurité typée sans sacrifier la flexibilité .

7. Service Worker : meilleur contrôle et gestion des erreurs ​

Des améliorations ont été apportées à la fonctionnalité Service Worker : meilleure gestion des quotas de cache, messages d’erreur plus précis (VERSION_FAILED), et options plus fines (updateViaCache, type) pour affiner le comportement à l’enregistrement.

8. Signal du router : currentNavigation ​

Le router propose désormais une propriété Signal currentNavigation, remplaçant getCurrentNavigation(). Cela rend l’API plus réactive et mieux intégrée dans le paradigme Signal d’Angular .

Avant :

ts
import { Router } from '@angular/router';

constructor(private router: Router) {
  const nav = this.router.getCurrentNavigation();
  console.log(nav?.extras.state);
}

Nouvelle API :

ts
import { inject } from '@angular/core';
import { Router } from '@angular/router';

const router = inject(Router);

effect(() => {
  const nav = router.currentNavigation();
  if (nav) {
    console.log('Navigation en cours vers :', nav.finalUrl?.toString());
  }
});

Ici, grâce au Signal, Angular relance automatiquement l’effet à chaque nouvelle navigation.