Modules
Un module est une classe annotée avec un décorateur @Module()
. Le décorateur @Module()
fournit des métadonnées que Nest utilise pour organiser la structure de l’application.
Chaque application a au moins un module, un module racine. Le module racine est le point de départ que Nest utilise pour construire le graphique de l’application - la structure de données interne que Nest utilise pour résoudre les relations et dépendances entre modules et fournisseurs. Bien que des applications très petites puissent théoriquement avoir juste le module racine, ce n’est pas le cas typique. Nous voulons mettre en avant que les modules sont fortement recommandés comme une manière efficace d’organiser vos composants. Ainsi, pour la plupart des applications, l’architecture résultante emploiera plusieurs modules, chacun encapsulant un ensemble de capabilités étroitement liées.
Le décorateur @Module()
prend un seul objet dont les propriétés décrivent le module :
Propriété | Description |
---|---|
providers | les fournisseurs qui seront instanciés par l’injecteur Nest et qui peuvent être partagés au moins à travers ce module |
controllers | l’ensemble des contrôleurs définis dans ce module qui doivent être instanciés |
imports | la liste des modules importés qui exportent les fournisseurs requis dans ce module |
exports | le sous-ensemble des providers fournis par ce module et qui devraient être disponibles dans d’autres modules qui importent ce module. Vous pouvez utiliser soit le fournisseur lui-même ou simplement son token (valeur provide ) |
Le module encapsule des fournisseurs par défaut. Cela signifie qu’il est impossible d’injecter des fournisseurs qui ne font pas directement partie du module courant ni qui ne sont pas exportés des modules importés. Ainsi, vous pouvez considérer les fournisseurs exportés d’un module comme l’interface publique du module, ou API.
Modules de fonctionnalité
Le CatsController
et le CatsService
appartiennent au même domaine d’application. Comme ils sont étroitement liés, il est logique de les déplacer dans un module de fonctionnalité. Un module de fonctionnalité organise simplement le code pertinent pour une fonctionnalité spécifique, gardant le code organisé et établissant des limites claires. Cela nous aide à gérer la complexité et à développer avec les principes SOLID, surtout à mesure que la taille de l’application et/ou de l’équipe augmente.
Pour démontrer cela, nous allons créer le CatsModule
.
import { Module } from '@nestjs/common';import { CatsController } from './cats.controller';import { CatsService } from './cats.service';
@Module({ controllers: [CatsController], providers: [CatsService],})export class CatsModule {}
Au-dessus, nous avons défini le CatsModule
dans le fichier cats.module.ts
, et déplacé tout ce qui concerne ce module dans le répertoire cats
. La dernière chose à faire est d’importer ce module dans le module racine (le AppModule
, défini dans le fichier app.module.ts
).
import { Module } from '@nestjs/common';import { CatsModule } from './cats/cats.module';
@Module({ imports: [CatsModule],})export class AppModule {}
Voici à quoi ressemble notre structure de répertoire maintenant :
Répertoiresrc
Répertoirecats
Répertoiredto
- create-cat.dto.ts
Répertoireinterfaces
- cat.interface.ts
- cats.controller.ts
- cats.module.ts
- cats.service.ts
- app.module.ts
- main.ts
Modules partagés
Dans Nest, les modules sont singletons par défaut, et par conséquent vous pouvez partager la même instance de n’importe quel fournisseur entre plusieurs modules sans effort.
Chaque module est automatiquement un module partagé. Une fois créé, il peut être réutilisé par n’importe quel module. Imaginons que nous souhaitions partager une instance du CatsService
entre plusieurs autres modules. Pour cela, nous devons d’abord exporter le fournisseur CatsService
en l’ajoutant au tableau <code>exports</code>
du module, comme montré ci-dessous :
import { Module } from '@nestjs/common';import { CatsController } from './cats.controller';import { CatsService } from './cats.service';
@Module({ controllers: [CatsController], providers: [CatsService], exports: [CatsService],})export class CatsModule {}
Maintenant, tout module qui importe le CatsModule
a accès au CatsService
et partagera la même instance avec tous les autres modules qui l’importent également.
Ré-exportation de module
Comme vu précédemment, les modules peuvent exporter leurs fournisseurs internes. De plus, ils peuvent ré-exporter les modules qu’ils importent. Dans l’exemple ci-dessous, le CommonModule
est à la fois importé dans et exporté du CoreModule
, le rendant disponible pour d’autres modules qui importent celui-ci.
import { Module } from '@nestjs/common';import { CommonModule } from '@nestjs/common';
@Module({ imports: [CommonModule], exports: [CommonModule],})export class CoreModule {}
Injection de dépendance
Une classe de module peut également injecter des fournisseurs (par exemple, pour des raisons de configuration) :
import { Module } from '@nestjs/common';import { CatsController } from './cats.controller';import { CatsService } from './cats.service';
@Module({ controllers: [CatsController], providers: [CatsService],})export class CatsModule { constructor(private catsService: CatsService) {}}
Cependant, les classes de module elles-mêmes ne peuvent pas être injectées en tant que fournisseurs en raison d’une dépendance circulaire.
Modules globaux
Si vous devez importer le même ensemble de modules partout, cela peut devenir fastidieux. Contrairement à Nest, les <a rel="nofollow" target="_blank" href="https://angular.fr">Angular</a>
enregistre les providers
dans le scope global. Une fois définis, ils sont disponibles partout. Nest, cependant, encapsule les fournisseurs à l’intérieur du scope du module. Vous ne pouvez pas utiliser les fournisseurs d’un module ailleurs sans d’abord importer le module encapsulant.
Lorsque vous souhaitez fournir un ensemble de fournisseurs qui devraient être disponibles partout dès le départ (par exemple, des helpers, des connexions à la base de données, etc.), rendez le module global avec le décorateur @Global()
.
import { Module, Global } from '@nestjs/common';import { CatsController } from './cats.controller';import { CatsService } from './cats.service';
@Global()@Module({ controllers: [CatsController], providers: [CatsService], exports: [CatsService],})export class CatsModule {}
Le décorateur @Global()
rend le module global. Les modules globaux doivent être enregistrés une seule fois, généralement par le module racine ou central. Dans l’exemple ci-dessus, le fournisseur CatsService
sera omniprésent, et les modules qui souhaitent injecter le service n’auront pas besoin d’importer le CatsModule
dans leur tableau d’importations.
Modules dynamiques
Le système de modules de Nest inclut une fonctionnalité puissante appelée modules dynamiques. Cette fonctionnalité vous permet de créer facilement des modules personnalisables qui peuvent enregistrer et configurer des fournisseurs dynamiquement. Les modules dynamiques sont couverts en profondeur ici. Dans ce chapitre, nous donnerons un aperçu pour compléter l’introduction aux modules.
Voici un exemple de définition d’un module dynamique pour un DatabaseModule
:
import { Module, DynamicModule } from '@nestjs/common';import { createDatabaseProviders } from './database.providers';import { Connection } from './connection.provider';
@Module({ providers: [Connection], exports: [Connection],})export class DatabaseModule { static forRoot(entities = [], options?) : DynamicModule { const providers = createDatabaseProviders(options, entities); return { module: DatabaseModule, providers: providers, exports: providers, }; }}
Ce module définit le fournisseur Connection
par défaut (dans les métadonnées du décorateur @Module()
), mais en outre - selon les objets entities
et options
passés au méthode forRoot()
- expose une collection de fournisseurs, par exemple, des dépôts. Notez que les propriétés retournées par le module dynamique étendent (plutôt que de remplacer) les métadonnées de module de base définies dans le décorateur @Module()
. C’est ainsi que le fournisseur Connection
déclaré statiquement et les fournisseurs de dépôt générés dynamiquement sont tous deux exportés à partir du module.
Si vous souhaitez enregistrer un module dynamique dans le scope global, définissez la propriété global
sur true
.
{ global: true, module: DatabaseModule, providers: providers, exports: providers,}
Le DatabaseModule
peut être importé et configuré de la manière suivante :
import { Module } from '@nestjs/common';import { DatabaseModule } from './database/database.module';import { User } from './users/entities/user.entity';
@Module({ imports: [DatabaseModule.forRoot([User])],})export class AppModule {}
Si vous souhaitez à votre tour ré-exporter un module dynamique, vous pouvez omettre l’appel de méthode forRoot()
dans le tableau d’exports :
import { Module } from '@nestjs/common';import { DatabaseModule } from './database/database.module';import { User } from './users/entities/user.entity';
@Module({ imports: [DatabaseModule.forRoot([User])], exports: [DatabaseModule],})export class AppModule {}
Le chapitre sur les modules dynamiques couvre ce sujet plus en détail, et inclut un exemple fonctionnel.