Load configuration before bootstrapping Angular app
When building an Angular application, you may need to load configuration settings before the application starts. This is often necessary for setting up environment-specific values, feature flags, or user preferences. In this guide, I will show you how to load configuration from a JSON file before bootstrapping an Angular app effectively.
Create configuration model
First we need to create a model that represents the structure of the configuration data.
Create a file called app-config-data.model.ts in the src/app/models folder. Define the properties of the configuration data in this file.
export interface AppConfigData {
apiUrl: string;
}
Create configuration file
Next, we need to create a JSON file that contains the actual configuration data. This file will be placed in the public folder of the project so that it can be accessed at runtime.
Create a file called config.json in the public/assets folder. Add the configuration data to this file in JSON format.
{
"apiUrl": "https://api.example.com"
}
Create injection token
Then we need to create an injection token that will be used to inject the configuration data into our application with Angular's Dependency Injection.
Created a file called app-config-data.token.ts in the src/app folder. The T type parameter of the InjectionToken is set to AppConfigData to ensure type safety when injecting the configuration data.
import { InjectionToken } from '@angular/core';
import { AppConfigData } from './models/app-config-data.model';
export const APP_CONFIG_DATA = new InjectionToken<AppConfigData>('AppConfigData');
Load the configuration
Open src/main.ts. This is the entry point of the Angular application where we will load the configuration before bootstrapping the app.
In this file I define a fuction that will load the data from a JSON file, using the fetch API. This function will add the configuration data to the providers array of the appConfig object, which is used when bootstrapping the Angular application. This way, the configuration data will be available for injection throughout the app.
import { bootstrapApplication } from '@angular/platform-browser';
import { App } from './app/app';
import { appConfig } from './app/app.config';
import { APP_CONFIG_DATA } from './app/app-config.token';
async function loadAppConfigData(): Promise<void> {
try {
// URL to the configuration file, in the 'public' folder of the project ('/public/assets/config.json').
const configUrl = '/assets/config.json';
// Load the configuration data from the JSON file.
const response = await fetch(configUrl);
if (!response.ok) {
throw new Error(`Failed to load app config. ${response.status} ${response.statusText}`);
}
// Parse the response data as JSON.
const configData = await response.json();
// Add the configuration data to the providers array of the appConfig object.
appConfig.providers.push({
provide: APP_CONFIG_DATA,
useValue: configData
});
} catch (error) {
console.error('Error loading app configuration.', error);
throw error;
}
}
// First load the configuration data.
await loadAppConfigData();
// Then bootstrap the application.
bootstrapApplication(App, appConfig)
.catch((err) => console.error(err));
Use the configuration data
Now that the configuration data is loaded and provided in the Angular application, you can inject it into any component or service using the APP_CONFIG_DATA injection token.
Example of injecting the configuration data into a service:
import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { APP_CONFIG_DATA } from '../app-config.token';
import { AppConfigData } from '../models/app-config-data.model';
import { Snack } from '../models/snack.model';
@Injectable({
providedIn: 'root'
})
export class SnackService {
// Inject the configuration data using the APP_CONFIG_DATA injection token.
private readonly apiUrl = inject<AppConfigData>(APP_CONFIG_DATA).apiUrl;
private readonly httpClient = inject(HttpClient);
getSnacks(): Observable<Snack[]> {
const requestUrl = `${this.apiUrl}/snacks`; // Use the apiUrl to make an HTTP request.
return this.httpClient.get<Snack[]>(requestUrl);
}
}