Tous les articles

·5 min de lecture

Migration Angular 18 → 19 : les ruptures réelles et comment les naviguer

Angular 19 apporte des changements fondamentaux sur l'injection de dépendances, les signaux et le rendu. Voici ce qui change vraiment, ce qui casse, et comment préparer votre migration sans panique.

Angular 19 n'est pas une mise à jour cosmétique. Contrairement à la 18, qui consolidait l'écosystème Signal, la 19 force des décisions architecturales : les providers standalone deviennent la norme, l'injection par constructeur recule, et le Control Flow offre enfin une alternative crédible aux *ngIf/*ngFor. Les équipes qui ont traîné sur Angular 15 trouveront un framework transformé. Ceux qui migrent depuis la 18 auront moins de friction, mais il faut comprendre les nouveaux patterns pour éviter de réécrire l'application en entier.

Les trois changements majeurs

Le premier changement concerne l'injection de dépendances. Angular 19 déprécie progressivement les décorateurs @Injectable() au profit des fonctions inject() appelées directement dans les composants et services. Ce n'est pas une suppression immédiate, mais le framework pousse clairement vers ce modèle. Pourquoi ? Parce que inject() est plus composable, facilite le tree-shaking, et rend le code plus lisible sans métadonnées. Exemple : un service d'authentification en Angular 18 ressemblait à constructor(private http: HttpClient) , tandis qu'en 19 vous écrirez private http = inject(HttpClient) . C'est une ligne de code au lieu de cinq, et le compilateur comprend mieux vos dépendances.

Le deuxième changement, c'est le Control Flow. Angular 19 introduit @if , @for , @switch et @defer comme syntaxe native remplaçant les directives *ngIf, *ngFor, *ngSwitch. Cette syntaxe est compilée directement en code optimisé, sans couche d'interprétation supplémentaire. Un @if génère un code plus performant qu'un *ngIf, surtout dans les boucles imbriquées. Concrètement : @if (isLoggedIn) { <app-dashboard /> } remplace <app-dashboard *ngIf="isLoggedIn" /> . Le rendu est prédictible, le change detection est plus efficace, et vous gagnez environ 5-15% de performance selon le benchmark officiel.

Le troisième changement concerne les signaux et le rendu réactif. Angular 19 stabilise les signaux comme primitive centrale du framework. Cela signifie que les observables restent valides, mais les signaux deviennent le chemin par défaut pour la réactivité locale. Les composants utilisant signal() et computed() au lieu de BehaviorSubject et Observable bénéficient d'une meilleure détection de changements granulaire. Vous ne recalculez que ce qui change, pas tout le composant. C'est particulièrement visible dans les formulaires et les listes longues.

Hydratation et SSR : le rendu devient prédictible

Angular 19 améliore l'hydratation côté serveur avec une meilleure synchronisation entre le rendu serveur et le client. Si vous utilisez Angular Universal, vous verrez que le temps jusqu'à l'interactivité (TTI) diminue significativement. L'hydratation n'est plus un risque de mismatch entre le HTML généré et le rendu client ; le framework gère mieux les événements pendant l'hydratation, ce qui réduit les bugs liés au timing.

Si vous êtes en SSR avec Angular Universal, la migration vers 19 apporte une stabilité bienvenue. Les directives structurelles anciennes (comme *ngIf dans le SSR) pouvaient causer des hydratation mismatch dans 10-15% des cas. Avec le Control Flow, ces problèmes disparaissent presque entièrement, car la syntaxe est compilée directement et déterministe. Le rendu côté serveur devient un vrai gain SEO et performance, pas un risque architectural.

Les dépendances qui cassent

Première victime : les directives de validation formulaire. Angular 19 change la façon dont les validateurs personnalisés sont appliqués. Si vous aviez des validateurs custom qui modifiaient le contexte de validation via AbstractControl.setErrors() , vous devrez les adapter. La nouvelle approche utilise les signaux pour tracer les changements de validation, ce qui rend le code plus lisible mais casse la rétrocompatibilité. Testez vos formulaires en priorité.

Deuxième point : HttpClientModule vs HttpClient. Angular 19 supprime HttpClientModule du bundle par défaut si vous n'appelez jamais HttpClient. C'est un gain de ~5KB. Mais si vous aviez des intercepteurs déclarés au niveau du module, vous devrez les migrer vers les providers standalone. Exemple : au lieu de HttpClientModule dans imports, vous passez withInterceptors([myInterceptor]) au bootstrapApplication() .

Troisième rupture : NgZone et change detection. Le rendu fin des signaux réduit le besoin de ngZone.runOutsideAngular() pour optimiser les performances. Si vous aviez du code agressif d'optimisation de change detection, il risque de devenir obsolète ou même de causer des bugs subtils où certaines mises à jour ne se déclenchent pas. Testez chaque ngZone.run() en context réel.

Migration pratique : étapes concrètes

Commencez par mettre à jour Angular CLI avec ng update @angular/cli@19 . Ensuite, lancez ng update @angular/core@19 . Le CLI est assez intelligent pour migrer automatiquement 60-70% de votre codebase : les imports, les décorateurs mineurs, quelques patterns simples. Mais il ne peut pas migrer vos décisions architecturales.

Ensuite, migrez manuellement les composants critiques. Prenez un composant simple, remplacez les *ngIf par @if, les *ngFor par @for, et changez un ou deux services pour utiliser inject() au lieu du constructeur. Testez avec Cypress ou Playwright. Vous verrez immédiatement si quelque chose casse. Puis, progressivement, migrez le reste du codebase.

Pour les formulaires réactifs, Angular 19 introduit les signaux dans FormControl. Vous pouvez écrire new FormControl(initialValue, { nonNullable: true }) et directement accéder à control.value sans subscription. C'est plus simple, moins de memory leaks, et le change detection est gratuit.

Le piège : la migration progressive

Le piège classique, c'est de vouloir tout migrer en une semaine. Angular 19 est rétrocompatible à 95%, mais ce 5% peut vous coûter des heures de débogage. Pire : vous pouvez avoir du code qui fonctionne en local mais casse en production, surtout si vous utilisez SSR ou des service workers. Testez chaque étape en environnement de staging. Ne mixez pas trop de patterns anciens et nouveaux dans le même composant ; c'est une source de bugs subtils où une partie du composant utilise les signaux et une autre utilise les observables, sans synchronisation claire.

Un autre piège : oublier que @defer a des implications de performance. La directive @defer charge les composants en lazy-load quand l'utilisateur les demande. C'est puissant, mais si vous l'appliquez partout sans mesurer, vous pouvez finir avec un premier chargement rapide mais des micro-lags lors du scroll ou des interactions. Mesurez avec Lighthouse et Web Vitals avant et après.

Conclusion

Angular 19 est une étape majeure vers un framework plus performant et plus maintenable. Les signaux, le Control Flow et l'injection moderne réduisent la complexité et les bugs. La migration depuis Angular 18 est faisable en 2-4 semaines selon la taille du codebase, à condition de tester progressivement et de ne pas essayer de tout changer à la fois. Les équipes qui embrassent les nouveaux patterns verront des gains de performance réels et une meilleure expérience développeur. Celles qui traînent les pieds risquent de se retrouver avec un codebase dual-pattern, difficile à maintenir. La clé : une stratégie de migration par couches, des tests automatisés à chaque étape, et une documentation claire des décisions architecturales pour l'équipe.