0

Directed by the answer to my question about Server-side rendering, I'm looking at implementing AOT compilation in my Angular2 app.

A bit of background to the problem I'm having: we have a build running in Visual Studio Online, which runs webpack etc, and ships a functioning webapp. We then have a release in VSO to different environments which puts some values (environment, base urls, important keys) into an env-config.js file. This env-config.js file is not bundled and packaged within the app, but we access it as a global js variable within our Angular code.

env-config.js

var envConfig = {
    'environment': 'local',
    'baseApiUrl': 'localhost:5555',
}

Within app-config.ts, we access envConfig from the window object, store this as a constant, and export the constant AppConfig, which we then register in app.module using an OpaqueToken.

app-config.ts

export function getEnvConfig(): IAppEnvConfig {
    if (window == null) {
        return {
            'environment': '',
            'baseApiUrl': ''
        };
    }
    else {
        return (window as any).envConfig;
    }
}

export const _envConfig: IAppEnvConfig = getEnvConfig();

export const AppConfig: IAppConfig = {
    applicationName: 'Web Application',
    environment: _envConfig.environment,
    baseApiUrl: _envConfig.baseApiUrl,
    otherSetting: 'someValue'
}

This works really well running in the browser with the JIT compiler. I'm following a combination of this and this and other tutorials to enable AOT compilation.

Running ngc gives me the following error:

"node_modules/.bin/ngc" -p app/tsconfig-aot.json Error encountered 
resolving symbol values statically. Calling function 'getEnvConfig',  
function calls are not supported. Consider replacing the function or lambda 
with a reference to an exported function, resolving symbol AppConfig

I added the check for window == null in getEnvConfig() because I don't think window will be available during non-browser compilation. If getEnvConfig() does anything other than return an empty IAppEnvConfig object I get the ngc error.

I have done a lot of Googling, but have found nothing specific to my issue, other than generic answers pointing towards using a factory function to create a new instance of a class, which I've tried to do here.

Sorry if that doesn't make much sense - please feel free to get clarification/tell me that I'm doing something incredibly stupid.

Thanks in advance, Alex

Community
  • 1
  • 1
Alex
  • 1,082
  • 3
  • 12
  • 23

1 Answers1

0

I'm not sure if this solution will fit you, but I post it any way. I faced the same issue and foud the problem was quite easy to solve. Simply put your functions in a class. Something like this:

export class AppConfig {
  _envConfig = AppConfig.getEnvConfig();
  AppConfig = {
    applicationName: 'Web Application',
    environment: this._envConfig.environment,
    baseApiUrl: this._envConfig.baseApiUrl,
    otherSetting: 'someValue'
  };

  static getEnvConfig() {
    if (window == null) {
      return {
        'environment': '',
        'baseApiUrl': ''
      };
    } else {
      return (window as any).envConfig;
    }
  }

  private constructor(){}
}
Robin Dijkhof
  • 18,665
  • 11
  • 65
  • 116
  • Thanks! How would you register this in your app.module.ts so that you can use it with the DI? Do you still use the OpaqueToken or just inject like you would a service? – Alex May 11 '17 at 15:01
  • Well, this is just a regular class so I doný think you need DI. I have never worked with OpaqueToken, however I read someting about it being replaced with InjectionToken. Never the less, this all seems like overkill to me sinds the CLI has a build-in option for this: https://github.com/angular/angular-cli/wiki/stories-application-environments – Robin Dijkhof May 11 '17 at 15:18
  • In progress, basically following your answer :) however, rather than having AppConfig exported as an object, I'm setting the config values as class properties. When it works, I'll accept your answer! – Alex May 15 '17 at 12:50