Aller au contenu

Angular 15

Angular 15 est là ! Les Standalone Components permettent de créer des composants, directives et pipes sans les NgModules. Simplification de la gestion des dépendances et amélioration des performances. D'autres améliorations incluent le router, HttpClient, TypeScript 4.9 et plus encore.

Photo by Arno Senoner / Unsplash

Je suis ravi de vous présenter un résumé des nouvelles fonctionnalités d'Angular 15, qui est sorti le 16 novembre 2022, comme prévu 5 mois après la version 14 qui avait un petit peu de retard, ainsi que d'Angular 15.1, qui est sorti récemment. Je suis là pour vous partager les points saillants de ces versions. Allons-y !

Goodbye NgModules !

Un changement majeur dans la façon de concevoir la modularité dans Angular est arrivé avec la stabilité des Standalone Components.

Que ce soit pour les composants, les directives ou les pipes, il est désormais possible de les créer en mode standalone. Cela signifie que l'utilisation des NgModules n'est plus obligatoire pour ces éléments, car ils peuvent désormais être considérés comme des modules à part entière.

Pour l'instant, les NgModules ne sont pas dépréciés, mais leur utilisation pourrait évoluer dans le futur. Il n'y a pas encore de clarification complète sur ce point. Cependant, nous pouvons toujours créer des NgModules pour regrouper nos éléments standalone et les importer ensemble. À l'avenir, il se peut que nous devions apprendre à nous passer totalement des NgModule.

Dans le même temps, cette évolution offre de nombreux avantages. Par exemple, lors des tests, il n'est plus nécessaire d'indiquer explicitement les dépendances lorsque nous ne voulons pas les simuler, car la résolution se fait automatiquement pour les NgModules dans le TestBed. De plus, avec chaque élément qui définit ses propres dépendances, il sera plus facile de repérer les éléments qui ne sont plus utilisés !

Il est également à noter l'introduction d'un nouveau paramètre --standalone lors de la création de composants, de directives et de pipes, permettant de les créer directement sans module.

Quelques changements dans le router

Une nouveauté intéressante est l'utilisation de provideRouter() pour la création du router. Du point de vue du développeur, cela ne change pas grand-chose, mais en interne, cela peut réduire la taille du bundle jusqu'à 11% grâce à une meilleure prise en charge de l'optimisation du code (tree-shaking).

Dans le même ordre d'idées, une petite amélioration de syntaxe a été introduite : l'auto-unwrap du default pour les imports dynamiques. L'idée est simple : si vous souhaitez effectuer un import dynamique, vous n'êtes plus obligé d'écrire quelque chose du type .then(m => m.MyModule), vous pouvez simplement l'omettre et Angular s'en chargera pour vous. L'exemple ci-dessous illustre cette utilisation avec les lazyRoutes.

// lazy.router.ts
import {Routes} from '@angular/router';
import {LazyComponent} from './lazy.component';

export default const lazyRoutes: Routes = [{path: '', component: LazyComponent}];

// app.router.ts
export const appRoutes: Routes = [{
  path: 'lazy',
  loadChildren: () => import('./lazy/lazy.routes')
}];

// main.ts
bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(appRoutes)
  ]
});

Une évolution notable est la dépréciation (à partir de la version 15.1) du guard CanLoad au profit de CanMatch, qui offre une fonctionnalité plus intéressante. CanMatch est désormais activé à chaque navigation, tout comme CanActivate.

Côté HttpClient

Une nouveauté intéressante est la possibilité de se passer de HttpClientModule et d'utiliser provideHttpClient() à la place (et provideHttpClientTesting() pour remplacer HttpClientTestingModule).

De plus, il est maintenant possible d'écrire des intercepteurs sous forme de fonctions, ce qui rend tout plus fonctionnel. Cependant, il convient de noter que les intercepteurs ne s'appliquent pas automatiquement aux modules chargés de manière paresseuse (lazy loaded). Pour résoudre ce problème, il faut utiliser withRequestsMadeViaParent().

import {
  provideHttpClient,
  withRequestsMadeViaParent,
  withInterceptors,
} from '@angular/common/http';

