0

In an Angular application (Angular 13) I have a custom ErrorHandler which is able to send frontend errors to the backend. For that it gets an ApiService injected. This ApiService needs the URL of the backend and this URL should be defined in a JSON file that we create in our deployment pipelines.

My question is: How can I load this JSON file before starting angular. I tried to load it as APP_INITIALIZER, but I learned that the ErrorHandler is build first, so that approach did not work.

My approach now was to modify the metadata of the AppModule in the main.ts instead of declaring them with the @NgModule decorator like described here: https://stackoverflow.com/a/45200115/865334

So my code in the main.ts looks like this:


Promise.all([
  fetch('./environment.json'),
  fetch('./features.json')
]).then(async ([environmentResponse, featuresResponse]) => {

  const environment = await environmentResponse.json() as Partial<Environment>
  const environmentService = new EnvironmentService(environment)
  appModuleMetadata.providers.push({provide: EnvironmentService, useValue: environmentService})

  const featureStrings = await featuresResponse.json() as string[]
  const activatedFeatures = new Set(featureStrings.map(featureString => FeatureHelper.getFeatureByName(featureString)))
  const featureToggleService = new FeatureToggleService(activatedFeatures)
  appModuleMetadata.providers.push({provide: FeatureToggleService, useValue: featureToggleService})

  const appModule = NgModule(appModuleMetadata)(AppModule)
  platformBrowserDynamic().bootstrapModule(appModule)
    .then(_ => defineCustomElements(window))
    .catch(error => console.error(error))
})

My app.modile.ts looks like this:


export class AppModule {
}

export const appModuleMetadata: NgModule = {
  declarations: [AppComponent],
  imports: [
    IonicModule.forRoot(),
    // ...
  ],
  // ...
}

appModuleMetadata contains exactly the same object that was previously passed to the @NgModule decorator.

My issue with this approach: It seems that Angular cannot compile the templates anymore, because the components are not registered anymore.

[ng] Error: src/app/app.component.html:1:1 - error NG8001: 'ion-app' is not a known element:
[ng] 1. If 'ion-app' is an Angular component, then verify that it is part of this module.
[ng] 2. If 'ion-app' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
stofl
  • 2,950
  • 6
  • 35
  • 48
  • 1
    I'm not entirely sure what exactly you're doing here. Seems overly complicated? My advice would be to create 2 injection tokens (for environment and features) - then do what you do now, fetch the files you need and then provide those values from the files as platformProviders. So, platformBrowserDynamic supports this, something like: platformBrowserDynamic([ { provide: ENVIRONMENT, useValue: environment, }, ]) .bootstrapModule(AppModule) .catch((err) => console.error(err)); – MikeOne Mar 31 '22 at 08:47
  • This works perfectly! Thank you so much, @MikeOne for your support! – stofl Apr 01 '22 at 20:17
  • Excellent, good to hear! Happy coding ;-) – MikeOne Apr 01 '22 at 21:18

0 Answers0