第十一章 Nest 创建动态模块

在 NestJS 中,动态模块允许在运行时动态添加和删除模块。这对于创建可扩展的和灵活的应用程序非常有用。

新建一个项目:

nest new dynamic-module -p npm

1717907361646.png
创建一个crud的模块:

nest g resource test

1717907490721.png
启动项目 浏览器访问 可以发现模块生效了

pnpm run start:dev

1717907603268.png
1717907581969.png
但是这个模块目前是静态的 内容固定不变 当我们想在mport 的时候给这个模块传一些参数,动态生成模块的内容 就可以使用 Dynamic Module动态模块
修改 test.module.ts: 给 TestModule 加一个 register 的静态方法,返回模块定义的对象

import { DynamicModule, Module } from '@nestjs/common';
import { TestService } from './test.service';
import { TestController } from './test.controller';

@Module({
})
export class TestModule {
  static register(options: Record<string, any>): DynamicModule {
    return {
      module: TestModule,
      providers: [
        {
          provide: 'TEST_OPTIONS',
          useValue: options
        },
        TestService
      ],
      exports: [TestService]
    }
  }
}

接着在 app.module.ts 使用

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TestModule } from './test/test.module';

@Module({
  imports: [TestModule.register({ test: '666' })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule { }

最后在 test.controller.ts打印

constructor(private readonly testService: TestService,
    @Inject('TEST_OPTIONS') private configOptions: Record<string, any>) { }
@Get()
  findAll() {
    console.log(this.configOptions);

    return this.testService.findAll();
  }

1717912063418.png
启动项目

pnpm run start:dev

访问 http://localhost:3000/test 可以看到控制台打印了 config 对象信息
1717912420117.png
这样我们就可以在 import 一个模块的时候,传入参数,然后动态生成模块的内容。

nest 约定了 3 种方法名:
foregister 是用于在整个应用程序中注册全局提供者的方法。当我们在应用程序的任何地方都需要访问该提供者时,可以使用 register 来注册。
forRoot 是用于在根模块中注册模块的方法。它将模块中的提供者和导出的模块注册为全局可访问的,这意味着其他模块可以直接使用这些提供者和导出的模块。
forFeature 是用于在特定模块中注册模块的方法。它将模块中的提供者和导出的模块注册为仅在该模块中可访问的。这通常用于在模块内部使用的服务和功能。
并且这些方法都可以写 xxxAsync 版本,也就是传入 useFactory 等 option,内部注册异步 provider。

Nest 还提供了另一种方式来创建动态模块
我们在生成一个新的模块:

nest g module aaa

创建一个controller:

nest g controller aaa --no-spec

新建一个 aaa.module-definition.ts 文件:

import { ConfigurableModuleBuilder } from "@nestjs/common";

/**
 * 定义了AaaModule的配置选项接口。
 * 
 * 该接口包括了aaa和bbb两个属性,分别对应不同的配置需求。
 */
export interface AaaModuleOptions {
    aaa: string;
    bbb: number;
}

/**
 * 使用ConfigurableModuleBuilder构建AaaModule的配置类和选项令牌。
 * 
 * 通过这种方式,可以动态配置模块的选项,并提供了一个令牌用于依赖注入,以便在模块中访问这些配置选项。
 */
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
    new ConfigurableModuleBuilder<AaaModuleOptions>().build()

这段代码是使用NestJS框架定义了一个可配置的模块AaaModule。

  • AaaModuleOptions接口定义了模块的配置选项,包括aaa属性(类型为字符串)和bbb属性(类型为数字)。
  • ConfigurableModuleBuilder是一个NestJS提供的类,用于构建可配置模块。通过调用其build()方法,可以生成一个配置类和一个选项令牌。
  • ConfigurableModuleClass是生成的配置类,可以用于动态配置模块的选项。
  • MODULE_OPTIONS_TOKEN是生成的选项令牌,可以用于依赖注入,在模块中访问配置选项。

然后我们在AaaModule 里继承它

import { Module } from '@nestjs/common';
import { AaaController } from './aaa.controller';
import { ConfigurableModuleClass } from './aaa.module-definition';

@Module({
  controllers: [AaaController]
})
export class AaaModule extends ConfigurableModuleClass {}

这样这个 CccModule 就已经有了 register 和 registerAsync 方法
app.module.ts:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TestModule } from './test/test.module';
import { AaaModule } from './aaa/aaa.module';

@Module({
  imports: [TestModule.register({ test: '666' }),
  AaaModule.register({
    aaa: 'aaa',
    bbb: 1
  }),
  // AaaModule.registerAsync({
  //   useFactory: () => ({
  //     aaa: 'aaa',
  //     bbb: 1
  //   })
  // })
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule { }

接着我们在 Controller 注入 aaa.controller.ts

import { Controller, Get, Inject } from '@nestjs/common';
import { AaaModuleOptions, MODULE_OPTIONS_TOKEN } from './aaa.module-definition';

@Controller('aaa')
export class AaaController {

    @Inject(MODULE_OPTIONS_TOKEN)
    private options: AaaModuleOptions;

    @Get('')
    hello() {
        return this.options;
    }
}

启动项目

pnpm run start:dev

1717914850954.png
1717914955633.png
可以看到拿到了options 对象 我们可以用来做配置
如果要用 forRoot、forFeature 可以调用 setClassMethodName 函数来设置一下

import { ConfigurableModuleBuilder } from "@nestjs/common";

/**
 * 定义了AaaModule的配置选项接口。
 * 
 * 该接口包括了aaa和bbb两个属性,分别对应不同的配置需求。
 */
export interface AaaModuleOptions {
    aaa: string;
    bbb: number;
}

/**
 * 使用ConfigurableModuleBuilder构建AaaModule的配置类和选项令牌。
 * 
 * 通过这种方式,可以动态配置模块的选项,并提供了一个令牌用于依赖注入,以便在模块中访问这些配置选项。
 */
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
    new ConfigurableModuleBuilder<AaaModuleOptions>().setClassMethodName('forRoot').build()
import { ConfigurableModuleBuilder } from "@nestjs/common";

/**
 * 定义了AaaModule的配置选项接口。
 * 
 * 该接口包括了aaa和bbb两个属性,分别对应不同的配置需求。
 */
export interface AaaModuleOptions {
    aaa: string;
    bbb: number;
}

/**
 * 使用ConfigurableModuleBuilder构建AaaModule的配置类和选项令牌。
 * 
 * 通过这种方式,可以动态配置模块的选项,并提供了一个令牌用于依赖注入,以便在模块中访问这些配置选项。
 */
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
    new ConfigurableModuleBuilder<AaaModuleOptions>().setClassMethodName('forFeature').build()

我们还可以设置为全局模块:
setExtras 第一个参数是给 options 扩展啥 extras 属性,第二个参数是收到 extras 属性之后如何修改模块定义

import { ConfigurableModuleBuilder } from "@nestjs/common";

/**
 * 定义了AaaModule的配置选项接口。
 * 
 * 该接口包括了aaa和bbb两个属性,分别对应不同的配置需求。
 */
export interface AaaModuleOptions {
    aaa: string;
    bbb: number;
}

/**
 * 使用ConfigurableModuleBuilder构建AaaModule的配置类和选项令牌。
 * 
 * 通过这种方式,可以动态配置模块的选项,并提供了一个令牌用于依赖注入,以便在模块中访问这些配置选项。
 */
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
    new ConfigurableModuleBuilder<AaaModuleOptions>()
        .setClassMethodName('register')
        .setExtras({
            isGlobal: true
        }, (definition, extras) => ({
            ...definition,
            global: extras.isGlobal,
        }))
        .build()

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫ゞ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值