Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nestjs: dynamic global module

The official nest docs on modules explain about global modules and dynamic modules. I'm wondering if it is possible to combine the two patterns?

My use case is the following: I have a dynamic config module:

export class ConfigModule {
    static forRoot(baseConfigPath: string): DynamicModule {
        const providers = [{ provide: 'Config', useValue: configFactory(baseConfigPath) }];

        return {
            module: ConfigModule,
            providers,
            exports: providers,
        };
    }
}

This enables the config-module to be dependent on the passed in base config path. I can then import the module in the main app module as follows:

@Module({
    imports: [ConfigModule.forRoot(path.resolve(__dirname, '../config'))],
    controllers: [AppController],
    providers: [AppService],
})
export class AppModule implements NestModule {}

which is kind of nice. However, I do have lots of other modules (child modules of the app module, siblings to the config module), where I also want that same instance of the dynamic config module to be injectable. Would be great if I could mark the dynamic ConfigModule somehow as global - or is there another way?

I've already tried making the ConfigModule global with @Global, but that didn't work - here's a super minimal reduced example repo based on the nest starter created by nest new: https://github.com/DeX3/nest-di-playground

like image 561
DeX3 Avatar asked Dec 11 '18 12:12

DeX3


People also ask

What is dynamic modules in NestJS?

In fact, what our register() method will return is a DynamicModule . A dynamic module is nothing more than a module created at run-time, with the same exact properties as a static module, plus one additional property called module .

What is DTO NestJS?

A DTO is an object that defines how the data will be sent over the network. We could determine the DTO schema by using TypeScript interfaces, or by simple classes. Interestingly, we recommend using classes here.

What is NestJS forRoot?

The forRoot sets up the loading of the . env file and the forChild uses it in another module. The problem is that forChild is called before forRoot . The ConfigService would be injected with missing config because forRoot hasn't executed first. > AppModule > ConfigModule.


1 Answers

Recently I built something like what you are describing, I got inspiration from nest/typeorm

@Module({})
export class LoggerModule {
  static forRoot(rootNamespace: string): DynamicModule {
    return {
      module: LoggerModule,
      imports: [LoggerCoreModule.forRoot(rootNamespace)],
    };
  }
}
@Global()
@Module({})
export class LoggerCoreModule {
  static forRoot(rootNamespace: string): DynamicModule {
    const namespaceProvider = {
      provide: LOGGER_ROOT_NAMESPACE,
      useValue: rootNamespace,
    };

    const loggerServiceProvider: Provider = {
      provide: LoggerService,
      useFactory: (namespace) => new LoggerService(namespace).init(),
      inject: [LOGGER_ROOT_NAMESPACE],
    };

    return {
      module: LoggerCoreModule,
      providers: [loggerServiceProvider, namespaceProvider],
      exports: [loggerServiceProvider, namespaceProvider],
    };
  }
}

Then, you will have a LoggerService in the global scope which was exported from LoggerCoreModule. You don't have to export the config you pass but I did it since my noncore module has a forFeature static method which needs it(I didn't paste the whole thing I built).

like image 55
Ing.LkRuiZ Avatar answered Sep 23 '22 15:09

Ing.LkRuiZ