typescript - Åtkomst till miljövariabler i produktionsbygget Angular 4


Jag vill distribuerar en produktionsbyggd Angular-app med en konfigurerbar API-URL för användaren att testa den. Jag använder environment.ts men efter produktionsbyggnaden vet jag inte hur jag ska konfigurera variablerna.

Vilket tillvägagångssätt behöver göras?

Svar #1

Filen environment*.ts innehåller konfigurationer för byggtid, som du inte kan ändra efter byggandet. Om du behöver ändra din konfiguration efter byggandet måste du lägga dem på en annan plats och hämta dem dynamiskt när applikationen startar

Det du kan göra är:

Steg #1: placera dina JSON-konfigurationsfiler under src/assets/config/[envName].json.

Observera: det måste vara i json-format, inte ts-format

Steg #2: Lägg till en ny konfigurationstjänst

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);
      });

    });
  }
}

Steg #3: I din huvudmodul, lägg till detta innan du deklarerar modulen

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

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

Steg #4: Modifiera modulens leverantörer för att lägga till detta providers: [ …

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


],

Steg 5: I din kod, istället för att använda environment.configXXX, använd detta

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

//…
return APP_CONFIG.configXXX;

Detta är ett förenklat exempel, du kommer faktiskt behöva göra några ändringar om du använder Angular Universal eftersom du behöver ha absoluta URL:er när du gör ett HTTP-anrop

Svar #2

Använder du Angular-CLI? Det borde vara lätt då. Du har något som detta:

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

Sätt helt enkelt in en annan URL i environment.prod.ts och din produktionsbygg får en andra URL. T.ex. låt oss säga att din environment.ts ser ut så här:

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

Sätt detta i environment.prod.ts:

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

Du kan ställa in fler miljöer, kolla den sektionen av .angular-cli.json och angular-cli-repot.

Redigera: Enligt din kommentar vill du ha mer.

Ja men ändå går detta inte att konfigurera efter bygget, eller hur? Eftersom jag inte vet vilken URL användaren vill använda vill jag därför göra det konfigurerbart från utsidan efter att ha distribuerat bygget.

Låt oss fortsätta detta scenario vidare. Låt oss ha en backend-klient:

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);
    }
}

Förenklat, men fungerar. Som standard ställer du in din egen URL. Men dina komponenter kan ange URL:en direkt och hämta andra saker från den URL:en.

Nu skulle nästa steg vara att erbjuda vilka backends du har. Detta kan vara en förkonfigurerad lista, eller så kan du låta klienten ange URL:en fritt (enkel inmatningsruta). Du kan ha en komponent som gör det och konfigurerar den här tjänsten. Du borde nog också ha en separat tjänst för din "riktiga" backend, där till exempel din autentisering finns. Men allt detta beror verkligen på ditt scenario.

Relaterade artiklar