How does the framework manage the lifetime of DynamicModules?
Generally speaking, like it does any other module. A dynamic module is just a special name for a module configuraed by a function and represented by an object. The end result is usually something like
{
module: SomeModuleClass,
imports: [Imports, For, The, Module],
providers: [SomeProviderToken, SomeProviderService, ExtraProvidersNeeded],
exports: [SomeProviderService],
}
Pretty much the same kind of thing you'd see in an @Module()
decorator, but configured via a function that possibly uses DI instead of just written directly
How can you share multiple dynamic module instances between modules?
I might need a bit of clarification here, but I'll be happy to edit my answer with more detail once I know what's the goal here, or what you're trying to do.
How can you manage/change the scope of DynamicModules? For exmaple, changing them from behaving transitively to as a singleton. Defining their injection token, retrieving them on demand, etc.
The easiest option for sharing your configuration (besides making the module @Global()
) is to make a wrapper module that re-exports the dynamic module once it has been configured.
Example: Let's say we have a dynamic FooModule
that we want to pass application
to, to designate the name of the application, and we want to re-use that module in several other places
@Module({
imports: [
FooModule.forRoot(
{ application: 'StackOverflow Dynamic Module Scope Question' }
)
],
exports: [FooModule],
})
export class FooWrapperModule {}
Now instead of importing FooModule.forRoot()
again in multiple places, we just import FooWrapperModule
and get the same instance of FooService
with the configuration originally passed.
I do want to mention that by convention, DynamicModule.forRoot/Async()
usually implies single time registration in the RootModule
and usually has a @Global()
or isGlobal: true
config attached to it somewhere. This isn't always the case, but it holds relatively true.
DynamicModule.register/Async()
on the other hand, usually means that we are configuring a dynamic module for this module only and it can be reconfigured elsewhere to have it's own separate config. This can lead to cool setups where you can have multiple JwtService
instances that have different secret
values for signing (like for an access and refresh token signing service).
Then there's DynamicModule.forFeature()
which is like register
in that it is at a per module basis, but usually it uses config from the forRoot/Async()
call that was already made. The @nestjs/typeorm
module, mikro-orm/nestjs
module, and @ogma/nestjs-module
module are three separate examples I can think of that follow this pattern. This is a great way to allow for general configuration at the root level (application name, database connection options, etc) and then allow for scoped configuration at the module level (what entities will be injected, logger context, etc)