DEV Community

Cover image for Angular app version attribute: APP_BOOTSTRAP_LISTENER token approach
Marin Muštra
Marin Muštra

Posted on • Edited on

4 1

Angular app version attribute: APP_BOOTSTRAP_LISTENER token approach

When developing applications, eventually we'll have some versioning to reflect our changes. An indicator, visual or on an HTML element, can be helpful when we have CI/CD flows and want to confirm pushed changes on production.

In this article, we will cover the attribute approach on HTML element. We'll use the bumped version from package.json and add attribute to our app's element like Angular does with the ng-version attribute.

Demo

Image description

The Code

Let's dive right in. To achieve this, we'll need to have access to the app's native element. We could get access to the element from the AppComponent, but there is a nicer way to do this, and that is by using APP_BOOTSTRAP_LISTENER token.

First things first, depending on TS config, we may need to set resolveJsonModule to true so that we are allowed to import needed values from package.json. If your moduleResolution is set to bundler you can skip this step.

// tsconfig.json

{
  "compilerOptions": {
    "resolveJsonModule": true
    // ...
  }
  // ...
}
Enter fullscreen mode Exit fullscreen mode

Then we need to define a provider using APP_BOOTSTRAP_LISTENER token. In callback we'll get the ComponentRef which will be used for setting up our version attribute.

// version.provider.ts

import {
  APP_BOOTSTRAP_LISTENER,
  ComponentRef,
  Provider,
  Renderer2,
} from '@angular/core';

import packageJson from './../package.json';
import { AppComponent } from './app.component';

function versionFactory() {
  return ({ injector, location }: ComponentRef<AppComponent>): void => {
    const renderer = injector.get(Renderer2);
    const element = location.nativeElement;

    renderer.setAttribute(
      element,
      `${packageJson.name}-version`,
      packageJson.version
    );
  };
}

export function provideVersion(): Provider {
  return {
    provide: APP_BOOTSTRAP_LISTENER,
    useFactory: versionFactory,
    multi: true,
  };
}
Enter fullscreen mode Exit fullscreen mode

In the end all we have left is to add a provider to our ApplicationConfig.

// app.config.ts

import { provideVersion } from './config/version.bootstrap';

export const appConfig: ApplicationConfig = {
  providers: [
    provideVersion(),
    // ...
  ],
};

Enter fullscreen mode Exit fullscreen mode

The Token

APP_BOOTSTRAP_LISTENER - A DI token that provides a set of callbacks to be called for every component that is bootstrapped.

During the Angular initialization process - when instantiating the application (and executing loadComponent method), registered listeners under the APP_BOOTSTRAP_LISTENER token will be called and the app component will be passed. At this moment the app component is already attached to DOM and has all the needed services provided. Registered listeners under the APP_BOOTSTRAP_LISTENER token will be called after the NavigationStart event is triggered for the first time of the app's lifetime.

One could ask, when to use the APP_BOOTSTRAP_LISTENER opposed to APP_INITIALIZER for setting various configs in applications? - A General rule of thumb can be based on the need of app component.

Use APP_BOOTSTRAP_LISTENER when you:

  • Need access to app component
  • Potentially need it after child components are added to app component
  • Potentially need it before loading other routed modules/components

Use APP_INITIALIZER when you:

  • Need access to services only
  • Potentially need app bootstrap to wait before sync/async work is done

Conclusion

Having a version attribute on an element is a nice way for the DEV/QA/TS/CS team to follow up on app's changes and have better communication. Also, by using bootstrap tokens, we can neatly "tuck" away all the configs for the application.

If you found this post helpful, feel free to share it with others who might benefit.

Thanks for reading!

Do your career a big favor. Join DEV. (The website you're on right now)

It takes one minute, it's free, and is worth it for your career.

Get started

Community matters

Top comments (0)

typescript

11 Tips That Make You a Better Typescript Programmer

1 Think in {Set}

Type is an everyday concept to programmers, but it’s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields

...

Read the whole post now!

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay