DEV Community

Cover image for Runtime config with Angular
Nicolas Beaussart
Nicolas Beaussart

Posted on • Edited on • Originally published at nbe.io

4 1

Runtime config with Angular

In angular, there is by default a buildtime config, it works well, but it have some disadvantages :

  • To change a config, you have to rebuild your application
  • Doesn't respect the "Build once, deploy everywhere" devops philosophy

For example, if you want to build your angular project into a docker image and use only the buildtime config, you will need to build every time the docker in order to point to another back-end !

The solution is Runtime config.

Runtime config is a config file, usually fetched at startup, containing configs like the server URL or other details.

Luckily, Angular have a hook to run something at startup, APP_INITIALIZER and we can use this to fetch the config at startup !

First, let's make the config.json file, in the assets folder :

{
  "API_URL": "http://localhost:3000"
}
Enter fullscreen mode Exit fullscreen mode

Then we can make the service that will fetch the configs :

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root',
})
export class AppConfigService {
  private appConfig;

  constructor(private http: HttpClient) {}

  loadAppConfig() {
    return this.http
      .get('/assets/config.json')
      .toPromise()
      .then(data => {
        this.appConfig = data;
      });
  }

  getServerUrl(): string {
    return this.appConfig.API_URL;
  }
}
Enter fullscreen mode Exit fullscreen mode

As you can see, you have to return a promise and not an observable, as APP_INITIALIZER needs a promise and not an observable.

Once we have this service, we have to edit the app.module.ts with a function to load the config

const initializerConfigFn = (appConfig: AppConfigService) => {
  return () => {
    return appConfig.loadAppConfig();
  };
};
Enter fullscreen mode Exit fullscreen mode

And provide it in the main module :

@NgModule({
  imports: [
    ...
    HttpClientModule,
    ...
  ],
  providers: [
    ...
    {
      provide: APP_INITIALIZER,
      useFactory: initializerConfigFn,
      multi: true,
      deps: [AppConfigService],
    },
    ...
  ],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

Here we have it ! Your application will be run after the fetch of the config.json.

Bonus : auto http prefixer

With that, we can make a auto http prefixer using our previously fetch settings :

import { Injectable } from '@angular/core';
import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { AppConfigService } from '../services/app-config.service';

 /**
 * Prefixes all requests not starting with `http[s]` with the dynamic config.
 */
@Injectable()
export class ApiPrefixInterceptor implements HttpInterceptor {
  constructor(private readonly appConfig: AppConfigService) {}

   intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (!/^(http|https):/i.test(request.url) && !request.url.startsWith('/assets/')) {
      request = request.clone({ url: this.appConfig.getServerUrl() + request.url });
    }
    return next.handle(request);
  }
}
Enter fullscreen mode Exit fullscreen mode

Then provide it in our AppModule :

@NgModule({
  imports: [
    ...
    HttpClientModule,
    ...
  ],
  providers: [
    ...
    {
      provide: APP_INITIALIZER,
      useFactory: initializerConfigFn,
      multi: true,
      deps: [AppConfigService],
    },
    {
      provide: HTTP_INTERCEPTORS,
      useClass: ApiPrefixInterceptor,
      multi: true
    },
    ...
  ],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

There you have it ! Automatic url prefixer from a dynamic url fetch from a config.json !

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (0)

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay