在生产构建中访问环境变量 Angular 4

Access environment variables in production build Angular 4

我想使用可配置的 api url 部署 angular 应用程序的生产版本供用户测试。我使用 environment.ts 但是在生产构建之后,我不知道如何配置变量。

需要采取什么方法?

您在使用 Angular-CLI 吗?那应该很容易吧。你有这样的东西:

src/
  app/
  environment/
    environment.ts
    environment.prod.ts

只需将不同的 url 放入 environment.prod.ts 中,您的产品构建就会获得第二个 url。例如。假设您的 environment.ts 看起来像这样:

{
  "production": false,
  "apiUrl": "http://localhost:8080"
}

将此放入 environment.prod.ts:

{
  "production": true,
  "apiUrl": "https://example.com/api"
}

您可以设置更多环境,检查 .angular-cli.json 和 angular-cli 存储库的那部分。

编辑: 根据您的评论,您想要更多。

Yes but still this is not configurable after the build isn't it? Because I don't know what url the user want to use therefore I want to make it configurable from the outside after deploying the build.

让我们继续这个场景。让我们有一个后端客户端:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { apiUrl } from '../environment/environment.ts';
@Injectable()
export class BackendService {
    backendUrl: string = apiUrl;      

    constructor(private httpClient: HttpClient) {}

    get(endpoint: string, params: any): Observable<any> {
      const url= `${this.backendUrl}/${endpoint}`;
      return this.httpClient.get(url, params);
    }
}

已简化,但有效。默认情况下,您可以设置自己的 URL。但是您的组件可以即时设置 url,并从中获取其他内容 url。

现在,下一步是提供您拥有的后端。这可以是一个预先配置的数组,也可以让客户端自由输入 url(简单的输入框)。您可以有一个组件来执行此操作,并在此处配置此服务。您可能还应该为 "proper" 后端提供单独的服务,例如你的身份是谎言。但这完全取决于您的情况。

  • 将你的配置放在资产文件夹中的 ts 文件中
  • 就像您正在获取 environment.ts 一样,获取该文件并使用其配置
  • 资产文件夹的内容没有最小化,因此它们也可以在生产构建中配置

环境*.ts 文件包含构建时配置,构建后无法更改。如果您需要在构建后更改您的配置,您需要将它们放在不同的地方并在应用程序启动时动态检索它们

您可以做的是:

步骤 #1:将您的 json 配置文件放在 src/assets/config/[envName].json.

注意:必须是json格式,不是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 production: boolean;
  readonly name: string;

  readonly apiBaseUrl: 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) => {

      let confName = environment.name + '.json';
      this.http.get('/assets/config/' + confName).map(res => res as any).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:修改模块提供者以添加此 供应商:[ …

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


],

第 5 步:在您的代码中,不要使用 environment.configXXX,而是使用此

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

//…
return APP_CONFIG.configXXX;

这是一个简化的示例,如果您使用 angular universal,您实际上需要进行一些更改,因为在进行 http 调用时需要有绝对 url

我们真的需要APP_INITIALIZER加载动态环境变量吗

嗯,除非我们需要一些异步调用来获取它们。否则我会建议:

env.js

(function (window) {
  window._env = window._env || {};
  window._env.url= 'http://api-url.com';
}());

index.html

<head>
  <script src="env.js"></script>
</head>
<body>
  <app-root></app-root>
</body>

最后在angular.json

中加上
"assets": [
              "any/env.js",

现在您只需使用应用程序中的一项服务即可阅读 window