Angular évolue vite. Entre les versions majeures, il y a des changements significatifs au modèle réactif, à l'architecture de rendu et à l'expérience développeur. Suivre le changelog d'Angular et décider ce qui entre dans un codebase de production d'entreprise réglementé sont deux activités très différentes. Ce qui suit, c'est la seconde : ce que j'utilise, ce que j'ai laissé de côté, et quel était le compromis dans chaque cas.
Le contexte compte : mon travail Angular a surtout été en entreprise, en banque, en assurance, en fintech et en santé, et je construis aussi MailHive, mon propre SaaS, en solo avec Angular. Les deux m'ont appris le même filtre : la stabilité est une préoccupation primordiale. Je n'adopte pas les API expérimentales en production. J'ai besoin d'histoires de test robustes. J'ai besoin de choses qui seront encore l'approche recommandée dans deux ans. Ce filtre change significativement comment j'évalue les nouvelles fonctionnalités Angular.
Signals : stabilisés et en production
Les Signals sont devenus stables dans Angular 17. Avec Angular 19, les parties dont je dépends étaient stables avec eux : signal inputs, signal outputs et toSignal. linkedSignal() et l'API resource étaient encore expérimentaux en 19, et effect() était encore en developer preview, c'est pourquoi ils ne figurent pas dans la liste ci-dessous. Les signals sont le changement que j'ai adopté le plus tôt et le plus complètement. Le front-end de MailHive est bâti sur des composants basés sur les signals et un état basé sur les signals, et pendant la bêta l'expérience a été largement positive.
Ce que j'utilise
- signal() pour l'état local de composant qui pilote le rendu du template
- computed() pour les valeurs dérivées. C'est plus propre que toute combinaison de pipe ou de getter que j'utilisais avant
- L'API input() signal au lieu du décorateur @Input(). Meilleure intégration TypeScript, les inputs requis sont type-safe
- output() au lieu de @Output(). Moins de boilerplate, cohérent avec le pattern input()
- toSignal() pour convertir les observables des services en signals pour la consommation dans le template
- takeUntilDestroyed(). Pas techniquement spécifique aux signals mais s'associe naturellement avec ce modèle réactif
Ce sur quoi je suis plus prudent
L'API resource (resource() et rxResource()) pour la récupération de données est intéressante mais je ne l'utilise pas encore en production. Le modèle mental qu'elle introduit est propre, mais c'est plus récent et j'ai vu la surface de l'API évoluer entre les versions mineures. Dans un contexte entreprise, je préfère utiliser un service avec un observable et toSignal() au point de consommation. C'est plus explicite et plus testable avec les outils que la plupart des équipes ont déjà.
linkedSignal() était expérimental en 19 et est devenu stable en v20, donc l'argument de la version ne tient plus. Ma réserve porte maintenant sur la lisibilité, pas sur la stabilité. Le cas d'usage est clair : un signal dont la valeur par défaut est dérivée d'un autre signal et peut être surchargée. Je l'ai vu décrit comme confus en revue de code, et je n'y ai recours que quand l'alternative est un effect() manuel qui réécrit dans un signal. La simplicité dans le code de production est une feature.
Les blocs Defer : véritablement utiles
Le bloc @defer, introduit dans Angular 17, est l'une des fonctionnalités sur lesquelles j'étais le plus sceptique et dont je suis depuis devenu un véritable adepte. La capacité de charger paresseusement une partie du template, et de spécifier les déclencheurs et les états d'espace réservé de manière déclarative, résout un vrai problème UX proprement.
@defer (on viewport) {
<app-analytics-dashboard />
} @placeholder {
<div class="skeleton skeleton--chart"></div>
} @loading (minimum 200ms) {
<app-spinner />
} @error {
<app-error-message message="Failed to load dashboard" />
}En pratique, ça gagne sa place pour : les widgets de tableau de bord sous la ligne de flottaison, les composants de graphiques lourds, le contenu qui nécessite une interaction utilisateur pour être pertinent (onglets, sections accordéon), et les composants tiers embarqués avec un poids de bundle important. Le déclencheur on viewport en particulier est extrêmement utile pour les mises en page de tableau de bord où plusieurs widgets se disputent le temps de chargement initial.
La stratégie de test pour @defer est suffisante pour la production : vous pouvez contrôler l'état de defer dans les tests et tester chaque état (placeholder, loading, content, error) indépendamment. C'est un prérequis pour l'adopter dans n'importe quel codebase où les attentes de couverture de test sont élevées.
Hydration incrémentale : stable depuis la v20, toujours pas dans ma stack
Angular 19 a introduit l'hydration incrémentale en developer preview et la v20 l'a promue au rang de stable. Elle hydrate le contenu rendu côté serveur par morceaux, par partie du template, au lieu de tout d'un coup. Combinée avec @defer, cela signifie que vous pouvez différer à la fois le rendu initial et l'hydration de parties spécifiques de la page.
C'est techniquement impressionnant. Les implications en termes de performance pour les pages riches en contenu sont significatives. Mais voici mon évaluation honnête pour la production : la majeure partie de l'Angular que j'ai livré n'utilise pas le SSR au niveau de sophistication qui rendrait l'hydration incrémentale une préoccupation prioritaire. C'est du travail SPA (single-page application), des parcours applicatifs et des tableaux de bord, pas des pages de contenu critiques pour le SEO. La fonctionnalité est stable et prête. Ce ne sont pas mes charges de travail qui en tirent profit.
Si vous construisez une application Angular publique avec SSR pour le SEO ou la performance, une vitrine e-commerce, un site marketing, une plateforme de contenu, l'hydration incrémentale vaut un investissement sérieux dès maintenant. Si vous construisez un tableau de bord entreprise authentifié, c'est une fonctionnalité à comprendre et à garder en réserve pour quand le cas d'usage se présentera.
Modes de rendu au niveau des routes
Angular 19 a introduit la configuration du mode de rendu au niveau des routes en developer preview, et la v20 l'a rendue stable. Dans une configuration de routes serveur (app.routes.server.ts), vous spécifiez par route si elle doit être : rendue côté serveur (SSR), pré-rendue (SSG), ou rendue côté client (CSR). C'est une amélioration significative par rapport à la configuration SSR tout-ou-rien précédente.
// app.routes.server.ts: render mode per route, next to the normal app.routes.ts
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{ path: '', renderMode: RenderMode.Prerender },
{ path: 'dashboard', renderMode: RenderMode.Client }, // authenticated, no SSR needed
{ path: 'about', renderMode: RenderMode.Prerender },
{ path: '**', renderMode: RenderMode.Server }
];Le modèle mental qu'il permet est propre : les pages publiques obtiennent le SSR/SSG pour la performance et le SEO, les pages d'application authentifiées obtiennent le CSR. Pour les applications qui couvrent les deux catégories, un produit avec une page d'accueil publique et un tableau de bord privé, c'est la bonne architecture et Angular la supporte maintenant proprement.
Composants standalone : pleinement adoptés, aucun regret
C'est moins Angular 19 et plus l'arc plus long d'Angular 14-17, mais les composants standalone sont maintenant mon défaut pour tout. Les NgModules ont disparu du nouveau code que j'écris. Dans les codebases qui en portent encore, je migre les modules existants graduellement plutôt qu'en une seule grande passe.
Les bénéfices que j'ai constatés en production : des bundles plus petits (le tree-shaking est plus efficace), des graphes de dépendances plus clairs (vous voyez exactement ce dont chaque composant a besoin), des tests plus simples (pas de configuration de module TestBed pour les composants qui n'en ont pas besoin), et un code splitting plus facile aligné avec le lazy loading au niveau des routes.
Le seul point de friction : les codebases volumineux avec des NgModules profondément imbriqués demandent un effort réel pour migrer de manière incrémentale. Angular fournit des schémas et des outils de migration, et ils fonctionnent bien pour les cas simples. Les hiérarchies de modules complexes avec des providers partagés entre modules nécessitent une attention manuelle minutieuse. Budgétez du temps pour cela si vous êtes en pleine migration.
OnPush Change Detection et l'interaction avec les Signals
Un point que je veux adresser directement parce que c'est une source fréquente de confusion : OnPush change detection et les signals interagissent d'une manière spécifique que vous devez comprendre.
Avec OnPush, un composant se re-rend quand : la référence d'un de ses inputs change, un événement provient de celui-ci, un async pipe se résout, ou markForCheck() est appelé. Avec les signals, il y a un déclencheur supplémentaire : quand un signal lu pendant le rendu précédent change de valeur, Angular marque automatiquement le composant pour vérification. Même avec OnPush.
C'est le bon comportement, mais cela signifie que OnPush plus signals est la bonne combinaison, pas une combinaison redondante. Vous gardez OnPush pour ses autres bénéfices (réduction des cycles de change detection par défaut) et les signals ajoutent des mises à jour réactives granulaires par-dessus. J'utilise OnPush sur chaque composant que j'écris, et sur MailHive il s'est bien comporté avec les signals pendant toute la bêta. Depuis la v22, c'est aussi la position du framework : OnPush est maintenant la stratégie de change detection par défaut pour les nouveaux composants, et l'ancien défaut always-check a été renommé Eager. Si vous êtes en v22, vous en héritez. Si vous êtes en v21 ou avant, continuez à le définir à la main, et sachez que la migration vers la v22 rend vos composants legacy non annotés plus stricts, pas plus permissifs.
La syntaxe de contrôle de flux
Angular 17 a introduit la nouvelle syntaxe de contrôle de flux dans les templates (@if, @for, @switch) pour remplacer *ngIf, *ngFor et *ngSwitch. Avec Angular 19, c'est clairement l'approche préférée et j'ai migré tout le nouveau code vers celle-ci.
@for (account of accounts(); track account.id) {
<app-account-card [account]="account" />
} @empty {
<p class="empty-state">No accounts found.</p>
}L'exigence de track dans @for est un changement cassant dans la bonne direction. Vous forcer à spécifier le tracking prévient les problèmes de performance que nous voyions avec les listes non trackées. Le bloc @empty est une amélioration de qualité de vie qui élimine un pattern courant d'un *ngIf séparé pour l'état vide.
Ce que j'attends de voir mûrir
- L'API resource() : la v22, sortie quelques jours avant cet article, la marque stable, et le concept est bon, mais je veux la voir tenir le coup sur une version majeure supplémentaire avant de l'utiliser en production plutôt que les patterns basés sur les observables
- Angular Material 3 dans les design systems établis : M3 est stable dans Angular Material depuis la v18, mais faire passer un thème établi aux tokens M3 est une décision de design system. Quand une autre équipe possède le design system, ce choix lui revient, pas au développeur front-end ; je surveille ça pour savoir à quoi m'attendre quand ça arrivera
- Signal Forms : expérimentaux dans Angular 21 et stables depuis la v22. Ce sera une amélioration majeure de DX ; en attendant qu'ils aient du vécu en conditions réelles, le pont FormControl + toSignal() fonctionne mais c'est un pont, pas une intégration native
Verdict final
Angular 19+ est un framework véritablement bon. La combinaison des signals, des composants standalone, des blocs defer et de la nouvelle syntaxe de template produit un code plus lisible, plus performant et plus testable que ce que j'écrivais deux versions majeures auparavant. La structure opiniâtre qui est parfois critiquée est exactement ce que je veux dans un contexte entreprise.
Ma philosophie d'adoption en production : signals et standalone pleinement intégrés. Blocs defer pour les cas d'usage de lazy-loading appropriés. Nouvelle syntaxe de contrôle de flux pour tous les nouveaux templates. Hydration incrémentale et modes de rendu par route quand le SSR deviendra une priorité. API resource quand elle aura été stable pendant une version ou deux.
Vous n'avez pas besoin d'utiliser chaque nouvelle fonctionnalité pour tirer de la valeur d'une version majeure. Être délibéré sur ce que vous adoptez et pourquoi est la marque d'un développeur senior.
Références
- Angular 19 release blog. https://blog.angular.dev/meet-angular-v19-7b29dfd05b84
- @defer block référence. https://angular.dev/guide/defer
- Angular resource() API. https://angular.dev/guide/signals/resource
- Incremental hydration guide. https://angular.dev/guide/incremental-hydration
- Route-level render modes. https://angular.dev/guide/ssr#rendering-modes