NestJS之06- Module 模块

717 阅读4分钟

1. 什么是Module

每个 Nest 应用程序至少有一个模块,即根模块。根模块是 Nest 开始安排应用程序树的地方。事实上,根模块可能是应用程序中唯一的模块,特别是当应用程序很小时,但是对于大型程序来说这是没有意义的。在大多数情况下,您将拥有多个模块,每个模块都有一组紧密相关的功能

// 如果你需要把这个模块 暴露到全局使用可以加 一个装饰器 @Global
// 使一切全局化并不是一个好的解决方案。 全局模块可用于减少必要模板文件的数量。 `imports` 数组仍然是使模块 API 透明的最佳方式。

@Global()
@Module({ 
    imports:[], // 可以注入 其他module 或者provider
    exports:[], // 如果你这个模块中的provider 要在别的模块中使用 你必须要在这里声明 导出这鞋provider ,当然 你也可以把 这个module导出其他地方import 一下这样其他模块中的provider 也是可以使用的
    providers:[]  // 由 Nest 注入器实例化的提供者,并且可以至少在整个模块中共享
})

2. 如何使用

1. 共享模块

user.module.ts 导出

@Module({
  controllers: [UserController],
  providers: [UserService],
  exports: [UserService],
})
export class UserModule {}

app.module.ts 导入 导入module

import { UserModule } from './user/user.module';
import { OrderModule } from './order/order.module';

@Module({
  imports: [UserModule, OrderModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

app.controller.ts 使用

import { UserService } from './user/user.service';

@Controller()
export class AppController {
  constructor(
    private readonly appService: AppService,
    private readonly userService: UserService,
  ) {}

  @Get('user')
  getUser(): string {
    return this.userService.findAll();
  }
}

2. 全局模块

@Global()进行module修饰

user.module.ts 必须进行导出

import { Global, Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';

@Global()
@Module({
  controllers: [UserController],
  providers: [UserService],
  exports: [UserService], // 必须进行导出
})
export class UserModule {}

在order 模块使用无须在module  imports导入

order.controller.ts

import { UserService } from '../user/user.service';

@Controller('order')
export class OrderController {
  constructor(
    private readonly orderService: OrderService,
    private readonly userService: UserService,
  ) {}

  @Get('user')
  getUser() {
    return this.userService.findAll();
  }
}

3. 动态导入

在 Nest.js 中,动态导入(Dynamic Module)是指能够在运行时动态加载和注入模块的功能。相比于静态导入,动态导入提供更大的灵活性,因为我们可以在运行时决定使用哪些模块或配置,而不需要在编译时确定。

通常情况下,我们会将服务和组件包含在 Nest.js 的模块中,并将它们使用 @Module 装饰器注册为一个静态模块。但是,在某些场景下,我们可能需要将服务和组件按需导入,或按照特定条件进行组合。这时就可以使用动态导入。

动态导入允许我们以 programmatic 的方式创建和组成 Nest.js 的模块,并通过调用 forRootforFeature 方法来注册服务和组件。forRoot 方法允许我们在导入模块并使用特定配置对象时创建模块,而 forFeature 允许我们在模块之间共享模块的特定部分。

动态导入模块的几个特点和优点:

  1. 动态导入允许我们在运行时动态加载和注册模块,从而允许更灵活的应用程序设计和建模。
  2. 动态导入模块提供了一种方便的方式,在不同的模块之间共享服务和组件。
  3. 动态导入允许我们根据特定的条件实现按需导入和使用模块。
  4. 动态加载模块允许我们创建可扩展、可维护和可重用的应用程序,从而提高了应用程序的复用性和可测试性。

案例

config.module.ts 导出

import { Module, Global, DynamicModule } from '@nestjs/common';
export interface Options {
  path: string;
}

@Global()
@Module({})
export class ConfigModule {
  static forRoot(options: Options): DynamicModule {
    return {
      module: ConfigModule,
      providers: [
        {
          provide: 'Config',
          useValue: { baseApi: '/api' + options.path },
        },
      ],
      exports: [
        {
          provide: 'Config',
          useValue: { baseApi: '/api' + options.path },
        },
      ],
    };
  }
}

=================== 原写法 ================
 @Module({
   controllers: [ConfigController],
   providers: [ConfigService]
 })
 export class ConfigModule {}

app.module.ts 导入

import { ConfigModule } from './config/config.module';

@Module({
  imports: [ConfigModule.forRoot({ path: '/666' })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

app.controller.ts 使用 Inject对应先前定义的provide

import { Controller, Get, Inject } from '@nestjs/common';

@Controller()
export class AppController {
  constructor(
    @Inject('Config') private readonly value: object,
  ) {}

  @Get()
  getHello(): object {
    return this.value;
  }
}

image.png

总结

  • 定义自己的controllers

  • 定义自己的service

  • 把自己的service放在providers中,这样controllers才能用service

  • 如果需要用外部的service,将外部module放在imports里

  • 如果自己的service也需要被其他module使用,将自己的service放到exports里