NestJS:动态模块中的嵌套异步初始化

Arn*_*aud 5 typescript nestjs

在我的主模块 (A) 中,我导入外部模块 (B) 及其配置:

imports: [
NestAuthModule.registerAsync({
  inject: [authConfig.KEY],
  useFactory: async (config: ConfigType<typeof authConfig>) => ({
    google: config.google,
    jwt: config.jwt,
  }),
})
]
Run Code Online (Sandbox Code Playgroud)
export class NestAuthModule {
  static registerAsync(options: AuthModuleAsyncOptions): DynamicModule {
    return this.createModule(
      this.createAsyncProviders(options),
      options.imports || []
    );
  }

  private static createModule(
    providers: Provider[],
    imports: Array<
      Type<any> | DynamicModule | Promise<DynamicModule> | ForwardReference
    >
  ) {
    return {
      module: NestAuthModule,
      controllers: [AuthController],
      providers: [
        ...providers
      ],
      imports: [
        ...imports,
        JwtModule.registerAsync({
          inject: [AuthModuleOptions],
          useFactory: async (options: AuthModuleOptions) => {
            return {
              secret: options.jwt.secretKey,
              signOptions: {
                expiresIn: options.jwt.expires,
              },
            };
          },
        }),
      ],
      exports: [AuthModuleOptions],
    };
  }

  private static createAsyncProviders(
    options: AuthModuleAsyncOptions
  ): Provider[] {
    if (options.useExisting || options.useFactory) {
      return [this.createAsyncOptionsProvider(options)];
    } else if (options.useClass) {
      return [
        this.createAsyncOptionsProvider(options),
        {
          provide: options.useClass,
          useClass: options.useClass,
        },
      ];
    }
    throw new Error('missing provider config');
  }

  private static createAsyncOptionsProvider(
    options: AuthModuleAsyncOptions
  ): Provider {
    const useFactory =
      options.useFactory ??
      (async (optionsFactory: AuthOptionsFactory) =>
        await optionsFactory.createAuthOptions());
    const inject = options.useFactory
      ? options.inject || []
      : [options.useExisting || options.useClass];
    return {
      provide: AuthModuleOptions,
      useFactory,
      inject,
    };
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,在模块 B 中,我正在使用工厂导入第三方模块,并且它需要模块 B 配置。但是,它尚不可用,因为它是异步的。它将在模块最终实例化时提供。但是,我已经在我的导入中注入了这个提供程序。所以,我收到注入错误:

[ExceptionHandler] Nest can't resolve dependencies of the JWT_MODULE_OPTIONS (?). Please make sure that the argument AuthModuleOptions at index [0] is available in the JwtModule context.
Potential solutions:
- If AuthModuleOptions is a provider, is it part of the current JwtModule?
Run Code Online (Sandbox Code Playgroud)

我很确定有解决方案,但我还没有找到。

ran*_*m42 2

我刚刚偶然发现了你同样的问题并找到了解决方案。您必须向子模块提供选项提供程序(在本例中为 JwtModule):

export const importAsyncModule = (
  parentModule: DynamicModule,
  subModule: DynamicModule,
  optionsToken: InjectionToken,
) => {
  const provider = parentModule.providers?.find(
    (x) => (x as any)?.provide === optionsToken,
  );
  if (!provider)
    throw new Error(`Provider for ${optionsToken.toString()} not found`);
  subModule.providers = subModule.providers ?? [];
  subModule.providers.unshift(provider);
  parentModule.imports = parentModule.imports ?? [];
  parentModule.imports.push(subModule);
  return subModule;
};
Run Code Online (Sandbox Code Playgroud)

如果m是你的父模块,你会这样做:

const jwtModule = JwtModule.registerAsync({
  useFactory: (opt: AuthenticationModuleOptions) => opt.jwt,
  inject: [MODULE_OPTIONS_TOKEN],
});
importAsyncModule(m, jwtModule, MODULE_OPTIONS_TOKEN);
Run Code Online (Sandbox Code Playgroud)