首页 > 解决方案 > 如何外部化 Angular 7 应用程序的属性值?

问题描述

我有一个 Angular 7 应用程序,其中的app.module.ts文件如下所示。请注意,在此示例中,有 2 个模块,每个模块都有 1 个键,其值需要外部化。externalized我的意思是应该在运行时从环境中获取值。

@NgModule({
 declarations: [ ... ],
 imports: [
  SomeModule.forRoot({ apiKey1: "needs to be externalized" }),
  AnotherModule.forRoot({ apiKey2: "needs to also be externalized" })
 ],
 providers: [ ... ],
 bootstrap: [AppComponent]
})
export class AppModule { }

我所做的是构建这个应用程序(例如ng build,然后使用 Docker 将其容器化)。在部署时,该DevOps人希望按如下方式运行 docker 容器。

docker run -e API_KEY_1='somekey' -e API_KEY_2='anotherkey' -p 80:80 my-container:production

请注意,API_KEY_1应该映射到apiKey1并且API_KEY_2应该映射到apiKey2

是否有任何规范的方法可以将 Angular 应用程序的值外部化?

我考虑过编写一个帮助脚本来对文件进行字符串替换,但我认为这种方法不是很规范(因为转译的 Angular 应用程序文件被混淆和缩小了)。该脚本将在容器启动时运行,读取环境变量(键和值),然后查看文件以将旧值替换为环境中的值。

最终,Angular 应用程序将与 Kubernetes 进行编排。我想知道是否有任何东西可以帮助或影响如何以最佳实践方式将价值观外化。

任何帮助表示赞赏。

标签: angulardockerkubernetesproperties-file

解决方案


您可以在自定义入口点中使用替换。

FROM nginx

RUN apt-get update && apt-get -y install gettext-base nginx-extras

ADD docker-entrypoint.sh /
ADD settings.json.template /

COPY dist /usr/share/nginx/html

ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

docker-entrypoint.sh这样:

#!/bin/bash

envsubst < "settings.json.template" > "settings.json"
cp settings.json /usr/share/nginx/html/assets/

# Launch nginx
exec "$@"

还有一个settings.json.template

{
  "apiKey2": "$API_KEY_2",
  "apiKey1": "$API_KEY_1"
}

然后在您的来源上添加一个文件 settings-loader.ts

export const settingsLoader = new Promise<any>((resolve, reject) => {
  const xmlhttp = new XMLHttpRequest();
  const method = 'GET';
  const url = './assets/settings.json';

  xmlhttp.open(method, url, true);

  xmlhttp.onload = function() {
    if (xmlhttp.status === 200) {
      const _environment = JSON.parse(xmlhttp.responseText);
      resolve(_environment);
    } else {
      resolve();
    }
  };

  xmlhttp.send();
});

在你的main.ts

import {enableProdMode} from '@angular/core';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';

import {AppModule} from './app/app.module';
import {environment} from './environments/environment';
import {settingsLoader} from 'settings-loader';

settingsLoader.then((settings) => {
  if (settings != null) {
    environment.settings = Object.assign(environment.settings, settings);
  }

  if (environment.production) {
    enableProdMode();
  }

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

然后你应该可以访问你的代码

import {environment} from '../environments/environment';

console.log(environment.settings.apiKey1);

推荐阅读