AppModule加载之前的角加载外部配置 [英] Angular load external configuration before AppModule loads

查看:157
本文介绍了AppModule加载之前的角加载外部配置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下情形(Angular v7):

Consider the following scenario (Angular v7):

  1. 从外部端点(JSON)加载配置参数(API服务器URL和Auth服务器URL),加载AppModule之前
  2. 将配置传递给AppModule(OAuth2模块)
  3. 使用AOT编译应用程序
  1. Load configuration parameters (API server URL and Auth server URL) from an external endpoint (JSON), before the AppModule is loaded
  2. Pass configuration to AppModule (OAuth2 module)
  3. Compile the app with AOT

第2点在这里很关键,看起来像这样:

Point 2 is key here, and looks like this:

@NgModule({
  imports: [
    ...
    OAuthModule.forRoot({
      resourceServer: {
        allowedUrls: [API_SERVER_URL], // <== we need to set the value that we loaded from the external endpoint (JSON) here
        sendAccessToken: true
      }
    }),
    ...
  ],
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule { }

我已经尝试的东西:

  • A solution with APP_INITIALIZER. This doesn't work, as the OAuthModule.forRoot() is triggered before the APP_INITIALIZER can download the external configuration JSON.
  • Load the config with an async function in the main.ts into the Angular environment variables, then bootstrap the AppModule. Also doesn't work due to the import { AppModule } from './app/app.module'; statement in main.ts, which causes the AppModule to load and fire OAuthModule.forRoot() before the external config is loaded (this comment confirms this behavior).
  • Load the AppModule dynamically in main.ts, so without the import statement on top. This is the StackBlitz example given in that comment. It works, but 1) breaks lazy loading WARNING in Lazy routes discovery is not enabled. and 2) doesn't work with AOT compiling. It does come very close to what I need.

好奇地想知道是否有人在 AppModule加载之前知道加载外部配置的另一种方法.

Curious to hear if someone is aware of another method to get external configuration loaded before the AppModule loads.

选项3的StackBlitz(动态加载AppModule): https://stackblitz.com/edit/angular -n8hdty

StackBlitz for option 3 (Load the AppModule dynamically): https://stackblitz.com/edit/angular-n8hdty

推荐答案

Angular文档有一章很好,称为NgModule FAQs,其中包含以下部分:

Angular documentation has a great chapter called NgModule FAQs which contains the following section:

如果两个模块提供相同的服务怎么办?

...

如果NgModule A为令牌"X"提供服务并导入 NgModule B,它也为令牌"X"提供服务,然后是NgModule A的服务定义获胜".

If NgModule A provides a service for token 'X' and imports an NgModule B that also provides a service for token 'X', then NgModule A's service definition "wins".

换句话说,您可以在AppModule中为您的库覆盖OAuthModuleConfig:

In other words, you can override OAuthModuleConfig for your library in AppModule:

main.ts

(async () => {
  const response = await fetch('https://api.myjson.com/bins/lf0ns');
  const config = await response.json();

  environment['allowedUrls'] = config.apiBaseURL;

  platformBrowserDynamic().bootstrapModule(AppModule)
    .catch(err => console.error(err));
})();

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { OAuthModule, OAuthModuleConfig } from 'angular-oauth2-oidc';
import { HttpClientModule } from '@angular/common/http';
import { environment } from '../environments/environment';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    OAuthModule.forRoot(),
  ],
  providers: [
    {
      provide: OAuthModuleConfig,
      useFactory: () => ({
        resourceServer: {
          allowedUrls: [environment['allowedUrls']],
          sendAccessToken: true
        }
      })
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

请注意,我们也应该使用useFactory而不是useValue,这样我们就不必依赖导入AppModule的时间.

Note that we should also use useFactory instead of useValue so we don't depend on when AppModule is imported.

这篇关于AppModule加载之前的角加载外部配置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