Issue
I read an old thread where it is recommended to share NX environment variables like the following:
import { environment } from '../environments/environment';
@Module({
providers: [
{
provider: 'someProviderName',
useValue: environment.someEnvironmentValue
}
],
MyService
})
class AppModule {
}
Then, you access them like:
@Injectable()
class MyService {
constructor(@Inject('someProviderName') someEnvironmentValue: someType) {
}
}
The justifications are that:
- It keeps your libs env independent.
- It allows you to build libs once, without knowing the apps they are used by or the env they ran in.
This is fine if you just need access to the environment variables from AppModule, but how can you share these environment variables with imported library modules? Especially library modules whose source does not reside within the same project as the environment.ts files?
Does every library module that need access to environment variables need to be a dynamic module (as well as all its parent modules) in order to take advantage of environment variables this way? And as such, do you need to chain down forRoot calls to get to any module that needs to access these variables?
Ex:
AppModule: DynamicModule
|
CoreModule: DynamicModule
| |
SomeFeatureModule: DynamicModule SomeOtherFeatureModule: NestModule
AppModule(Needs ENV so it becomes aDynamicModulewithForRoot)CoreModule(Needs env fromAppModuleso it becomes aDynamicModulewithForRootSomeFeatureModuleneeds env fromCoreModuleso it becomes aDynamicModulewithforRoot)- ... so on and so forth.
Also what would making all modules that need environment values into DynamicModule do to performance?
Example:
@Module({})
export class MyLibModule {
static forRoot(providers: Provider[]): DynamicModule {
return {
module: MyLibModule ,
providers: [...providers],
};
}
}
const ENV_VALUE_PROVIDERS: ValueProvider[] = [
{
provide: 'PRODUCTION',
useValue: environment.production,
},
];
@Module({
providers: ENV_VALUE_PROVIDERS,
imports: [MyLibModule.register(ENV_VALUE_PROVIDERS)],
})
export class AppModule {}
Why does NestJS force any lib modules to be dynamic to access these type of environment variables in this case given these variables are available at compile-time?
The only other solution I have thought of is to create a Library Module that gets imported by every module that needs environment variables. This module would be initialized in the AppModule using forRoot with the environment variables to be exported. The problem with this solution is that many libraries would then have a direct dependency on this module.
Solution
I still don't have answers to all my questions on DynamicModules, but for the time being I unblocked myself by:
Injecting my variable using a ValueProvider, and then using a "factory" option object in the module to pass in the particular environment variable that the module needs.
Here's some basic untested code illustrating the concept:
app/environments/environment.ts
export class Environment {...}
app/app.module.ts
import { environment } from 'environments/environment';
Module({
providers: [{ provide: Environment, useValue: environment }],
imports: [
MyModule.register({
provide: MyModuleOptions,
value: (environment: any) => environment.MyModuleOptions,
inject: [Environment],
})
],
})
export class AppModule {}
lib/my-module.module.ts
@Module({
providers: [SomeProviderThatUsesMyModuleOptions],
exports: [SomeProviderThatUsesMyModuleOptions]
})
export class MyModule {
static register(
options: MyModuleOptions | Provider<MyModuleOptions>)
: DynamicModule {
...
return {
module: MyModule,
providers: [MyModuleOptions]
...
};
}
}
This article goes into much better detail on the core concept.
Answered By - Francisco Aguilera
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.