Angular load external configuration before AppModule loads

后端 未结 3 734
悲哀的现实
悲哀的现实 2020-12-06 06:29

Consider the following scenario (Angular v7):

  1. Load configuration parameters (API server URL and Auth server URL) from an external endpoint (JSON), befo
3条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-12-06 07:07

    Another option here. @yurzui answer works, but it requires the use of useFactory which make the code harder to understand.

    useFactory is required because Angular @NgModule decorators will be executed as soon as the AppModule is imported in main.ts and so the configuration isn't loaded yet.

    So I decided to load the configuration even before that by adding a script in the scripts section of angular.js. Here's how:

    src/config/load.js:

    // This file is added to the scripts section of 'angular.json' so it can run before Angular bootstrap process.
    // It responsability is to load app configuration from JSON files.
    (() => {
      const fetchSync = url => {
        // The code below will log the following warning: "[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.",
        // but since we want the configuration to be set before Angular bootstrap process, we ignore this warning.
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url, false);
        xhr.send(null);
        return JSON.parse(xhr.responseText);
      };
    
      // We attach the fetched configuration to the 'window' global variable to access it later from Angular.
      window.configuration = {
        ...fetchSync('config/config.base.json'),
        ...fetchSync('config/config.local.json'),
      };
    })();
    

    angular.json:

      // ...
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            // ...
            "assets": [
              // ...
              "src/config/config.base.json",
              "src/config/config.local.json"
            ],
            "scripts": ["src/config/load.js"],
      // ...
    

    src/config/configuration.ts:

    import get from 'lodash/get';
    
    export class Configuration {
      // We get the configuration from the 'window.configuration' property which as been set earlier by 'config/load.js'.
      private static value = (window as any).configuration;
    
      /**
       * Get configuration value.
       * @param path The path of the configuration value. Use '.' for nested values.
       * @param defaultValue The returned value if the given path doesn't exist.
       * @example
       * const baseUrl = Configuration.get('apis.github.baseUrl');
       */
      static get(path: string, defaultValue?: T): T {
        return get(Configuration.value, path, defaultValue);
      }
    }
    

    Then you can use:

    OAuthModule.forRoot({
      resourceServer: {
        allowedUrls: Configuration.get('allowedUrls')
        sendAccessToken: true
      }
    }),
    

    See this if you have problem with lodash.

提交回复
热议问题