在 NestJs 中配置依赖 DynamicModules 的最佳方法
Posted
技术标签:
【中文标题】在 NestJs 中配置依赖 DynamicModules 的最佳方法【英文标题】:Best way to configure dependent DynamicModules in NestJs 【发布时间】:2021-06-26 10:31:54 【问题描述】:我一直在努力寻找处理导入在同一范围内具有相互依赖关系的 Nest 模块的最佳方法。
我的具体用例是一个大型 monorepo,其中包含多个微服务应用程序,这些应用程序需要一组通用组件(例如数据库、传输等)的特定配置/设置。我的目的是提供一个“汇总”模块来标准化配置过程。
问题在于模块导入数组中的模块似乎完全相互隔离。虽然我可以使用@Global
,但它违背了模块级隔离的目的,坦率地说有点@Dirty
。
我尝试过的简化版本:
@Module()
export class ChaptersModule
static registerAsync(config: IChaptersAsyncConfig): DynamicModule
const provider =
provide: CHAPTERS,
useFactory: config.useFactory,
inject: config.inject || [],
;
return
module: ChaptersModule,
imports: [CharactersModule], // <-- another DynamicModule
providers: [provider, ChaptersService],
exports: [ChaptersService],
;
将该模块及其依赖项导入另一个模块时:
@Module(
imports: [
CharactersModule.forRootAsync(
useFactory: () => characterData,
),
ChaptersModule.registerAsync(
useFactory: () => chapterData,
),
],
controllers: [AppController],
providers: [AppService],
)
export class AppModule
Nest 实例化 CharactersModule 两次(一次用于***导入,一次用于 ChaptersModule 导入),即使 它们共享相同的消费模块范围。因为模块需要配置,Nest 实例化时没有它的配置提供程序,我得到了我最好的新朋友:
Error: Nest can't resolve dependencies of the ChaptersService (CHAPTERS, ?). Please make sure that the argument CharactersService at index [1] is available in the ChaptersModule context.
在这件事上花费的时间比我愿意公开分享的要多,我能找到的唯一解决方法是实例化 CharactersModule 并然后通过 requires?: any[]
属性将其传递给依赖模块添加到我的界面。
// Pre-Configure any dependent modules
export const configured = [
CharactersModule.forRoot(characterData)
]
@Module(
imports: [
...configured, // include configured modules in module imports
ChaptersModule.registerAsync(
requires: configured, // pass configured modules
useFactory: () => chapterData
)
],
controllers: [AppController],
providers: [AppService],
)
export class AppModule
这感觉很hacky并且似乎有效,但我肯定错过了什么吗?示例 repo 是 here(我预计它的工作方式是在 broken
分支中。
处理场景的正确方法是什么?
【问题讨论】:
【参考方案1】:I've got a Git repo that walks through the steps of how this is achievable with some clever RxJS,但我也会在这里给出一个高层次的概述。
所以我们的想法是你最终会为你的模块类添加几个 RxJS 操作符和属性;即一个Deferred
静态变量、一个私有静态timeout
变量和一个Subject
变量来保存模块配置。然后,在forRoot()
或forRootAsync()
内部,在返回配置之前,您最终会调用this.moduleConfig.next(configuration)
。现在,您需要在应用程序中的任何其他位置调用 Module.Deferred
并获取 RxJS 延迟配置。这个Deferred
是race
介于timeout
和subject.pipe(take(1))
之间,这将允许您获得错误(从未调用过配置)或稍后获得配置。
@golevelup/nestjs-modules
有一个称为externallyConfigured()
的方法,它几乎可以为您处理上述问题。我强烈建议给我链接的 repo 阅读以了解模式,然后对我链接的包进行一次尝试,看看它需要多少照顾。
【讨论】:
谢谢杰。共享配置以外的资源的捆绑包(例如数据库模块)呢?我是否正确理解一个模块只会与直接后代共享 DI 范围,除非它是全局的? 我不确定我是否遵循了这个问题。 很公平 :) 我检查了你的 repo 和 golevelup 的,乍一看,它们似乎更适合共享配置。会挖得更深一些。感谢您的帮助!以上是关于在 NestJs 中配置依赖 DynamicModules 的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章
Nestjs 应用程序中`@ntegral/nestjs-sentry` 包的依赖注入问题