Skip to content
On this page

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应用程序。