export default [
  {
    path: '',
    providers: [
      provideHttpClient(
        withRequestsMadeViaParent(),
        withInterceptors([
          (req, next) => {
            console.log('TodosComponent Interceptors');
            return next(req);
          },
        ])
      ),
    ],
    loadComponent() {
      return import('./todos/todos.component');
    },
  },
];

Directive Composition

@Component({
  selector: 'mat-menu',
  hostDirectives: [HasColor, {
    directive: CdkMenu,
    inputs: ['cdkMenuDisabled: disabled'],
    outputs: ['cdkMenuClosed: closed']
  }]
})
class MatMenu {}

Une nouvelle fonctionnalité intéressante est l'ajout de la composition de directives. Dans cet exemple, nous créons une directive "MatMenu" qui est améliorée grâce à l'utilisation des directives "HasColor" et "CdkMenu". La directive "HasColor" est entièrement reprise, avec tous ses entrées (Input) et sorties (Output), ainsi que sa logique, dans la directive "MatMenu" sans avoir à faire quoi que ce soit de plus. Quant à la directive "CdkMenu", seule une partie de ses entrées est reprise, mais toute sa logique est présente.

Cette possibilité ouvre de nombreuses opportunités de réutilisation de code ! Personnellement, c'est quelque chose qui me manquait dans de nombreux cas, surtout que React propose depuis longtemps des HOC (Higher-Order Component).

Il est important de noter que cette fonctionnalité n'est disponible que si les directives utilisées dans la composition sont elles-mêmes des "standalones".

Quelques changements plus anecdotiques

Goodbye useless ngOnInit()

Dans les futures générations de composants, la méthode ngOnInit() ne sera plus automatiquement générée dans la grande majorité des cas. Cependant, vous pourrez toujours l'ajouter manuellement si nécessaire !

Self closing tag (15.1)

Cette version apporte une amélioration attendue par de nombreux développeurs, en particulier ceux qui travaillent également avec React. Désormais, il est possible d'écrire l'une ou l'autre des variantes suivantes :

<my-component />
<my-component></my-component>
<!-- work also with ng-content and ng-container -->
<ng-content />
<ng-container />

Version plus récente de TypeScript

À partir de la version 15, il est possible d'utiliser TypeScript 4.8.2+ et même la version 4.9 pour la 15.1. Comme d'habitude, plusieurs améliorations ont été apportées à la compilation, sans nécessiter de configuration supplémentaire.

~ déprécié dans Sass

Lors de la mise à jour vers la version 15, vous pourriez rencontrer cette erreur :

'src/styles.scss' imports '~font-awesome/scss/font-awesome' with a tilde. Usage of '~' in imports is deprecated.

Pas de panique, il vous suffit de supprimer le symbole ~ et tout devrait fonctionner comme avant. Cette erreur est causée par l'utilisation d'une version plus récente du compilateur Sass, qui offre de meilleures performances. Si vous ne mettez pas à jour votre projet à l'aide de la CLI, vous devrez effectuer cette modification manuellement dans vos fichiers. Toutefois, si vous utilisez le CLI, un schéma se chargera automatiquement de mettre à jour ces importations pour vous !

Conclusion

En conclusion, la version 15 d'Angular apporte son lot de nouveautés et d'améliorations significatives. Les développements autour de la modularité offrent une plus grande flexibilité en permettant la création de composants, directives et pipes en mode standalone, sans nécessairement recourir aux NgModules. Cette approche simplifie la gestion des dépendances et facilite l'identification des éléments inutiles, tout en offrant des gains en termes de taille de bundle et de performances.

Par ailleurs, cette version introduit des fonctionnalités appréciables, telles que l'auto-unwrap du default pour les imports dynamiques, rendant ainsi le code plus concis et plus agréable à écrire. Les évolutions au niveau des DevTools, la compatibilité totale avec Firefox et la possibilité de les utiliser hors ligne sont également des améliorations notables. Avec ces avancées majeures, Angular continue de s'adapter et de répondre aux besoins des développeurs, offrant ainsi une expérience de développement améliorée et des possibilités étendues pour la création d'applications web modernes.

Dernier