I am trying to create a DynamicModule
in Nestjs, but it seems I can't properly use useFactory
to inject ConfigModule in the process.
If I use a hardcoded boolean instead of config.get('cache').enabled
everything works as expected, but I receive the following error if I try to use config:
TypeError: Cannot read properties of undefined (reading 'get')
Here's the code I arranged so far:
app.module.ts
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
validate,
}),
CoreModule.registerAsync({
useFactory: (config: ConfigService) => ({
cacheEnabled: config.get('cache').enabled,
}),
imports: [ConfigModule],
injects: [ConfigService],
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
core.module.ts
@Module({})
export class CoreModule {
static registerAsync = (options: {
useFactory: (...args: any[]) => { cacheEnabled: boolean };
imports: any[];
injects: any[];
}): DynamicModule => {
const imports = [];
const providers = [];
if (options.useFactory().cacheEnabled) imports.push(HttpCacheModule);
return {
module: CoreModule,
imports,
providers,
};
};
}
In your case, you're calling
options.useFactory
directly: this is supposed to be handled by NestJS's dependency injection, where it will automatically pass the injections and set the return-value to be the provider-value for the class-defined token.If you look at the implementation of
ConfigurableModuleBuilder
, you'll see that it simply returns a new (asynchronous) provider of the form:The solution is then to then have static imports (only appending consumer-provided imports in dynamic modules), and have providers be dynamically configured (which only works if you have control over the module and providers.
Alternatively, use environment-variables (or some other pre-NestJS mechanism) to get your configuration for conditionally importing modules (you'll likely want to wait for env-vars with
await ConfigModule.envVariablesLoaded
).