#Dynamic Modules

11 messages · Page 1 of 1 (latest)

lost plinth
#

Hello!
A question about dynamic modules.

I'm trying to make a dynamic module that has static methods forRoot, forRootAsync, forFeature

According to the documentation, options can be passed to forRoot that define the global configuration for the module. Then, using the same module in other modules, but with forFeature, you can override some options, while knowing about the global configuration that was set via forRoot.

The idea is this: there are three modules AModule, BModule, CModule.

AModule is the main one. It will be connected to AppModule with some global configuration (forRoot). It will also be connected to other modules, already with some options overridden (forFeature)

BModule will be connected to AModule and must know about the global configuration that was passed via forRoot, as well as the configuration for a specific module (forFeature), where AModule is connected. Options must be merged

CModule - will be connected to BModule and already merged options must be passed to it.

The problem is that I do not understand how to do this correctly.
When I tried to implement the plan on my own, I encountered the fact that the options passed via forFeature are picked up only from the first module that is connected to AppModule, and not as planned, each module has its own options

#
import { DynamicModule, Module } from '@nestjs/common'

@Module({})
export class AModule {
  static forRoot(options: Record<string, unknown>): DynamicModule {
    return {
      module: AModule,
    }
  }

  static forFeature(options: Record<string, unknown>): DynamicModule {
    return {
      module: AModule,
      imports: [BModule.forRoot(options)],
    }
  }
}

@Module({})
export class BModule {
  static forRoot(options: Record<string, unknown>): DynamicModule {
    return {
      module: BModule,
      imports: [CModule.forRoot(options)],
    }
  }
}

@Module({})
export class CModule {
  static forRoot(options: Record<string, unknown>): DynamicModule {
    return {
      module: CModule,
    }
  }
}
cerulean portal
#

The answer is a hidden "global module". That's how most of the existing forRoot/forFeature modules work.

#

The forRoot registers an extra dynamic "core" module, that is made global and hosts the configuration. This module is then also imported by the forFeature modules and that's how they can read the root configuration

lost plinth
#

In my case, the problem is not getting the global configuration. I manage to get it and merge it with the options that were transferred to forFeature.

The problem is that the atomic module in which the configuration is reassigned takes the configuration that is specified in the first module to be connected in the AppModule.

To make it clearer, see the example below. The BarFeatureModule will end up with {foo:1}, not {foo:2 } as expected

@Module({
    import: [AModule.forFeature({ foo: 1 })]
})

export class FooFeatureModule {}

@Module({
    import: [AModule.forFeature({ foo: 2 })]
})

export class BarFeatureModule {}

@Module({
    import: [
        FooFeatureModule,
        BarFeatureModule,
    ]
})

export class AppModule {}

This is just a sample code. If you need more details to understand the problem, I can provide real code later, where everything will be clearly visible.

cerulean portal
#

It is really hard for me to understand with just these samples. What you describe seems strange, if the modules worked correctly.

If you could supply an actual code, or, better, a minimal working example, I could probably assist better

plain hound
lost plinth
lost plinth
plain hound
lost plinth