0

To prevent building our Angular-App multiple times for different environments, we tried to forgo injecting environment-specific variables (e.g. service endpoints) into our app with regular fileReplacements and instead load those environments from assets (/assets/environment.js in our case).

The approach is outlined in posts like this or this.

The environment.js is very simple. It's included in a <script> tag in our index.html to ensure it's loaded and executed before any angular-code and it simply sets a property of window (yay global variables!)

window.env = {
  serviceUrl: 'https://production.example.com/api'
}

This works very well with one critical exception. There are modules in our application that require access to those environment variables when setting up:

@NgModule({
  imports: [
    ExampleModule.forExample({
      serviceUrl: window.env.serviceUrl,
    }),
  ],
  ...
})
export class AppModule { }

This will fail because window.env is not present/undefined at AoT compilation.

Is there any way to work around this issue?

Most of our applications are heavy so we don't want to switch to JiT compilation and we'd also like to keep builds to a minimum because they can take up to 20 minutes for certain projects.

Leo
  • 115
  • 1
  • 7
  • 2
    Why not create a service that provides the values at runtime? Or maybe make serviceUrl a getter: `ExampleModule.forExample({ get serviceUrl() { return window.env.serviceUrl; }, }),` – Andrei Tătar Apr 25 '19 at 13:57
  • 1
    You could inject these from the server-side using Angular Universal. We pull in environment variables via Node and pass them to the index.html and then pick them up in Angular. – Brandon Taylor Apr 25 '19 at 13:58
  • @Brandon I already pass my env variables to the index.html, the problem remains the same with server-side rendering. But I will definitely check out Angular Universal! – Leo Apr 29 '19 at 06:26
  • @AndreiTătar I can't access a service in the NgModule-decorator. I suppose passing functions instead of values to the module could work but requires changes in the ExampleModule, which can be an external dependency. – Leo Apr 29 '19 at 06:47
  • @Leo I think you misunderstood my comment. When I'm referring to an environment variable, I'm referring to an actual environment variable from the OS, not from the environments file in Angular. – Brandon Taylor Apr 29 '19 at 14:51
  • @Brandon I understand, but it doesn't matter where the variable actually comes from, as the AoT build has already evaluated the NgModule decorator when it receives the variables because the app is built before deploying it, whether you deploy it with a traditional web server or Angular Universal. – Leo Apr 30 '19 at 08:23

1 Answers1

0

After basically giving up we found NGSSC (https://github.com/kyubisation/angular-server-side-configuration).

NGSSC is able to tokenize variables during the AoT-Build. When deploying the app to a specific environment, these tokens can be replaced with the actual variable values by calling ngssc insert.

Leo
  • 115
  • 1
  • 7