# 模塊
模塊是具有 `@Module()` 裝飾器的類。 `@Module()` 裝飾器提供了元數據,Nest 用它來組織應用程序結構。

每個 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 中,默認情況下,模塊是**單例**,因此您可以輕松地在多個模塊之間共享**同一個**提供者實例。

實際上,每個模塊都是一個**共享模塊**。一旦創建就能被任意模塊重復使用。假設我們將在幾個模塊之間共享 `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?