Blog angular

Standalone component en Angular, une nouvelle approche qui fait du bien

Rémi T. 6 min de lecture

Standalone component en Angular, une nouvelle approche qui fait du bien

Lorsque nous travaillons sur un projet Angular, nous sommes confrontés à de nombreuses décisions architecturales. L’une de ces décisions concerne la manière dont nous diviserons l’application. Historiquement, nous utilisions le concept de module. Seulement, depuis la version 15 (en réalité depuis la version 14 si l’on compte la phase de preview), une nouvelle approche possible est celle des standalone components. Elle se démarque comme une solution élégante pour simplifier l’architecture de notre application, et sera sûrement la plus plébiscitée par la team Angular dans le futur.

Qu’est-ce qu’un standalone component ?

Le principal objectif d’un standalone component est de se passer du concept de module. Finis les modules avec la déclaration d’une trentaine de composants, pipes, directives et j’en passe. Fini également ce bon vieux SharedModule importé partout dans notre application. Utiliser des standalone components dans notre application présente de nombreux avantages.

1. Réutilisation facilitée

Ils favorisent la réutilisation du code. Nous pouvons créer des composants spécialisés pour des fonctionnalités spécifiques et les réutiliser dans toute notre application plus facilement, étant donné qu’ils ne seront liés à aucun module. Ils n’ont pas besoin d’être déclarés dans un module, ce qui réduit également la quantité de code.

2. Maintenance et testabilité améliorées

En isolant des fonctionnalités spécifiques dans des standalone components, la maintenance du code devient plus simple. Ils sont plus concis et peuvent tout autant importer des composants, modules, pipes et directives.

Les standalone components sont plus faciles à tester, car ils sont indépendants et ont une portée limitée. Cela facilite la création de tests unitaires pour garantir le bon fonctionnement de chaque composant. D’un point de vue qualité de code, ils permettent d’éviter d’écrire du code redondant et rendent l’utilisation d’Angular plus simple. Ils sont aussi plus performants et tree-shakable.

3. Recommandé mais pas obligatoire

Les standalone components ne sont pas obligatoires et peuvent s’intégrer très facilement dans une application modularisée déjà existante. Cela signifie que nous pouvons migrer de manière incrémentale vers ce concept sans casser toute notre application.

Comment créer un standalone component ?

Le plus simple pour créer un nouveau standalone component est d’utiliser la CLI Angular pour générer un nouveau composant en spécifiant l’option --standalone :

ng generate component my-component --standalone

En ouvrant le fichier TypeScript de notre composant, nous voyons que la propriété standalone dans l’annotation @Component a pour valeur true, ce qui signifie que notre composant est défini en tant que standalone.

@Component({
  selector: 'app-my-component',
  standalone: true,
  imports: [],
  templateUrl: './my-component.component.html',
  styleUrls: ['./my-component.component.scss']
})
export class MyComponentComponent {}

Attention : maintenant que MyComponentComponent est défini comme standalone, il ne peut plus être déclaré dans la propriété declarations d’un module. Pour l’utiliser, il faudra l’importer dans celui-ci (nous verrons cela un peu plus loin dans l’article).

À la manière d’un module, nous pouvons dorénavant utiliser la propriété imports pour importer ce dont nous avons besoin dans notre composant (autres composants, pipes, directives, modules, etc.).

Le but d’un standalone component étant de n’importer que le strict nécessaire afin qu’il soit le plus petit possible, il faut faire attention à ce que nous importons. Depuis la version 15, il est maintenant possible de se passer du CommonModule en n’important que les directives et pipes que nous utilisons dans le template :

import { NgIf, NgFor } from '@angular/common';

@Component({
  selector: 'app-my-component',
  standalone: true,
  imports: [NgIf, NgFor],
  templateUrl: './my-component.component.html',
  styleUrls: ['./my-component.component.scss']
})
export class MyComponentComponent {}

De plus, si vous voulez éviter de passer l’option --standalone à la CLI à chaque fois que vous voulez créer un nouveau composant, vous pouvez définir globalement cette option dans le fichier angular.json à la racine de votre application :

{
  "projects": {
    "my-app": {
      "schematics": {
        "@schematics/angular:component": {
          "standalone": true
        }
      }
    }
  }
}

Comment utiliser un standalone component ?

Maintenant que nous avons créé un standalone component, voyons comment nous pouvons l’utiliser dans notre application. Nous n’avons plus de module pour l’importer, donc nous importons directement le composant dans un autre module (ou même dans un autre standalone component) :

import { NgModule } from '@angular/core';
import { MyComponentComponent } from './my-component/my-component.component';

@NgModule({
  imports: [MyComponentComponent]
})
export class AppModule {}

Et voilà : son utilisation reste similaire à un composant « classique » dans le template :

<app-my-component></app-my-component>

Routing et standalone component

Mais dans tout ça, comment faire pour déclarer notre standalone component en point d’entrée d’une route ? Pour cela rien de plus simple : rien ne change par rapport à un composant « classique », on utilise toujours la propriété component en déclarant notre route.

const routes: Routes = [
  { path: 'my-path', component: MyComponentComponent }
];

Cependant, utiliser cette solution n’est pas recommandé car nous ne faisons pas de lazy loading (ce qui n’est pas idéal pour de nombreuses raisons). Pour corriger cela, nous avons deux possibilités.

La première avec la syntaxe loadComponent, similaire au lazy loading de module :

const routes: Routes = [
  {
    path: 'my-path',
    loadComponent: () =>
      import('./my-component/my-component.component')
        .then(m => m.MyComponentComponent)
  }
];

Sauf que cette solution ne fonctionne que pour faire du lazy loading avec une seule route. Pour faire du lazy loading avec plusieurs routes, nous pouvons importer plusieurs routes d’un seul coup avec la syntaxe suivante :

const routes: Routes = [
  {
    path: 'my-path',
    loadChildren: () =>
      import('./my-component/my-component.routes')
        .then(m => m.MY_COMPONENT_ROUTES)
  }
];

Pour plus d’informations sur le concept de routing et standalone component, la documentation officielle est bien faite.

Que pouvons-nous migrer en standalone ?

Le concept de standalone ne se limite pas aux composants. Tout ce qui est importable dans un module (sauf un module lui-même) peut être migré en standalone, c’est-à-dire :

  • Composants
  • Pipes
  • Directives

Et même :

  • Router
  • Application

Pour migrer facilement vers le concept de standalone, la CLI Angular met à disposition une commande pour nous simplifier la vie. Avant de la lancer, nous devons vérifier que :

  • Nous utilisons au minimum la version 15.2 d’Angular
  • Notre application build sans erreur
  • Notre branche git est propre

Puis nous pouvons lancer la commande suivante pour convertir tous nos composants, pipes et directives en standalone :

ng generate @angular/core:standalone

Cette commande possède plusieurs options. Pour plus d’informations, référez-vous à la documentation officielle.

Take away

Le concept de standalone en Angular offre une approche puissante pour améliorer la modularité, la réutilisation de code et la maintenabilité de vos applications. En les utilisant efficacement, vous pouvez segmenter votre code en composants indépendants, facilitant ainsi le développement, la mise à jour et l’extension de vos composants.

Cette approche vous permet de vous passer du concept de module, de favoriser la réactivité et de maximiser la performance de votre application. Vous pouvez grandement simplifier le processus de développement en Angular, en créant des applications plus robustes et évolutives.

Contact

Et votre prochaine mission ?