typescript - NestJS: nestede asynkrone initialiseringer i dynamiske moduler
I hovedmodulen min (A) importerer jeg en ekstern modul (B) med dens konfigurasjon:
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,
};
}
}
Merk at i modul B importerer jeg en tredjepartsmodul ved hjelp av en fabrikk, og den trenger modul B-konfigurasjon. Den er imidlertid ikke tilgjengelig ennå fordi den er asynkron. Den vil bli levert når modulen endelig er instansiert. Jeg injiserer imidlertid allerede denne provideren i importene mine. Så jeg får en injeksjonsfeil:
[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?
Jeg er ganske sikker på at det finnes en løsning, men jeg har ikke funnet den ennå.
Svar #1
Jeg ramlet nettopp over det samme problemet som deg og fant en løsning. Du må gi alternativleverandøren din til undermodulen (i dette tilfellet 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;
};
Hvis m er din overordnede modul, ville du gjort:
const jwtModule = JwtModule.registerAsync({
useFactory: (opt: AuthenticationModuleOptions) => opt.jwt,
inject: [MODULE_OPTIONS_TOKEN],
});
importAsyncModule(m, jwtModule, MODULE_OPTIONS_TOKEN);
