1. モジュールとは何ですか?
モジュールは、NestJS のコード編成の単位です。すべてのアプリケーションには少なくとも 1 つのモジュールがあります — ルートモジュール (アプリモジュール)。 NestJS はそれに応じてコードの編成を奨励します 機能モジュール、各モジュールは関連する関数のグループをカプセル化します。
@Module({
imports: [], // Modules khác mà module này cần
controllers: [], // Controllers thuộc module này
providers: [], // Services/Providers thuộc module này
exports: [], // Providers được chia sẻ ra ngoài
})
export class UsersModule {}
2. 機能モジュール
// Cấu trúc thư mục theo feature
src/
├── app.module.ts // Root module
├── users/
│ ├── users.module.ts
│ ├── users.controller.ts
│ ├── users.service.ts
│ ├── dto/
│ │ ├── create-user.dto.ts
│ │ └── update-user.dto.ts
│ └── entities/
│ └── user.entity.ts
├── products/
│ ├── products.module.ts
│ ├── products.controller.ts
│ ├── products.service.ts
│ └── ...
└── orders/
├── orders.module.ts
└── ...
// users.module.ts
@Module({
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService], // Cho phép module khác dùng UsersService
})
export class UsersModule {}
// orders.module.ts — cần dùng UsersService
@Module({
imports: [UsersModule], // Import để dùng exported providers
controllers: [OrdersController],
providers: [OrdersService],
})
export class OrdersModule {}
// app.module.ts — Root module
@Module({
imports: [UsersModule, ProductsModule, OrdersModule],
})
export class AppModule {}
3. 共有モジュール
// Shared module — chứa các utilities dùng chung
@Module({
providers: [
HelperService,
SlugService,
PaginationService,
],
exports: [
HelperService,
SlugService,
PaginationService,
],
})
export class SharedModule {}
// Sử dụng trong nhiều modules
@Module({
imports: [SharedModule], // Mỗi module cần import riêng
// ...
})
export class UsersModule {}
@Module({
imports: [SharedModule],
// ...
})
export class ProductsModule {}
4. グローバルモジュール
// Global module — không cần import trong từng module
@Global()
@Module({
providers: [
ConfigService,
LoggerService,
CacheService,
],
exports: [
ConfigService,
LoggerService,
CacheService,
],
})
export class CoreModule {}
// Chỉ cần import một lần trong AppModule
@Module({
imports: [CoreModule, UsersModule, ProductsModule],
})
export class AppModule {}
// Bây giờ mọi module đều có thể inject ConfigService
// mà KHÔNG cần import CoreModule
@Injectable()
export class UsersService {
constructor(private config: ConfigService) {} // ✅ Works!
}
⚠️警告: 悪用しないでください @グローバル()。 Config、Logger、Cache などの真にグローバルなサービスにのみ使用されます。
5. 動的モジュール
// Dynamic module — cấu hình tại thời điểm import
@Module({})
export class DatabaseModule {
static forRoot(options: DatabaseOptions): DynamicModule {
return {
module: DatabaseModule,
global: true,
providers: [
{ provide: 'DATABASE_OPTIONS', useValue: options },
{
provide: 'DATABASE_CONNECTION',
useFactory: async (opts: DatabaseOptions) => {
return await createConnection(opts);
},
inject: ['DATABASE_OPTIONS'],
},
DatabaseService,
],
exports: [DatabaseService, 'DATABASE_CONNECTION'],
};
}
// forFeature — đăng ký entities/repositories
static forFeature(entities: Type[]): DynamicModule {
const repositories = entities.map(entity => ({
provide: getRepositoryToken(entity),
useFactory: (connection: Connection) => connection.getRepository(entity),
inject: ['DATABASE_CONNECTION'],
}));
return {
module: DatabaseModule,
providers: repositories,
exports: repositories,
};
}
}
// Sử dụng
@Module({
imports: [
DatabaseModule.forRoot({ // Root config
host: 'localhost',
port: 5432,
database: 'myapp',
}),
],
})
export class AppModule {}
@Module({
imports: [
DatabaseModule.forFeature([User, Product]), // Feature entities
],
})
export class UsersModule {}
6. モジュールの再エクスポート
@Module({
imports: [CommonModule],
exports: [CommonModule], // Re-export cả module
})
export class CoreModule {}
// Ai import CoreModule sẽ tự động có access CommonModule
7. 循環依存関係の処理
// ❌ Circular: UsersModule ↔ OrdersModule
// UsersModule imports OrdersModule
// OrdersModule imports UsersModule
// ✅ Giải pháp: forwardRef()
@Module({
imports: [forwardRef(() => OrdersModule)],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
@Module({
imports: [forwardRef(() => UsersModule)],
providers: [OrdersService],
exports: [OrdersService],
})
export class OrdersModule {}
// Trong service
@Injectable()
export class UsersService {
constructor(
@Inject(forwardRef(() => OrdersService))
private ordersService: OrdersService,
) {}
}
ベストプラクティス: 循環依存を避けてください。発生した場合は、共通ロジックを共有モジュールに分割するか、イベントベースの通信を使用します。
8. まとめ
- 機能モジュール: ビジネスドメインに応じてコードを整理する
- 共有モジュール: 共有ユーティリティが含まれており、インポートが必要です
- グローバルモジュール:
@グローバル()、どこでも自動的に利用可能 - 動的モジュール:
forRoot()/forFeature()パターン。パターン - 循環依存関係を避け、イベントベースの通信を優先します
次の投稿がつながります TypeORMとPrismaによるデータベース。