【问题标题】:Angular5: Deploying Angular application to multiple clientsAngular5:将 Angular 应用程序部署到多个客户端
【发布时间】:2020-02-10 18:31:48
【问题描述】:

我正在开发一个 Angular 应用程序,它是一种产品并部署到多个客户端。客户将采用这个 Angular 应用程序并将其托管在他们的服务器中。因此,服务的 url 对于客户端会有所不同。我见过谈论开发,产品的解决方案。但这不适用于这种情况。我正在寻找一个类似于 .net 配置文件的配置文件。我创建了一个单独的 app.config.ts 文件,但是在我构建时会构建它。我正在寻找一种解决方案,我可以将应用程序部署到任何客户端,而无需他们再次构建它。

import { InjectionToken } from "@angular/core";

export let APP_CONFIG = new InjectionToken("app.config");

export interface IAppConfig {
    apiEndpoint: string;
}

export const AppConfig: IAppConfig = {    
    apiEndpoint: "http://88.87.86.999/"
};

【问题讨论】:

  • Angular 应用程序是否会从与服务相同的服务器和端口托管/提供?还是会有所不同?
  • 它们会有所不同。如果它是相同的,那么我可以很容易地得到托管的 url.. :)
  • 问题是 Angular 应用程序将在客户端的浏览器中运行,因此需要在每个客户端上发送或存储任何配置。我不确定你会怎么做?不幸的是,在构建时需要知道服务器地址。我唯一能想到的就是将其部署为Docker容器,并让客户在启动容器时提供服务器地址作为参数?

标签: angular angular-cli angular5


【解决方案1】:

你可以做什么它在assets文件夹中以json格式托管配置文件并动态检索它。您需要确保在应用程序启动之前检索它,这样它就可以在需要时在组件/服务中使用。为此,您可以使用 APP_INITIALIZER 令牌

步骤#1:将你的json配置文件放在src/assets/config/conf.json下(json格式,不是ts格式,因为prod模式下没有TS编译器)

第 2 步:添加新的配置服务

import {Inject, Injectable} from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {Observable} from 'rxjs/Rx';
import {environment} from "../../environments/environment";

/**
 * Declaration of config class
 */
export class AppConfig
{
//Your properties here
  readonly apiEndpoint: string;
}

/**
 * Global variable containing actual config to use. Initialised via ajax call
 */
export let APP_CONFIG: AppConfig;

/**
 * Service in charge of dynamically initialising configuration
 */
@Injectable()
export class AppConfigService
{

  constructor(private http: HttpClient)
  {
  }

  public load()
  {
    return new Promise((resolve, reject) => {

      this.http.get('/assets/config/config.json').catch((error: any): any => {
        reject(true);
        return Observable.throw('Server error');
      }).subscribe((envResponse :any) => {
        let t = new AppConfig();
        //Modify envResponse here if needed (e.g. to ajust parameters for https,...)
        APP_CONFIG = Object.assign(t, envResponse);
        resolve(true);
      });

    });
  }
}

第 3 步:在您的主模块中,在声明模块之前添加此内容

/**
* Exported function so that it works with AOT
* @param {AppConfigService} configService
* @returns {Function}
*/
export function loadConfigService(configService: AppConfigService): Function 

{
  return () => { return configService.load() }; 
}

步骤#4:修改模块提供程序以添加此

providers: [
  …

  AppConfigService,
  { provide: APP_INITIALIZER, useFactory: loadConfigService , deps: [AppConfigService], multi: true },


],

第 5 步:在您的代码中,使用配置

import {APP_CONFIG} from "../services/app-config.service";

//…
return APP_CONFIG.configXXX;

现在,您可以将应用发送给多个客户;每个客户端只需要在 conf.json 文件中有他们的特定参数

【讨论】:

  • 唯一的问题是,客户端的用户只需执行 http:url/assets/config.json.. 即可轻松访问 conf.json 文件。
  • 这是怎么回事?即使配置完全打包到构建中,它仍然可以访问,因为最终它只是客户端 JS 代码。也许在 json 文件中检索一个加密的配置,以使其稍微难以查看这些值,但我不确定没有意义
  • 这会比将配置属性保存在环境文件中更好吗?
  • @bubble 如果它保存在环境文件中,那么您必须为每个客户端构建一个版本。使用这种方法,您可以拥有与部署到每个客户端相同的构建,只需更改配置文件
  • 感谢@David 的详细解释。但是,我们在引导我们的应用程序时遇到了使用 AppConfigService 的问题,因为某些根模块需要在引导时传递设置,并且该服务仅在引导后运行。例如 AuthModule.forRoot(appConfig)
【解决方案2】:

为了使配置在初始时加载并在引导 AppModule 时使用它,我们在 ma​​in.ts 中使用了这个简单的解决方案。

注意我们排队

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

在等待获取配置文件的异步函数中。

(async () => {

  // console.time()
  const response = await fetch('./assets/config/conf.json');
  const json = await response.json();
  Object.entries(json).forEach(([key, value]) => {
    environment[key] = value;
  });
  // console.timeEnd()

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

})();

配置文件位于资产中,并相应地被部署作业替换。

意味着我们有基于环境的配置:

  • config.json
  • config.qa.json
  • config.prod.json

我们的获取时间大约需要 40 毫秒(几乎不需要。取消注释 console.time 以检查您自己项目中的估计值)。我怀疑它会在任何项目上消耗太多时间,因为它是从本地文件中获取的。祝你好运!

【讨论】:

  • 小补充:如果您需要将这些环境变量传递给 AppModule 中的提供程序,您可以使用useFactory。更多详情here
  • 我还需要在引导之前注入变量。所以非常感谢这个解决方案。此外,我喜欢这种方法,因为它仍然可以运行 ng build --prod 等。
猜你喜欢
  • 1970-01-01
  • 2019-07-17
  • 2019-10-06
  • 2015-10-17
  • 2019-07-18
  • 2018-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多