S

super-dev — full-stack

@super-dev.app · Full-stack · ★ ouvert aux missions
12,8k abonnés·47 vidéos·Actif depuis 2017

Développeur full-stack .NET / Angular avec une casquette DevOps sur Azure Cloud. Aussi à l'aise sur Flutter + Firebase. Je construis des produits, je les déploie, je les surveille.

Retour aux articles
ANGULAR
ANGULAR

Passer une app Angular en zoneless + signals

Article 1 sur 4 — Angular 21 en pratique
Zoneless, signals, resource(), @defer, SignalStore — le front moderne, en vrai.

Pendant des années, Angular s'est appuyé sur zone.js pour savoir quand redéclencher le change detection : un patch monkey de toutes les API asynchrones du navigateur. Ça marche, mais c'est une boîte noire coûteuse. Depuis Angular 21, on peut s'en passer entièrement avec provideZonelessChangeDetection() et laisser les signals piloter la réactivité.

Pourquoi virer zone.js

zone.js intercepte setTimeout , les promesses, les events DOM, et déclenche un cycle de détection global à chaque fois. Sur une grosse app, on vérifie des milliers de bindings alors que trois ont changé. Le mode zoneless inverse la logique : rien ne se redessine tant qu'un signal lu dans le template n'a pas notifié son changement.

  • bundle plus léger : on supprime une dépendance de ~100 ko
  • traces de pile lisibles : plus de frames zone.run partout
  • détection ciblée : seuls les composants qui dépendent du signal modifié sont marqués

Activer le mode zoneless

Tout se joue dans la configuration de l'application. On retire provideZoneChangeDetection et on branche le provider zoneless :

TypeScript
1import { provideZonelessChangeDetection } from '@angular/core';
2import { bootstrapApplication } from '@angular/platform-browser';
3
4bootstrapApplication(AppComponent, {
5 providers: [
6 provideZonelessChangeDetection(),
7 provideRouter(routes),
8 ],
9});

Penser en réactivité fine

Une fois zoneless, tout l'état doit être un signal sinon le template ne se met plus à jour. On remplace les champs mutables par signal() , les valeurs dérivées par computed() , et les effets de bord par effect() :

TypeScript
1@Component({
2 selector: 'app-cart',
3 changeDetection: ChangeDetectionStrategy.OnPush,
4 template: `Total : {{ total() }} €`,
5})
6export class CartComponent {
7 protected readonly items = signal<CartItem[]>([]);
8 protected readonly total = computed(() =>
9 this.items().reduce((sum, item) => sum + item.price * item.quantity, 0),
10 );
11}

Les pièges à connaître

Le code legacy qui fait setTimeout(() => this.value = x) sans passer par un signal ne rafraîchira plus la vue. Idem pour les souscriptions RxJS : il faut soit toSignal() , soit appeler signal.set() dans le subscribe . Côté tests, on bascule Vitest en zoneless et on remplace les fakeAsync / tick par await fixture.whenStable() . La doc officielle détaille chaque cas dans le guide zoneless .

Le zoneless ne rend pas une app magiquement plus rapide. Il rend la réactivité explicite : tu sais exactement pourquoi quelque chose se redessine, et c'est ça qui change tout en debug.
super-dev — portfolio.app
// Continuer dans ANGULAR
Un moteur façon DOOM dans le navigateur, à trois backends
11 min • 1,4k lectures
Charger des données avec resource() et httpResource()
7 min • 3,6k lectures
@defer et le nouveau control flow : moins de JS au démarrage
6 min • 2,9k lectures