Den*_*ing 6 typescript angular
考虑以下情形(Angular v7):
第二点是这里的关键,看起来像这样:
@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 { }
Run Code Online (Sandbox Code Playgroud)
我已经尝试了以下内容:
OAuthModule.forRoot()
会在APP_INITIALIZER
下载外部配置JSON 之前触发。main.ts
进入角环境变量,然后引导中的AppModule。由于中的import { AppModule } from './app/app.module';
语句也无法正常工作main.ts
,这会导致AppModule在加载OAuthModule.forRoot()
外部配置之前加载并启动(此注释确认了此行为)。main.ts
,所以没有import
在上面的语句。这是该注释中给出的StackBlitz示例。它可以工作,但是1)打破了延迟加载,WARNING in Lazy routes discovery is not enabled.
并且2)不适用于AOT编译。它确实非常接近我的需求。想知道是否有人知道在加载AppModule 之前加载外部配置的另一种方法。
选项3的StackBlitz(动态加载AppModule):https ://stackblitz.com/edit/angular-n8hdty
Angular文档中有一章非常棒,称为NgModule FAQs,其中包含以下部分:
如果两个模块提供相同的服务怎么办?
...
如果NgModule A为令牌“ X”提供服务,并导入NgModule B也为令牌“ X”提供服务,则NgModule A的服务定义“获胜”。
换句话说,您可以在AppModule中为您的库重写OAuthModuleConfig:
主要
(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));
})();
Run Code Online (Sandbox Code Playgroud)
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 {}
Run Code Online (Sandbox Code Playgroud)
请注意,我们也应该使用useFactory
代替,useValue
这样我们就不必依赖何时AppModule
导入。
除了@yurzui 的回答,如果你在 AOT 中尝试这个(例如ng build --prod
),你会得到
ERROR in Error during template compile of 'AppModule' 'AuthModule' 中的装饰器不支持函数表达式 'AuthModule' 包含位于 src\app\core\auth.module.ts(29,23) 的错误考虑将函数表达式更改为导出的函数。
所以我们为工厂创建了一个导出函数:
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 {}
Run Code Online (Sandbox Code Playgroud)
这里的另一种选择。@yurzui 答案有效,但它需要使用useFactory
它使代码更难理解。
useFactory
是必需的,因为 Angular@NgModule
装饰器将在AppModule
导入后立即执行main.ts
,因此尚未加载配置。
所以我决定通过在angular.js
. 就是这样:
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'),
};
})();
Run Code Online (Sandbox Code Playgroud)
角度.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"],
// ...
Run Code Online (Sandbox Code Playgroud)
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<string>('apis.github.baseUrl');
*/
static get<T>(path: string, defaultValue?: T): T {
return get(Configuration.value, path, defaultValue);
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以使用:
OAuthModule.forRoot({
resourceServer: {
allowedUrls: Configuration.get('allowedUrls')
sendAccessToken: true
}
}),
Run Code Online (Sandbox Code Playgroud)
如果您对 lodash 有问题,请查看此内容。
归档时间: |
|
查看次数: |
1159 次 |
最近记录: |