Внешняя конфигурация угловой нагрузки перед загрузкой AppModule - PullRequest
0 голосов
/ 01 февраля 2019

Рассмотрим следующий сценарий (Angular v7):

  1. Загрузка параметров конфигурации (URL-адрес сервера API и URL-адрес сервера аутентификации) из внешней конечной точки (JSON), до модуля AppModule
  2. Передача конфигурации в AppModule (модуль OAuth2)
  3. Скомпилируйте приложение с помощью AOT

Точка 2 является ключевой здесь и выглядит следующим образом:

@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 { }

То, что я пытался доказать:

  • Решение с APP_INITIALIZER .Это не работает, так как OAuthModule.forRoot() запускается до того, как APP_INITIALIZER может загрузить внешнюю конфигурацию JSON.
  • Загрузить конфигурацию с помощью асинхронной функции в main.ts впеременные среды Angular, затем загрузите AppModule.Также не работает из-за оператора import { AppModule } from './app/app.module'; в main.ts, который заставляет AppModule загружать и запускать OAuthModule.forRoot() перед загрузкой внешней конфигурации ( этот комментарий подтверждает это поведение).
  • Динамически загружать AppModule в main.ts, поэтому без оператора import вверху. Этот является примером StackBlitz, приведенным в этом комментарии. Работает , но 1) прерывает отложенную загрузку WARNING in Lazy routes discovery is not enabled. и 2) не работает с компиляцией AOT.Это действительно подходит очень близко к тому, что мне нужно.

Интересно узнать, знает ли кто-нибудь о другом способе загрузки внешней конфигурации до загрузки AppModule.

StackBlitz для варианта 3 (динамически загружать модуль приложения): https://stackblitz.com/edit/angular-n8hdty

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

В дополнение к ответу @ yurzui, если вы попробуете это в AOT (например, ng build --prod), вы получите

ERROR in Error during template compile of 'AppModule'
  Function expressions are not supported in decorators in 'AuthModule'
    'AuthModule' contains the error at src\app\core\auth.module.ts(29,23)
      Consider changing the function expression into an exported function.

, поэтому мы создадим экспортированную функцию для фабрики:

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';

export function oAuthConfigFactory() : OAuthModuleConfig {
  return {
    resourceServer: {
      allowedUrls: [environment.servers.apiServer],
      sendAccessToken: true
    }
  }
}

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    OAuthModule.forRoot(),
  ],
  providers: [
    {
      provide: OAuthModuleConfig,
      useFactory: oAuthConfigFactory
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}
0 голосов
/ 01 февраля 2019

В документации Angular есть замечательная глава под названием FAQs по NgModule, которая содержит следующий раздел:

Что, если два модуля предоставляют один и тот же сервис?

...

Если NgModule A предоставляет сервис для токена 'X' и импортирует NgModule B, который также предоставляет сервис для токена 'X', то определение сервиса NgModule A "выигрывает".

Другими словами, вы можете переопределить OAuthModuleConfig для вашей библиотеки в 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 импортируется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...