如何在NestJS中共享动态模块?自定义模块遇实例重复问题
NestJS 动态模块配置疑问:EmailModule为何无法像ConfigModule那样全局复用?
问题场景
我写了一个动态模块EmailModule:
@Injectable() export class EmailSender {} @Module({}) export class EmailModule { static forRoot(options: { smtpHost: string; smtpPassword: string }): DynamicModule { return { module: EmailModule, providers: [EmailSender,], exports: [EmailSender,], }; } }
同时有包含CatModule的MainModule:
@Injectable() export class CatService { constructor(emailSender: EmailSender) {} } @Module({ imports: [ EmailModule, ], providers: [CatService,], exports: [CatService,], }) export class CatModule {} @Module({ imports: [ EmailModule.forRoot({ smtpHost: 'localhost', smtpPassword: 'password', }), CatModule, ], }) export class MainModule {}
这段代码跑不起来,CatService无法解析EmailSender。我必须在CatModule里导入EmailModule.forRoot({host, password})才能用,但我不想这么做——毕竟还有DogModule、HorseModule等一堆子模块,总不能每个都重复写.forRoot({...})。我希望只在主模块调用一次.forRoot({...})完成配置,所有子模块直接导入EmailModule就能用。
我确定这是可行的,因为NestJS自带的ConfigModule就是这么玩的,换成它之后一切正常:
@Injectable() export class CatService { constructor(configService: ConfigService) {} } @Module({ imports: [ ConfigModule, ], providers: [CatService,], exports: [CatService,], }) export class CatModule {} @Module({ imports: [ ConfigModule.forRoot({ envFilePath: '../.env', }), CatModule, ], }) export class MainModule {}
搞不懂为什么ConfigModule能正常工作,我的EmailModule却不行?它到底有什么特殊之处?
更新:尝试解决方案但无效
我按照方案改了代码,但还是不行:
import {type DynamicModule, Inject, Injectable, Module,} from '@nestjs/common'; import {NestFactory,} from '@nestjs/core'; interface EmailModuleOptions { smtpHost: string; smtpPassword: string; } const EMAIL_MODULE_OPTIONS = 'EMAIL_MODULE_OPTIONS'; @Injectable() export class EmailSender { constructor( @Inject(EMAIL_MODULE_OPTIONS) private readonly config: EmailModuleOptions) { console.log('EmailSender constructor, ', config); } sendEmail(): void { console.log({ message: 'Meow', host: this.config.smtpHost, password: this.config.smtpPassword, }); } } @Module({ }) export class EmailModule { private static emailOptions = {}; static forRoot(options: EmailModuleOptions): DynamicModule { this.emailOptions = options; return EmailModule.forFeature(); } static forFeature(): DynamicModule { return { module: EmailModule, providers: [ EmailSender, { provide: EMAIL_MODULE_OPTIONS, useValue: EmailModule.emailOptions, }, ], exports: [EmailSender,], }; } } @Injectable() export class CatService { constructor(private readonly emailSender: EmailSender) {} sayHello(): void { this.emailSender.sendEmail(); } } @Module({ imports: [ EmailModule.forFeature(), ], providers: [CatService,], exports: [CatService,], }) export class CatModule {} @Module({ imports: [ EmailModule.forRoot({ smtpHost: 'localhost', smtpPassword: 'password', }), CatModule, ], }) export class MainModule {} const main = async (): Promise<void> => { const app = await NestFactory.createApplicationContext(MainModule); const catService = app.get(CatService); catService.sayHello(); }; main();
控制台输出如下:
[Nest] 30872 - 04/06/2023, 2:46:37 PM LOG [NestFactory] Starting Nest application... EmailSender constructor, { smtpHost: 'localhost', smtpPassword: 'password' } EmailSender constructor, {} [Nest] 30872 - 04/06/2023, 2:46:37 PM LOG [InstanceLoader] MainModule dependencies initialized +29ms [Nest] 30872 - 04/06/2023, 2:46:37 PM LOG [InstanceLoader] EmailModule dependencies initialized +1ms [Nest] 30872 - 04/06/2023, 2:46:37 PM LOG [InstanceLoader] EmailModule dependencies initialized +0ms [Nest] 30872 - 04/06/2023, 2:46:37 PM LOG [InstanceLoader] CatModule dependencies initialized +0ms { message: 'Meow', host: undefined, password: undefined }
明显NestJS创建了两个EmailSender实例,而CatService用的是那个没有配置的空实例。
内容的提问来源于stack exchange,提问作者Farad
相关产品推荐
相关产品推荐

