How to add your library's version to Angular application

Versioning is one of the most important aspects of software product development. Not only it helps to differentiate the various builds and releases of software, but a well-versioned software will also have the traceability back to the builds, merge requests, commits, and issues.

It is not uncommon to find the version embedded in the applications, and in these days of web applications, most web applications also display the version, although it may not be that conspicuous.

But what if you are a library developer? You cannot show the library version anywhere in the UI (unless the app developer/UI Team decides to do so). One of the ways this can be done is to inject an attribute in the DOM. As an example, this is how angular embeds its version in the application.

<!doctype html>
<html lang="en">
  <head>...</head>
  <body>
    <app-root ng-version="9.1.0">...</app-root> (1)
    <script src="runtime.js" type="module"></script>
    <script src="polyfills.js" type="module"></script>
    <script src="styles.js" type="module"></script>
    <script src="vendor.js" type="module"></script>
    <script src="main.js" type="module"></script>
  </body>
</html>
1Notice the Angular version being injected as ng-version="9.1.0"

Now, if you are developing your own library you might want to add your library’s version here as well. This comes very handy when you want to support an application in production and there is no other way to tell which version the application is using.

For this, we would need to find a way to get hold of the app’s root component in our library, and then inject the version as an attribute. One of the ways to get this is to provide a bootstrap listener via APP_BOOTSTRAP_LISTENER token. According to the Angular documentation:

All callbacks provided via this token will be called for every component that is bootstrapped.

This gives us a chance to get the ComponentRef of the root component when it is bootstrapped. Then, we can set the attribute in the callback that we would inject.

One of the ways to provide this callback can be to configure this in our library’s module. To do this, we will have to introduce a static function forRoot [1] in our module which returns ModuleWithProviders and provide the callback in the providers array.

library.module.ts
import { CommonModule } from '@angular/common';
import { APP_BOOTSTRAP_LISTENER, NgModule, Provider } from '@angular/core'; (1)

export function setLibraryVersion(componentRef: ComponentRef<any>) { (2)
  componentRef.location.nativeElement.setAttribute('lib-version', 'v1.0.0');
}

@NgModule({
  imports: [
    CommonModule
})
export class LibraryModule {

  static forRoot(): ModuleWithProviders {
    return {
      ngModule: LibraryModule,
      providers: [

        // The following code injects library version as an
        // attribute to the bootstrapped component
        // which will the the root component in case of applications
        {
          provide: APP_BOOTSTRAP_LISTENER, multi: true,
          useValue: setLibraryVersion (3)
        }
      ]
    };
  }
}
1Import APP_BOOTSTRAP_LISTENER
2Define the hook
3Provide the hook

Finally, all you have to do is to make sure to update your documentation mentioning to provide your library’s module using forRoot() in the application’s module. And once you have that taken care of, here is how the DOM will look like in the application:

<!doctype html>
<html lang="en">
  <head>...</head>
  <body>
    <app-root ng-version="9.1.0" lib-version="v1.0.0">...</app-root> (1)
    <script src="runtime.js" type="module"></script>
    <script src="polyfills.js" type="module"></script>
    <script src="styles.js" type="module"></script>
    <script src="vendor.js" type="module"></script>
    <script src="main.js" type="module"></script>
  </body>
</html>
1Now we have our version being injected as lib-version="v1.0.0"

There you go! Now if you have an application developer asking for support, it is much easier for him/her to tell you the version of the library by just looking at the DOM.


1. You may use any name you like. forRoot is a convention commonly used.
Load Comments?