NestJS:在动态模块中嵌套async init



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

imports: [
NestAuthModule.registerAsync({
inject: [authConfig.KEY],
useFactory: async (config: ConfigType<typeof authConfig>) => ({
google: config.google,
jwt: config.jwt,
}),
})
]
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,
};
}
}

请注意,在模块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?

我很肯定有一个解决办法,但是我还没有找到。

我只是偶然发现了你同样的问题,并找到了一个解决方案。您必须向子模块(在本例中为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;
};

如果m是您的父模块,您将执行:

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

最新更新