@nxt-engineering/ngx-runtime-config
v0.0.10
Published
This project provides a way to load runtime configuration for an Angular application from a remote endpoint during the initialization of Angular. This is useful for scenarios where configuration values need to be dynamic and can't be hard-coded into the a
Downloads
338
Readme
ngx-runtime-config
This project provides a way to load runtime configuration for an Angular application from a remote endpoint during the initialization of Angular. This is useful for scenarios where configuration values need to be dynamic and can't be hard-coded into the application at build time.
We mostly use this for getting the OIDC configuration for the current environment, for delivering access tokens and configuration for third party services, and to implement feature flags, allowing us to dynamically enable and disable certain features without redeployment. We use it to initialize services like angular-oauth2-oidc, angular-auth-oidc-client, Turnstile, Sentry, Matomo, Clarity and basically any other service.
This project builds on APP_INITIALIZER,
so that the configuration is loaded during the initialization phase of Angular.
This way, the configuration is available early on.
The configuration is cached, so that reloading the window does not require another round-trip to the server. But for the first initialization, you pay a small penalty, as the application needs another roundtrip to the server.
Getting Started
Install the package:
npm install @nxt-engineering/ngx-runtime-configThen create an interface for your application's configuration needs, like so:
// src/app/app.runtime-config.ts
import { OpenIdConfiguration } from "angular-auth-oidc-client";
export interface AppRuntimeConfig {
server: {
// useful information about the server to render in the footer
env: string;
version: string;
};
featureFlags?: {
featureA?: boolean;
featureB?: number; // might be a ratio, e.g. 0.5
featureC?: string; // might be a pattern, e.g. `@my-org.com`
featureD?: string[]; // might be a list of accounts, e.g. `["carla", "beat", "test123"]`
};
auth: OpenIdConfiguration; // you can re-use interfaces of other components
}Then extend the providers array where you bootstrap your application,
usually in the app.config.ts or the main.ts file:
// src/app/app.config.ts
import { ApplicationConfig, provideZoneChangeDetection } from "@angular/core";
import { provideRouter } from "@angular/router";
import { provideRuntimeConfig } from "@nxt-engineering/ngx-runtime-config";
import { routes } from "./app.routes";
import { AppRuntimeConfig } from "./app.runtime-config";
export const appConfig: ApplicationConfig = {
providers: [provideRuntimeConfig<AppRuntimeConfig>(), provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)],
};If you don't provide a configuration URL, the default URL is /.well-known/runtime-config.
The expected response is a JSON that matches the interface you defined.
As an example, this JSON matched the interface defined above.
{
"server": {
"env": "prod",
"version": "v42-f321ba9"
},
"featureFlags": {
"featureB": 1.0
},
"auth": {
"authority": "https://my-app.zitadel.cloud/",
"clientId": "112233445566778899@backoffice",
"scope": "openid profile email offline_access",
"responseType": "code"
}
}Advanced Usage
You have several options to deliver this file:
- Have your application server handle that pre-configured URL (or place a file there)
- Configure your application server, web server or CDN to redirect with
301 Moved Permanentlyto the actual endpoint - Configure the actual endpoint in code, like in the following example
// src/app/app.config.ts
import { ApplicationConfig, provideZoneChangeDetection } from "@angular/core";
import { provideRouter } from "@angular/router";
import { provideRuntimeConfig } from "@nxt-engineering/ngx-runtime-config";
import { routes } from "./app.routes";
import { AppRuntimeConfig } from "./app.runtime-config";
export const appConfig: ApplicationConfig = {
providers: [
provideRuntimeConfig<AppRuntimeConfig>({
configEndpoint: "/api/v2/client-config",
autoLoad: true, // default
cacheBehavior: "sessionStorage", // default
cacheValidityMillis: 1000 * 60 * 60, // default
}),
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
],
};The configuration is automatically loaded during the bootstrap phase of Angular (unless you opt out). If the value is already cached, it will not be fetched a second time. By default, the configuration is cached in the sessionStorage for one hour.
If your application is often opened in multiple tabs simultaneously, then you should consider changing the cache to the localStorage:
// src/app/app.config.ts
import { ApplicationConfig, provideZoneChangeDetection } from "@angular/core";
import { provideRouter } from "@angular/router";
import { provideRuntimeConfig } from "@nxt-engineering/ngx-runtime-config";
import { routes } from "./app.routes";
import { AppRuntimeConfig } from "./app.runtime-config";
export const appConfig: ApplicationConfig = {
providers: [
provideRuntimeConfig<AppRuntimeConfig>({
cacheBehavior: "localStorage",
// …
}),
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
],
};To read the configuration, you can inject the NgxRuntimeConfigService and access it's config property:
// src/app/app.component.ts
import { AppConfig } from "./app.config";
import { NgxRuntimeConfigService } from "@nxt-engineering/ngx-runtime-config";
export class AppComponent {
constructor(readonly configService: NgxRuntimeConfigService<AppConfig>) {
this.serverConfig = configService.config()?.server;
}
}This also allows you to reload the configuration, should that become necessary:
// src/app/app.component.ts
import { AppConfig } from "./app.config";
import { NgxRuntimeConfigService } from "@nxt-engineering/ngx-runtime-config";
export class AppComponent {
constructor(readonly configService: NgxRuntimeConfigService<AppConfig>) {}
async reloadConfig() {
await this.configService.reload();
}
}By default, reload() will ignore the cache.
Demo Projects
There are some demo projects to see how the NgRuntimeConfigService is used in a real Angular projects.
Note:
These projects load the runtime config file from
/runtime-config.json. The corresponding JSON is provided as a static file inpublic/runtime-config.json. In a real project, this file would not be checked-in into your source code. Rather, it'd either be generated during deployment or on-demand by an application server.
Fetch-based config loader
This project does not configure a HttpClient.
So the NgRuntimeConfigService relies on the native fetch() method to get the configuration from the server.
This is useful, if you need information from the runtime configuration to configure the HttpClient.
ng serve @nxt-engineering/demo-fetchHttpClient-based config loader
This project is configured with a HttpClient.
ng serve @nxt-engineering/demo-httpRelease
Instructions to publish a new release:
- Set the version in
./projects/nxt-engineering/ngx-runtime-config/package.json. git commit -m 'prepare <the version>'git tag <the version>git pushgit push --tags
License
This project is licensed under the MIT License, see the LICENSE file for details.
