客户特定的环境变量或配置(NX & Angular)

Customer specific environment variables or configuration (NX & Angular)

假设我们有两个应用程序,20 位客户正在使用其中一个应用程序。这两个应用程序都使用相同的 table 组件,有 5 列。现在有 5 个客户想要不同的列顺序和列名称。因此,我的第一个想法是为 table 创建一个“默认”配置,如果存在“客户配置”,该配置将被覆盖。

问题: serve/build 具有特定“客户配置”的应用程序是否已经存在预定义方法?目前我们只有一个应用程序的单一配置,需要为每个客户手动替换。如果您想快速重建所有客户应用程序,这会花费很多时间。

为什么不将服务器中的客户特定配置作为 JSON 文件提供?

我会添加客户特定的 UI 配置,并可能在客户登录后立即获取它。

您最好的前进方式是在运行时加载配置。在 angular 中,profiles/environments 仅为构建时 - 这意味着您在编译期间使用的任何配置文件都将在运行时修复 - 而这不是您想要的。

如何加载 initialization/config 数据的一种常见方法是使用在模块初始化序列期间运行的 APP_INITIALIZER(doc)。例如,您可能已经在允许访问 UI 之前处理身份验证。 首先,您可以在静态 json 文件中定义每个客户的自定义数据,例如

/assets/
  ⊢customer1.json
  ⊢customer2.json
  ⊢...
  ⨽customerN.json

但是每次您需要修改配置或添加新客户时,都需要代码 change/build/deployment。一种更灵活的方法是在 API 中提供一个简单的配置端点,例如GET /config 将从数据库中加载给定 user/customer 的自定义配置(基于您随请求发送的身份验证)。这样您就可以自由添加和修改自定义设置,而无需重新部署您的前端应用程序 - 甚至让客户自己调整设置并保存。

让我们看一些代码:

你没有提到,你如何确定当前用户属于哪个客户,或者你如何处理授权,所以你需要填补空白:

/*
Let say we have a simple config object, that contains our customizations
*/
export class CustomerConfig {
  columnOrder: string;
  someOtherCustomization: string;
}

@Injectable()
export class ConfigurationService {
   //this is the config you can then use in your components 
   config: CustomerConfig 

   constructor(private http: HttpClient) {}

   public init() : Observable<CustomerConfig > {
      //somehow validate and obtain the current User
      //for example injecting your Auth service or whatever you use
      //for demo purposes just a constant
      const customerId = 'foobar'
      return http.get(`/assets/${customerId}.json`)
         .pipe(
            tap(configFromFile => this.config = configFromFile )
          ) 
      //or, if you have a `/config` API endpoint then just
      //return http.get(`/api/config`)....
      //of course, you'll need to add your error handling, defaults etc...
   }

}

现在是初始化程序(在您的根模块中):

/*
Our initializer factory returning initializer function. 
We can inject dependencies/services that we declared bellow in the provider def 
Angular will block initialization of this module until the return observable(or promise) completes
*/
function initializeAppFactory(configService: ConfigurationService): () => Observable<any> {
  return () => configService.init();
}

@NgModule({
 imports: [BrowserModule],
 declarations: [AppComponent],
 bootstrap: [AppComponent],
 providers: [{
   provide: APP_INITIALIZER,
   useFactory: initializeAppFactory, 
   multi: true, //there can be more than 1 initializer fn
   deps: [ConfigurationService] //dependencies available to our initializer fn
  }]
 })
export class AppModule {}

现在您可以在需要读取自定义数据的任何组件中注入 ConfigurationService