Le futur d'Angular (part 1)
Tags: angular, webdev, productivity, opensource
Published: 2022-05-24 06:10:13

## Introduction

La release de la version 14 d'Angular approche à grand pas. Cette release est attendue avec beaucoup d'impatience par la communauté aux vues des nouveautés qu'elle apporte:

- composant standalone
- formulaire typé
- composition pattern

Toutes ces nouveautés vont avoir un réel impact sur la façon de concevoir nos applications.

**Comment utiliser ces nouveautés ? Quelles sont leurs impacts ?**

_Cet article s'appuie sur la version Angular 14 release candidate 1. Potentiellement les APIs décrites risquent d'être modifiées._

## Standalone Components

Jusqu'à maintenant, les applications Angular étaient articulées autour de la notion de modules. Ces derniers regroupent la déclaration des composants, directives, pipes et providers. 
En résumé, ces modules étaient présents pour gérer les dépendances.

Dans la version 14 d'Angular, l'équipe a décidé à travers des RFCs [ici](https://github.com/angular/angular/discussions/43784) et [là](https://github.com/angular/angular/discussions/45554) de simplifier ce modèle et rendre le composant comme élément central des applications Angular (comme peuvent le faire Vue ou React).

Afin de rendre cela possible, Angular a décidé d'introduire la notion de **composants standalone**

```ts
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  stylesUrl: './app.component.css',
  standalone: true,
  imports: [CommonModule]
})
export class AppComponent {}
```

L'annotation Component prend désormais deux nouvelles options

- standalone qui definit si notre composant se trouve être un composant standalone ou non
- imports: disponible uniquement si l'option standalone est à _true_. Cette option permet d'importer d'autres composants standalone ou des modules.

**Mais pourquoi devons-nous utiliser l'option imports pour importer des modules ?**

En réalité lorsqu'un composant est standalone, implicitement Angular va créer un module (que l'on nomme en général: virtual module)

La notion de composant standalone revient à écrire

```ts
@Module({
   declatations: [AppComponent],
   exports: [AppComponent]
})
export class AppComponent { }
```

Il est donc logique d'importer les modules dont dépend le composant standalone pour garder en place le système qui existe aujourd'hui.

Cette feature inclut des changements dans les notions suivantes:

- routing
- module
- bootstrapping de l'application

Le modèle d'Angular s'oriente plus autour du composant qu'autour du module maintenant. Dans les précédentes versions, il était nécessaire de bootstrapper sur un module, ce qui n'est plus le cas. Angular nous offre la possibilité de bootstrapper directement sur un composant à condition que celui-ci soit **standalone**

```ts
import { bootstrapApplication } from '@angular/platform-browser';

bootstrapApplication(AppComponent, { providers: [] }).then().catch();
```

**Mais si on a plus de module, comment importer par exemple _HttpClientModule_ ou encore _BrowserAnimationModule_ et surtout comment déclarer notre routing ?**

Angular est persuadé que cette problématique peut se résoudre par les _providers_. D'ailleurs c'est ce que nous expose en grande majorité les modules cité ci-dessus.

Pour palier à ce problème, Angular modifie ces APIs de deux manières:

- l'option providers qui permet d'enregistrer un provider
- la fonction **importModuleWithProviders** qui permet d'importer les providers qu'expose un module.

Ainsi si l'on souhaite importer le client HTTP d'Angular pour toute l'application, il suffira d'écrire:

```ts
bootstrapApplication(AppComponent, { providers: [
  importModuleWithProviders(HttpClientModule),
] }).then().catch();
```

**NB: À l'avenir Angular offrira une nouvelle fonction _withHttpCLient()_ qui réalisera le même travail que ci-dessus**

Du coté **Routing**, les composants standalone ont ouvert une multitude de possibilités:

- lazyloader un composant standalone
- lazyloader un ensemble de composants standalone en passant un fichier de configuration de routes

#### Lazyloader un composant standalone

Une nouvelle option est disponible lors de la déclaration de notre routing, il s'agit de l'option **loadComponent**. Cette option garde exactement la même syntaxe que l'option **loadChildren** à la différence qu'elle importe un composant standalone.

```ts
{
  path: 'user', loadComponent: () => 
    import('./feature/user.component).then(cp => cp.UserComponent)
}
```

#### Lazyloader un ensemble de composants standalone

**Sans modules**, la question de comment gérer la navigation enfant se pose.

Angular a étendu l'API de l'option loadChildren afin que celle-ci puisse charger un fichier de configuration de route en plus d'un module.

```ts
export const USER_ROUTES: Routes = [
 path: '', component: UserComponent, children: [
    { path: 'admin', component: UserAdminComponent },
    { path: 'sub-admin', component: UserSubAdminComponent }
  ]
]
```

**Attention**: tous les composants doivent être des composants de type standalone.

```ts
{
  path: 'user', loadChildren: () => 
    import('./feature/user.route').then(r => r.USER_ROUTES)
}
```

Le chargement de notre routing au sein de l'application se réalise comme pour le module HttpClientModule.

```ts
bootstrapApplication(AppComponent, { providers: [
  importModuleWithProviders(HttpClientModule),
  importModuleWithProviders(RouterModule.forRoot(APP_ROUTES))
] }).then().catch();
```

Le lien [github suivant](https://github.com/Nicoss54/standalone-components) est un exemple de comment marche la notion des composants standalone.

Cette notion n'est pas seulement applicable aux composants, elle est étendable également aux directives et aux pipes

```ts
@Directive({
  selector: '[focus]'
  standalone: true
})
export class FocusDirective {}

@Pipe({
  name: 'na',
  standalone: true
})
export class NaPipe implements PipeTransform {}
```

## Conclusion

Les composants standalone ouvrent de nouvelles possibilités pour rendre nos applications et librairies encore plus scalables.

L'architecture atomique pronée par Angular et les modules restent de mises à la seule différence qu'elle sera moins boilerplating (deux fichiers au lieu de trois pour un bootstrapping par exemple).

Dans cette nouvelle version, composants, directives et pipes pourront s'utiliser 'out of the box'. Nullement besoin de les déclarer dans un module au préalable.