Appearance
NestJS模块系统
NestJS模块系统是组织应用程序结构的核心机制。模块是一个带有@Module()装饰器的类,它提供元数据,Nest用来组织应用程序结构。本章详细介绍NestJS模块系统的各个方面。
模块基础
模块定义
@Module()装饰器接受一个描述模块属性的对象:
typescript
import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
import { CatsService } from './cats/cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
imports: [],
exports: [],
})
export class CatsModule {}
模块元数据详解
typescript
@Module({
// 控制器数组 - 处理传入请求并返回响应
controllers: [
CatsController,
DogsController,
],
// 提供者数组 - 注入器可以实例化的服务、仓库、工厂等
providers: [
CatsService,
DogsService,
{
provide: 'CONFIG_SERVICE',
useFactory: () => {
// 工厂函数创建提供者
return new ConfigService();
},
},
],
// 导入模块数组 - 依赖的其他模块
imports: [
DatabaseModule,
CommonModule,
ConfigModule.forRoot({ isGlobal: true }),
],
// 导出提供者数组 - 其他模块可以使用的提供者
exports: [
CatsService,
'CONFIG_SERVICE', // 可以导出自定义提供者
],
})
export class AppModule {}
功能模块
简单功能模块
typescript
// users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService], // 导出服务供其他模块使用
})
export class UsersModule {}
复杂功能模块
typescript
// posts/posts.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PostsController } from './posts.controller';
import { PostsService } from './posts.service';
import { Post } from './entities/post.entity';
import { Comment } from './entities/comment.entity';
import { UsersModule } from '../users/users.module';
@Module({
imports: [
// TypeORM集成
TypeOrmModule.forFeature([Post, Comment]),
// 依赖其他模块
UsersModule,
],
controllers: [PostsController],
providers: [
PostsService,
// 自定义提供者
{
provide: 'POST_VALIDATOR',
useClass: PostValidatorService,
},
],
exports: [PostsService],
})
export class PostsModule {}
核心模块
共享模块
typescript
// shared/shared.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { ConfigModule } from '@nestjs/config';
import { DatabaseModule } from '../database/database.module';
import { LoggerService } from './logger/logger.service';
import { ValidationService } from './validation/validation.service';
@Module({
imports: [
ConfigModule,
JwtModule.register({
secret: process.env.JWT_SECRET,
signOptions: { expiresIn: '1h' },
}),
DatabaseModule,
],
providers: [
LoggerService,
ValidationService,
],
exports: [
LoggerService,
ValidationService,
JwtModule,
ConfigModule,
],
})
export class SharedModule {}
全局模块
typescript
// database/database.module.ts
import { Module, Global } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { DatabaseService } from './database.service';
@Global() // 全局模块 - 只需导入一次
@Module({
imports: [ConfigModule],
providers: [DatabaseService],
exports: [DatabaseService],
})
export class DatabaseModule {}
// 在app.module.ts中只需导入一次
@Module({
imports: [DatabaseModule], // 全局模块,其他模块无需再次导入
// ...
})
export class AppModule {}
动态模块
基础动态模块
typescript
// config/config.module.ts
import { Module, DynamicModule } from '@nestjs/common';
import { ConfigService } from './config.service';
export interface ConfigModuleOptions {
folder?: string;
envFilePath?: string;
}
@Module({})
export class ConfigModule {
static forRoot(options: ConfigModuleOptions = {}): DynamicModule {
const configService = new ConfigService(options);
return {
module: ConfigModule,
providers: [
{
provide: ConfigService,
useValue: configService,
},
],
exports: [ConfigService],
global: true, // 可选:设为全局
};
}
static forFeature(entities: Function[]): DynamicModule {
return {
module: ConfigModule,
providers: [
// 根据传入的实体动态创建提供者
...entities.map(entity => ({
provide: `${entity.name}Repository`,
useValue: createRepository(entity),
})),
],
exports: entities.map(entity => `${entity.name}Repository`),
};
}
}
高级动态模块
typescript
// cache/cache.module.ts
import { Module, DynamicModule, Provider } from '@nestjs/common';
import { RedisModule } from 'nestjs-redis';
import { CacheService } from './cache.service';
import { MemoryCacheService } from './memory-cache.service';
import { RedisCacheService } from './redis-cache.service';
export interface CacheModuleOptions {
type: 'memory' | 'redis';
ttl?: number;
redisUrl?: string;
}
@Module({})
export class CacheModule {
static register(options: CacheModuleOptions): DynamicModule {
let provider: Provider;
if (options.type === 'redis') {
provider = {
provide: CacheService,
useClass: RedisCacheService,
};
} else {
provider = {
provide: CacheService,
useClass: MemoryCacheService,
};
}
const dynamicImports = options.type === 'redis'
? [RedisModule.register({ url: options.redisUrl })]
: [];
return {
module: CacheModule,
imports: dynamicImports,
providers: [
provider,
{
provide: 'CACHE_OPTIONS',
useValue: options,
},
],
exports: [CacheService],
};
}
static registerAsync(options: {
useFactory: (...args: any[]) => CacheModuleOptions;
inject?: any[];
}): DynamicModule {
return {
module: CacheModule,
providers: [
{
provide: CacheService,
useFactory: (opts: CacheModuleOptions) => {
if (opts.type === 'redis') {
return new RedisCacheService();
}
return new MemoryCacheService();
},
inject: ['ASYNC_CACHE_OPTIONS'],
},
{
provide: 'ASYNC_CACHE_OPTIONS',
useFactory: options.useFactory,
inject: options.inject || [],
},
],
exports: [CacheService],
};
}
}
模块依赖关系
模块间的依赖
typescript
// auth/auth.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UsersModule } from '../users/users.module';
import { PassportModule } from '@nestjs/passport';
@Module({
imports: [
// 依赖用户模块
UsersModule,
// Passport认证模块
PassportModule,
// JWT模块配置
JwtModule.register({
secret: process.env.JWT_SECRET,
signOptions: { expiresIn: '60m' },
}),
],
providers: [AuthService],
controllers: [AuthController],
exports: [AuthService], // 导出服务供其他模块使用
})
export class AuthModule {}
循环依赖处理
typescript
// users/users.module.ts
import { Module, forwardRef } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { OrdersModule } from '../orders/orders.module';
@Module({
imports: [
// 使用forwardRef处理循环依赖
forwardRef(() => OrdersModule),
],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
// orders/orders.module.ts
import { Module, forwardRef } from '@nestjs/common';
import { OrdersController } from './orders.controller';
import { OrdersService } from './orders.service';
import { UsersModule } from '../users/users.module';
@Module({
imports: [
// 循环依赖的另一方
forwardRef(() => UsersModule),
],
controllers: [OrdersController],
providers: [OrdersService],
})
export class OrdersModule {}
模块层次结构
应用程序模块结构
AppModule
├── UsersModule
│ ├── UserEntities
│ └── UserServices
├── PostsModule
│ ├── PostEntities
│ └── PostServices
├── AuthModule
│ ├── Strategies
│ └── Guards
└── DatabaseModule
├── Connection
└── Repositories
模块分组
typescript
// modules/core.module.ts
import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { ConfigModule } from './config/config.module';
import { LoggerModule } from './logger/logger.module';
@Module({
imports: [
DatabaseModule,
ConfigModule,
LoggerModule,
],
})
export class CoreModule {}
// modules/features.module.ts
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
import { PostsModule } from './posts/posts.module';
import { CommentsModule } from './comments/comments.module';
@Module({
imports: [
UsersModule,
PostsModule,
CommentsModule,
],
})
export class FeaturesModule {}
// app.module.ts
import { Module } from '@nestjs/common';
import { CoreModule } from './modules/core.module';
import { FeaturesModule } from './modules/features.module';
@Module({
imports: [
CoreModule,
FeaturesModule,
],
})
export class AppModule {}
模块配置
模块配置对象
typescript
// interfaces/module-options.interface.ts
export interface CommonModuleOptions {
logger?: boolean;
cache?: boolean;
cors?: {
origin?: string | string[];
credentials?: boolean;
};
}
// common/common.module.ts
import { Module, DynamicModule } from '@nestjs/common';
import { CommonModuleOptions } from './interfaces/module-options.interface';
import { CommonService } from './common.service';
@Module({})
export class CommonModule {
static forRoot(options: CommonModuleOptions = {}): DynamicModule {
const providers = [];
// 根据配置动态添加提供者
if (options.logger) {
providers.push({
provide: 'LOGGER_PROVIDER',
useClass: LoggerProvider,
});
}
if (options.cache) {
providers.push({
provide: 'CACHE_PROVIDER',
useClass: CacheProvider,
});
}
return {
module: CommonModule,
providers: [
CommonService,
...providers,
],
exports: [
CommonService,
...providers.map(p => p.provide),
],
};
}
}
模块注册模式
typescript
// services/services.module.ts
import { Module, DynamicModule } from '@nestjs/common';
import { EmailService } from './email/email.service';
import { SmsService } from './sms/sms.service';
import { PushService } from './push/push.service';
interface ServiceModuleOptions {
services: ('email' | 'sms' | 'push')[];
}
@Module({})
export class ServicesModule {
static register(options: ServiceModuleOptions): DynamicModule {
const providers = [];
if (options.services.includes('email')) {
providers.push(EmailService);
}
if (options.services.includes('sms')) {
providers.push(SmsService);
}
if (options.services.includes('push')) {
providers.push(PushService);
}
return {
module: ServicesModule,
providers: providers,
exports: providers,
};
}
}
// 使用方式
@Module({
imports: [
ServicesModule.register({
services: ['email', 'sms'],
}),
],
})
export class AppModule {}
模块生命周期
模块初始化
typescript
// lifecycle/lifecycle.module.ts
import {
Module,
OnModuleInit,
OnModuleDestroy,
OnApplicationBootstrap
} from '@nestjs/common';
@Module({
providers: [LifecycleService],
})
export class LifecycleModule implements OnModuleInit, OnModuleDestroy, OnApplicationBootstrap {
async onModuleInit() {
console.log('LifecycleModule initialized');
}
async onApplicationBootstrap() {
console.log('Application bootstrap complete');
}
async onModuleDestroy() {
console.log('LifecycleModule destroyed');
}
}
模块最佳实践
1. 模块职责单一
typescript
// 好的模块设计 - 职责单一
@Module({
controllers: [UserController],
providers: [UserService, UserValidator],
exports: [UserService],
})
export class UserModule {}
// 避免模块过于庞大
@Module({
controllers: [
// 太多控制器
UserController, PostController, CommentController, ...
],
providers: [
// 太多提供者
UserService, PostService, CommentService, ...
],
})
export class MassiveModule {} // 避免这样设计
2. 合理的模块划分
typescript
// 按功能划分模块
export class UserManagementModule {} // 用户管理
export class ContentManagementModule {} // 内容管理
export class NotificationModule {} // 通知系统
export class AnalyticsModule {} // 分析系统
3. 明确的依赖关系
typescript
// 明确定义模块依赖
@Module({
imports: [
DatabaseModule,
CommonModule,
AuthModule,
],
// ...
})
export class FeatureModule {}
4. 慎用全局模块
typescript
// 谨慎使用@Global()装饰器
@Global() // 只有在确实需要全局访问时才使用
@Module({
providers: [GlobalService],
exports: [GlobalService],
})
export class GlobalModule {}
通过合理的模块设计,可以构建出结构清晰、易于维护和扩展的NestJS应用程序。