在线文档教程

模块

模块

模块是用@Module()装饰器注释的类。的@Module()装饰提供了元数据, Nest利用它来组织应用程序结构

每个应用程序至少有一个模块,一个根模块根模块是Nest用来构建应用程序图的起点。实际上,根模块可能是应用程序中唯一的模块,尤其是当应用程序很小时。然而,对于大型应用程序,它没有意义。在大多数情况下,您将拥有多个模块,每个模块封装一组紧密相关的功能

所述@Module()装饰采用单个对象,其属性描述该模块:

providers将由Nest注入器实例化的提供程序,并且至少可以在此模块上共享。
controllers必须创建的控制器集
imports导出此模块中所需的提供程序的导入模块列表
exports其子集providers由此模块提供,并且应该在其他模块中可用

功能模块

CatsControllerCatsService属于同一应用程序域。由于它们密切相关,因此将它们移入功能模块是有意义的。功能模块仅组织与特定功能相关的代码,使代码井井有条,并建立清晰的边界。这有助于我们管理复杂性并按照SOLID原则进行开发,尤其是随着应用程序和/或团队规模的增长。

cats/ cats.module.ts

JS

import { Module } from '@nestjs/common'; import { CatsController } from './cats.controller'; import { CatsService } from './cats.service'; @Module{ controllers: [CatsController], providers: [CatsService], }) export class CatsModule {}

提示要使用CLI创建模块,只需执行$ nest g module cats命令即可。

我们定义了cats.module.ts文件,然后将与此模块相关的所有内容移动到cats目录中。我们需要做的最后一件事是将此模块导入根模块(ApplicationModule)。

app.module.ts

JS

import { Module } from '@nestjs/common'; import { CatsModule } from './cats/cats.module'; @Module{ imports: [CatsModule], }) export class ApplicationModule {}

这就是我们的目录结构现在的样子:

Cat

DTO

create-cat.dto.ts

接口

cat.interface.ts

cats.service.ts

cats.controller.ts

cats.module.ts

app.module.ts

main.ts

共享模块

在Nest中,默认情况下模块是单例,因此您可以毫不费力地在多个模块之间共享任何提供程序的相同实例

事实上,每个模块都是一个共享模块。一旦创建,它可以被任何模块重用。让我们想象一下,我们希望CatsService在其他几个模块之间共享实例。为了做到这一点,我们首先需要导出CatsService通过将其添加到模块的供应商exports阵列,如下图所示:

cats.module.ts

JS

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 {}

现在,任何导入的模块CatsModule都可以访问,并将CatsService与导入该模块的所有其他模块共享同一实例。

模块重新导出

如上所述,模块可以导出其内部提供程序。而且,他们可以重新导出自己导入的模块。在下面的示例中,CommonModule既导入从导出的CoreModule,使得它可用于其中导入其它模块。

JS

@Module{ imports: [CommonModule], exports: [CommonModule], }) export class CoreModule {}

依赖注入

模块类也可以注入提供者(例如,用于配置目的):

cats.module.ts

JS

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 readonly catsService: CatsService) {} }

但是,由于循环依赖性,提供程序无法注入模块类。

全局模块

如果你必须在任何地方导入相同的模块集,那可能会很烦人。在Angular中,providers它们在全局范围内注册。一旦定义,它们随处可用。另一方面,Nest将提供程序封装在模块范围内。您无法在不导入模块提供程序的情况下使用模块提供程序。但有时候,您可能只想提供一组应该始终可用的东西 - 开箱即用,例如:帮助程序,数据库连接等等。这就是为什么你能够使模块成为全局模块的原因。

JS

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 {}

@Global()装饰使得模块全局范围。全局模块只能注册一次,最好是根模块或核心模块之后,CatsService提供商将无处不在,但CatsModule不会被导入。

提示让一切都变得全局化并不是一个好的决定。全局模块可用于减少必要的样板量。该imports阵列仍然是使模块API透明的最佳方法。

动态模块

Nest模块系统包括一个称为动态模块的强大功能。使用此功能,您可以轻松创建可自定义的模块,这些模块可以动态注册和配置提供程序。动态模块在这里进行了广泛的介绍。在本章中,我们将简要概述以完成对模块的介绍。

JS

import { Module, DynamicModule } from '@nestjs/common'; import { createDatabaseProviders } from './database.providers'; import { Connection } from './connection.provider'; @Module{ providers: [Connection], }) export class DatabaseModule { static forRoot(entities = [], options?): DynamicModule { const providers = createDatabaseProviders(options, entities return { module: DatabaseModule, providers: providers, exports: providers, }; } }

提示forRoot()可能返回动态模块同步或异步(Promise)。

此模块Connection默认情况下(在@Module()装饰器元数据中)定义了提供程序,但此外-根据传递给该方法的entitiesoptions对象forRoot(),还公开了提供程序的集合,例如存储库。请注意,动态模块返回的属性扩展(而不是覆盖)@Module()装饰器中定义的基本模块元数据。这就是从模块中导出静态声明的Connection提供程序动态生成的存储库提供程序的方式。

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 ApplicationModule {}

为了导出动态模块,可以省略函数调用部分:

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 ApplicationModule {}