I saw a lot of articles about loading configuration fields at runtime, but nothing solve the problem when you have multiple environments/domains in this file, lets say google, stackoverflow, etc as presented below.
{
"localhost": {
"api": "http://localhost:42324",
"production": false
},
"google": {
"api": "https://google.com",
"production": true
},
"stackoverflow": {
"api": "https://stackoverflow.com",
"production": true
}
}
Using a config service and APP_INITIALIZER (from angular), I load the configuration file and inject the fields in my application. I see there are 2 ways to do that, one adding all these specified above in the providers array, and the second to use ngDoBootstrap, which will wait for configuration to be loaded before bootstraping the application.
providers: [
{
provide: APP_INITIALIZER,
useFactory: appInitializerFn,
multi: true,
deps: [ConfigService]
}
]
export class AppModule {
constructor(private configService: ConfigService) {}
ngDoBootstrap(app: ApplicationRef) {
this.configService.init().then(() => app.bootstrap(AppComponent));
}
}
The problem:
How I filter the configuration object, to load only what I need from there. for domain google.com to load only object google, for domain stackoverflow.com to load only object stackoverflow.
Maybe a solution:
I'm thinking to use window.location to get the domain. Using that way, I can filter the json and get only the specific configuration object. And my service init method will be:
init(): Promise<AppConfig | undefined> {
return this.http
.get<any | undefined>('./app-config.json')
.toPromise()
.then((config) => {
const host = window.location.host;
if (typeof config !== 'undefined') {
switch (host) {
case 'http://localhost:4200': {
this.configuration = config.localhost;
break;
}
case 'https://google.com': {
this.configuration = config.google;
break;
}
case 'https://stackoverflow.com': {
this.configuration = config.stackoverflow;
break;
}
default:
this.configuration = { ... };
}
}
return this.configuration;
});
}
I tested it with different localhost ports and using window.location.port, but not yet in production. I'm thinking if this solution is ok, or should exists another way to do that.
I'm imagined that I can give some parameters when execute a command to run angular application, but this is outside the environment, because the angular app is just a /dist folder with all the files, and an external process (nginx/nodejs service) will listen to that folder to run the application.
// another idea was that the app-config.json file to contains fields with variables which will be populated somehow ...
{
"api": "${API_URL}",
"production": "${PRODUCTION_MODE}"
}
summary: Is something like "build once for all environments"