是否可以通过自定义参数在NestJs中使用Factory DynamicModules?

时间:2019-04-09 17:41:17

标签: typescript nestjs

我有一个共享库,它将为其他应用程序提供模块。因此,我需要动态的自定义参数来为应用程序内的每个模块生成自定义实例。

我已经在官方回购中为此打开了一个问题 nestjs/issues/1965,但也许有人可以给我一些想法或帮助我解决这个问题。

我已经查看了nestjs文档,还阅读了代码和问题,但是我找不到从实例化过程中动态获取参数以生成所需内容的自定义实例的方法。

所以基本上我需要提供一个可以进入实例化过程的字符串,以便返回的实例将使用该字符串来限定模块的配置范围。因此,我目前正在做的事情是侵入Nest的实例以将范围注入其中,我认为这不是最好的选择。

这是我为该问题编写的代码示例:

库代码

// decorator
export function Configurable(scope: string) {
  return (target: object, key: string | symbol, index?: number) => {
    const meta = Reflect.getMetadata(CONFIGURABLE_METADATA, target) || {};
    let dependencies = meta.dependencies || [];

    dependencies = [...dependencies, { scope, key }];

    Reflect.defineMetadata(
      CONFIGURABLE_METADATA,
      { dependencies },
      target,
    );

    Inject(CONFIGURATION_PROVIDER_TOKEN)(target, key, index);
  };
}
// explorer service
@Injectable()
export class ExplorerService {
  constructor(private readonly modulesContainer: ModulesContainer) {}

  injectScopes(): void {
    const providers = [...this.modulesContainer.values()]
      .map((module: NestModule) => {
        return [...module.providers.values()];
      }).reduce((a, b) => a.concat(b), []);

    providers.forEach(provider => {
      const { instance } = provider;

      if (!instance && !instance.constructor) {
        return;
      }

      // custom metadata
      const meta = Reflect.getMetadata(CONFIGURABLE_METADATA, instance.constructor);

      if (meta) {
        meta.dependencies.forEach(dep => {
          const { index, scope } = dep;
          const wrapper = provider[INSTANCE_METADATA_SYMBOL].dependencies[index];
          const { instance: depInstance } = wrapper;
          Object.defineProperty(depInstance, 'scope', { value: scope });
        });
      }
    });
  }
}

应用程序代码(使用库)

// usage in the application
@Module({
  imports: [ConfigurationModule.forRoot(factoryOptions)],
  providers: [UserConfigProvider],
  exports: [ConfigurationModule]
})
export class AppModule {}
// user config provider
@Injectable()
export class AssessmentConfiguration {
  constructor(
    @Configurable('common')
    private readonly commonConfig: ConfigurationService,
    @Configurable('users')
    private readonly usersConfig: ConfigurationService,
  ) {}
}

感谢我能提供的任何帮助或由此引起的讨论。如果缺少某些内容,我可以提供更多信息或上下文。

0 个答案:

没有答案