angularangular-libraryruntime-configurationinjection-tokens

How to pass a Lib Config using forRoot() with InjectionToken in Angular


I've been inspired by this answer in order to provide my APP_Config as an injection token, I got this in my main.ts

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { APP_CONFIG } from './app/config/AppConfig';


function configListener(this: any) {
  try {
    const configuration = JSON.parse(this.responseText);

    // pass config to bootstrap process using an injection token
    platformBrowserDynamic([
      { provide: APP_CONFIG, useValue: configuration }
    ])
      .bootstrapModule(AppModule)
      .catch(err => console.error(err));

  } catch (error) {
    console.error(error);
  }
}

function configFailed() {
  console.error('Error: retrieving config.json');
}


const request = new XMLHttpRequest();
request.addEventListener('load', configListener);
request.addEventListener('error', configFailed);
request.open('GET', './assets/app.config.json');
request.send();

export interface AppConfig {
  clientId: string;
  clientSecret: string;
  ...
}

I can use the loaded config from any service in my application

  constructor(@Inject(APP_CONFIG) private appConfig: AppConfig) {}

But I'm not able to pass the config for the shared Library in my app.module.ts

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    ...,
    LibModule.forRoot({
      authConfig: {
        clientId: 'XXXXXXXX',
        dummyClientSecret: 'XXXXXX',
         ...
      }
      
    })
  ],
  providers: [
   
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

How can I provide the config in forRoot()from the APP_CONFIG InjectionToken ? is there a relevant solution or I have to update the shared Library module ?

@NgModule({
  declarations: [],
  imports: [...],
  providers: [...],
})
export class LibModule {
  static forRoot(configuration: Config): ModuleWithProviders<LibModule> {
    return {
      ngModule: LibModule,
      providers: [{ provide: AUTH_CONFIGURATION, useValue: configuration }],
    };
  }
}


export const AUTH_CONFIGURATION = new InjectionToken<Config>('AUTH_CONFIGURATION');

PS: I am trying to load my app configuration at the runtime which allows to reuse the same build artifact for all environments (I got ideas from this article)

My issue is already mentioned here https://github.com/angular/angular/issues/23279#issuecomment-412108311


Solution

  • The solution may be quite simple ! we can provide the AUTH_CONFIGURATION directly from our application as the following

    const generateAuthConfiguration = (appConfig: AppConfig) => {
       return {
         authConfig: {
            clientId: appConfig.clientId,
            dummyClientSecret: appConfig.clientSecret,
         }
       }
    }
    
    @NgModule({
      declarations: [AppComponent],
      imports: [
        BrowserModule,
        ...,
        { 
          ngModule: LibModule,
          providers: [
            {
              provide: AUTH_CONFIGURATION,
              useFactory: generateAuthConfiguration,
              deps: [APP_CONFIG]
            }
          ]
        }
      ],
      providers: [
       
      ],
      bootstrap: [AppComponent],
    })
    export class AppModule {}
    
    

    That's it !