NestJS 中共享动态模块 - 动态模块注册几次会发生什么?

问题描述 投票:0回答:2

我需要共享一个动态模块。在文档中我发现我们可以在全球范围内共享服务。 是的,这是一个解决方案。但是,我想知道在模块级别是否可能。这就是为什么我对当动态模块注册几次时会发生什么感兴趣。从实践中,我发现它在 NestJS 中创建了不同的模块实例。 该模块的行为与 Angular 中的不同,但 NestJS 喜欢提及 Angular 的相似性。 属性模块带我走了。现在我明白它仅用于控制模块行为。但是,我没有看到任何 文档中的解释。我看到类似的问题。但我还没有找到我感兴趣的细节。

以下代码只是想法。还没有检查过。

import { DynamicModule, Module } from '@nestjs/common';
import { ConfigService } from './config.service';

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

export const ConfiguredConfigModule = ConfigModule.register({key: 'flower'});
... 

@Module({
  imports: [ConfiguredConfigModule]
})
export class AppModule {}

问候。

nestjs
2个回答
1
投票

NestJS 喜欢提及 Angular 相似性。

相似,而不是等同。它们“相似”而不是“相同”。行为上的差异是预料之中的 从实践中,我发现它在 NestJS 中创建了不同的模块实例。

这是正确的。根据

convention

,当我们希望制作一次东西并从根模块中重复使用它时,我们使用像
forRoot

这样的名称,当我们希望必须多次注册模块时,我们使用register这样的名称,但这是onyl社区约定,根本不是一个硬性规则。当您调用

DynamicModule.forRoot/register/Async()
时,您将
在当前模块的上下文中创建一个动态模块
如果您想共享动态模块,我建议围绕动态模块创建一个包装器,这样您就可以对 
.forRoot()/register()/whaterver() 进行包装器调用,并按名称导出动态模块(添加 exports: [DynamicModule]

)。这将允许您导入包装器并拥有一个 DynamicModule 实例,而无需将其设为全局实例


我在为我的项目创建核心库时遇到了同样的问题。
我还想知道为什么没有信息和方法来共享模块而不使其@Global。

在尝试了包装器、全局变量、nestjs 核心反射之后,我找到了使用装饰器的解决方案,该装饰器将动态模块转换为静态模块,不会创建额外的实例并且易于使用。

0
投票
import { ModuleMetadata, Module, DynamicModule } from '@nestjs/common'; export function SharedModule(metadata: ModuleMetadata): ClassDecorator { return <T extends Function>(target: T) => { let isInitialized = false; Module(metadata)(target); const getModule = (mdl: DynamicModule) => { if (isInitialized) { return target; } Module( mdl ? { providers: mdl.providers, exports: mdl.exports, imports: mdl.imports, controllers: mdl.controllers, } : metadata, )(target); isInitialized = true; }; const staticMethods = Object.getOwnPropertyNames(target).filter( (prop) => typeof target[prop] === 'function', ); for (const method of staticMethods) { const originalMethod = target[method]; target[method] = function (...args: any[]) { return getModule(originalMethod(...args)); }; } return target; }; }

Decorator 完全取代了 @Module(...) 并且到目前为止效果良好。 所有模块导入为 [Module.forRoot()] 或 [Module] 将返回相同的模块实例。

export type StorageModuleOptions = { clientProvider: Provider<ExtendedCacheClient>; }; @SharedModule({}) export class StorageModule { static forRoot(args: StorageModuleOptions): DynamicModule { const { providers, exports } = buildCustomProvider(args.clientProvider, DICacheClient); return { module: StorageModule, providers: [...providers], exports: [...exports], }; } }
    

© www.soinside.com 2019 - 2024. All rights reserved.