Appearance
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.