# 模块
模块是具有 `@Module()` 装饰器的类。 `@Module()` 装饰器提供了元数据,Nest 用它来组织应用程序结构。
![图1](https://docs.nestjs.com/assets/Modules_1.png)
每个 Nest 应用程序至少有一个模块,即根模块。根模块是 Nest 开始安排应用程序树的地方。事实上,根模块可能是应用程序中唯一的模块,特别是当应用程序很小时,但是对于大型程序来说这是没有意义的。在大多数情况下,您将拥有多个模块,每个模块都有一组紧密相关的**功能**。
`@module()` 装饰器接受一个描述模块属性的对象:
|||
|:-----:|:-----:|
|providers| 由 Nest 注入器实例化的提供者,并且可以至少在整个模块中共享|
|controllers|必须创建的一组控制器|
|imports|导入模块的列表,这些模块导出了此模块中所需提供者|
|exports|由本模块提供并应在其他模块中可用的提供者的子集。|
默认情况下,该模块**封装**提供程序。这意味着无法注入既不是当前模块的直接组成部分,也不是从导入的模块导出的提供程序。因此,您可以将从模块导出的提供程序视为模块的公共接口或API。
## 功能模块
`CatsController` 和 `CatsService` 属于同一个应用程序域。 应该考虑将它们移动到一个功能模块下,即 `CatsModule`。
> cats/cats.module.ts
```typescript
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
```typescript
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class ApplicationModule {}
```
现在 `Nest` 知道除了 `ApplicationModule` 之外,注册 `CatsModule` 也是非常重要的。 这就是我们现在的目录结构:
```text
src
├──cats
│ ├──dto
│ │ └──create-cat.dto.ts
│ ├──interfaces
│ │ └──cat.interface.ts
│ ├─cats.service.ts
│ ├─cats.controller.ts
│ └──cats.module.ts
├──app.module.ts
└──main.ts
```
## 共享模块
在 Nest 中,默认情况下,模块是**单例**,因此您可以轻松地在多个模块之间共享**同一个**提供者实例。
![图1](https://docs.nestjs.com/assets/Shared_Module_1.png)
实际上,每个模块都是一个**共享模块**。一旦创建就能被任意模块重复使用。假设我们将在几个模块之间共享 `CatsService` 实例。 我们需要把 `CatsService` 放到 `exports` 数组中,如下所示:
> cats.module.ts
```typescript
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` ,并且它们将共享相同的 `CatsService` 实例。
## 模块导出
如上所示,模块可以导出其内部提供者。此外,他们可以重新导出他们导入的模块。在下面的示例中,既可以导入`CommonModule`**也**可以导出`CoreModule`,使其可用于导入该模块的其他模块。
```typescript
@Module({
imports: [CommonModule],
exports: [CommonModule],
})
export class CoreModule {}
```
# 依赖注入
提供者也可以注入到模块(类)中(例如,用于配置目的):
> cats.module.ts
```typescript
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) {}
}
```
但是,由于[循环依赖](https://docs.nestjs.com/fundamentals/circular-dependency)性,模块类不能注入到提供者中。
## 全局模块
如果你不得不在任何地方导入相同的模块,那可能很烦人。在 [Angular](https://angular.io) 中,提供者是在全局范围内注册的。一旦定义,他们到处可用。如果不首先导入封装模块,您将无法在其他地方使用模块的提供程序。但是有时候,你可能只想提供一组随时可用的东西 - 例如:helper,数据库连接等等,请使用`@Global()`装饰器使模块成为**全局的**。这就是为什么你能够使模块成为全局模块。
```typescript
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` 组件将无处不在,而想要使用 `CatsService` 的模块则不需要在 `imports` 数组中导入 `CatsModule`。
> 使一切全局化并不是一个好的解决方案。 全局模块可用于减少必要模板文件的数量。 `imports` 数组仍然是使模块 API 透明的最佳方式。
## 动态模块
`Nest` 模块系统包括一个称为动态模块的强大功能。此功能使您可以轻松创建可自定义的模块,这些模块可以动态注册和配置提供程序。动态模块在这里广泛介绍。在[本章](/8/fundamentals/dynamic-modules)中,我们将简要概述以完成模块介绍。
以下是一个动态模块定义的示例 `DatabaseModule`:
```typescript
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()` 装饰器元数据中)定义提供程序,但此外-根据传递给方法的 `entities` 和 `options` 对象 `forRoot()` -公开提供程序的集合,例如存储库。请注意,动态模块返回的属性扩展(而不是覆盖)`@Module()` 装饰器中定义的基本模块元数据。这就是从模块导出静态声明的 `Connection` 提供程序和动态生成的存储库提供程序的方式。
如果要在全局范围内注册动态模块,请将 `global` 属性设置为 `true`。
```typescript
{
global: true,
module: DatabaseModule,
providers: providers,
exports: providers,
}
```
> 如上所述,将所有内容全局化不是一个好的设计决策。
可以通过以下`DatabaseModule`方式导入和配置:
```typescript
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 {}
```
如果你想反过来重新导出一个动态模块,则可以 `forRoot()` 在导出数组中省略方法调用:
```typescript
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 {}
```
[动态模块](https://docs.nestjs.com/fundamentals/dynamic-modules)章介绍中更详细地在本主题,并且包括一个[实例](https://github.com/nestjs/nest/tree/master/sample/25-dynamic-modules)。
- 介绍
- 概述
- 第一步
- 控制器
- 提供者
- 模块
- 中间件
- 异常过滤器
- 管道
- 守卫
- 拦截器
- 自定义装饰器
- 基础知识
- 自定义提供者
- 异步提供者
- 动态模块
- 注入作用域
- 循环依赖
- 模块参考
- 懒加载模块
- 应用上下文
- 生命周期事件
- 跨平台
- 测试
- 技术
- 数据库
- Mongo
- 配置
- 验证
- 缓存
- 序列化
- 版本控制
- 定时任务
- 队列
- 日志
- Cookies
- 事件
- 压缩
- 文件上传
- 流式处理文件
- HTTP模块
- Session(会话)
- MVC
- 性能(Fastify)
- 服务器端事件发送
- 安全
- 认证(Authentication)
- 授权(Authorization)
- 加密和散列
- Helmet
- CORS(跨域请求)
- CSRF保护
- 限速
- GraphQL
- 快速开始
- 解析器(resolvers)
- 变更(Mutations)
- 订阅(Subscriptions)
- 标量(Scalars)
- 指令(directives)
- 接口(Interfaces)
- 联合类型
- 枚举(Enums)
- 字段中间件
- 映射类型
- 插件
- 复杂性
- 扩展
- CLI插件
- 生成SDL
- 其他功能
- 联合服务
- 迁移指南
- Websocket
- 网关
- 异常过滤器
- 管道
- 守卫
- 拦截器
- 适配器
- 微服务
- 概述
- Redis
- MQTT
- NATS
- RabbitMQ
- Kafka
- gRPC
- 自定义传输器
- 异常过滤器
- 管道
- 守卫
- 拦截器
- 独立应用
- Cli
- 概述
- 工作空间
- 库
- 用法
- 脚本
- Openapi
- 介绍
- 类型和参数
- 操作
- 安全
- 映射类型
- 装饰器
- CLI插件
- 其他特性
- 迁移指南
- 秘籍
- CRUD 生成器
- 热重载
- MikroORM
- TypeORM
- Mongoose
- 序列化
- 路由模块
- Swagger
- 健康检查
- CQRS
- 文档
- Prisma
- 静态服务
- Nest Commander
- 问答
- Serverless
- HTTP 适配器
- 全局路由前缀
- 混合应用
- HTTPS 和多服务器
- 请求生命周期
- 常见错误
- 实例
- 迁移指南
- 发现
- 谁在使用Nest?