Skip to content

jontze/ng-remote-config

Repository files navigation

Angular Remote Configuration Library

ToC

Overview

This Angular library provides a simple way to manage remote configuration settings in an Angular application. The library allows you to store, retrieve, and inject configuration objects in a structured and type-safe manner.

Features

  • Easy to set and retrieve configurations.
  • Injectable service for accessing configurations via Angular's dependency injection system.
  • Support to access configurations outside of the DI context.

Installation

Install it via npm

npm install @jontze/ng-remote-config

or yarn

yarn add @jontze/ng-remote-config

or any other Node.JS package manager.

Angular Version Matrix

Angular Version ng-remote-config Version
^18.0.0 ^1.0.0

Usage

  1. Fetch your Config and Set in the Store

Move your angular app bootstrap code to a separate file. Here it's called bootstrap.ts.

// bootstrap.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, appConfig);

In your application entrypoint (usually main.ts), fetch the configuration files and then set them in the store. After that, import your application bootstrap.

// main.ts
import { setRemoteConfig } from '@jontze/ng-remote-config';

Promise.all([
  fetch('/assets/config.json')
    .then((res) => res.json())
    .then((config) => setRemoteConfig(config)),
  fetch('/assets/features.json')
    .then((res) => res.json())
    .then((features) => setRemoteConfig(features, 'features')),
])
  .then(() => import('./bootstrap'))
  .catch((err) => console.error(err));
  1. Provide the Configuration in DI
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideConfig } from '@jontze/ng-remote-config';

import { appRoutes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [provideRouter(appRoutes), provideConfig()],
};
  1. Access the Configuration via the ConfigService
interface YourConfigType {
  apiUrl: string;
}

interface FeatureFlags {
  featureA: boolean;
  featureB: boolean;
}

@Component({
  standalone: true,
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrl: './app.component.css',
})
export class AppComponent implements OnInit {
  private readonly configService = inject(ConfigService);

  ngOnInit(): void {
    console.debug('ConfigService:', this.configService.getConfig<YourConfigType>());
    console.debug('ConfigService:', this.configService.getConfig<FeatureFlags>('features'));
  }
}
  1. Outside of the DI Context: Access the Configuration via the Store
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { getRemoteConfig } from '@jontze/ng-remote-config';

import { appRoutes } from './app.routes';

interface ApiConfig {
  apiUrl: string;
}

export const appConfig: ApplicationConfig = {
  providers: [provideRouter(appRoutes), provideSomeAPI({ url: getRemoteConfig<ApiConfig>().apiUrl })],
};

Example

You can take a look at the ng-remote-config-example application for a better understanding.

Why?

In traditional Angular applications, configurations are often hardcoded or environment-specific. This approach requires a separate build for each environment (e.g., development, staging, production). Managing multiple builds can be cumbersome and error-prone, especially in continuous integration and delivery pipelines.

To prevent this you can dynamically load configurations at runtime, eliminating the need for multiple builds. This allows you to have a single build that can be deployed across different environments. Furthermore, you can even change configuration without the need to redeploy your app! Built once, deploy everywhere!

Addressing Angular’s Limitation with Async Providers

Angular lacks built-in support for asynchronous providers, making it difficult to fetch and inject loaded configurations or settings dynamically during application bootstrap.

Issue: angular/angular#23279

A common and reliable solution to this problem is to fetch the configurations before application bootstrap. However, this has several drawbacks.

Drawbacks to Consider

  1. Increased Initial Loading Time: Fetching configurations dynamically at runtime add to the initial loading time of your application. The configurations need to be retrieved and processed before the application can fully initialize, which might slightly delay the startup time.

  2. Potential for Run-time Errors: Since configurations are fetched dynamically, any issues with the configuration service or the configuration data itself can lead to run-time errors.

  3. Dependency on External Configuration Services: Relying on remote configurations means your application depends on the availability and reliability of the configuration service. Network issues or service outages can impact your application's ability to retrieve configurations, so you should consider fallback mechanisms or local caching.

Contribution

Contributions are welcome! Please open issues or pull requests for bug reports or feature requests.

License

This project is licensed under the MIT License.