сценарий предварительной сборки для обновления config.json на основе переменной среды

У меня есть приложение angular 9, в котором я читаю URL-адрес api из папки ресурсов:

@Injectable()
export class ConfigService {

  private configUrl = '../../../assets/config/config.json';

  constructor(private loggerService: LoggerService) { }

  public async loadConfig(): Promise<any> {
    try {
      const response = await fetch(this.configUrl);

      if (!response.ok) {
        throw new Error(response.statusText);
      }

      return await response.json();
    } catch (err) {
      this.loggerService.error(`ConfigService 'loadConfig' threw an error on calling ${this.configUrl} : ${err.tostring()}`);
    }
  }
}

Метод, используемый для чтения файла конфигурации, описан в разделе Настройка производственных файлов angular после сборки.

environment.ts является

export const environment = {
  production: false,
  apiUrl: "https://localhost/api/",
};

environment.prod.ts является

export const environment = {
  production: true,
  apiUrl: "https://server/api/",
};

config.json является

{
  "apiUrl": "http://someTestServer/api/"
}

Неполный скрипт для копированияapiUrl к config.json

var fs = require("fs");
fs.readFile(`./src/environments/environment.${process.env.CONFIG}.ts`, 'utf8', function (err, data) {

  fs.writeFile('./src/assets/config/config.json', data, function (err) {
    if (err) throw err;
    console.log('complete');
  });
});

Мой раздел сценария package.json выглядит следующим образом:

  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "build-test": "CONFIG=test node update-config.js && npm run build",
    "build-prod": "CONFIG=prod node update-config.js && npm run predeploy",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "predeploy": "ng build --prod",
    "deploy": "node ftpdeploy.js"
  }

Учитывая вышесказанное: как я могу автоматически заполнять содержимое моего config.json файл на основе другой переменной среды до сборки, поэтому мне не нужно вручную копировать и вставлять файл json в \dist папка?

Обновление 1. Теперь я могу скопировать содержимое моего enviroment.xxx.ts в файл config.json. Осталась одна проблема: когда я копирую содержимое из environment.xxx.ts, он копирует все содержимое environment.xxx.ts в config.json (он также копирует раздел импорта моего enviroment.xxx.ts), однако ожидаемый результат - прочитатьenvironment (export const environment) в объект и обновите config.json в соответствии с источником environmentобъект. Как я могу этого добиться?

2 ответа

Изменение сценария предварительной сборки как:

const fs = require("fs");
fs.readFile(`/src/environments/${process.env.CONFIG}.ts`, (err, content) => {
  fs.writeFile("/src/assets/config/config.json", JSON.stringify(versionObject), () => { });
});

затем из командной строки (я предполагаю npm run build - это команда для сборки, в противном случае измените ее с помощью команды сборки):

$ CONFIG=environment npm run build

должен решить вашу проблему.

Редактировать:

"scripts": {
  "ng": "ng",
  "start": "ng serve",
  "build": "ng build",
  // add more lines as you need like this, one for each build environment
  "build-test": "CONFIG=test node update-config.js && npm run build",
  "build-prod": "CONFIG=prod node update-config.js && npm run predeply",
  "test": "ng test",
  "lint": "ng lint",
  "e2e": "ng e2e",
  "predeploy": "ng build --prod",
  "deploy": "node ftpdeploy.js"
},

Я заметил \ в вашем вопросе, вероятно, вы работаете под Windows, обязательно используйте bash: добавить файл с именем .npmrc только со следующей строкой script-shell=bash

Изменить: если вы хотите прочитать файл среды с помощьюfetch и проанализируйте его с помощью await response.json(), файл должен быть файлом json, а не файлом ts:

{
  production: true,
  apiUrl: "https://server/api/",
}

Надеюсь это поможет.

Судя по тому, что вы указали в своих обновленных сообщениях и комментариях, то, чего вы хотите достичь, невозможно.

По сути, вы хотите скопировать объект (environment) значение в файл json, но этот объект импортирует некоторые из своих значений из другого источника.

Итак, у вас есть что-то вроде этого

где-то.

export const constantValue = "myValue";

environment.xx.ts

import {constantValue} from "./somewhere";

export const environment = {
  production: false,
  apiUrl: "https://localhost/api/",
  otherValue: constantValue
};

Проблема: перед сборкой вы не можете получить доступ к значению дляconstantValue, поэтому вы не можете сделать его заранее подготовленным скриптом.

После сборки environment объект будет включен в main-es2015XXX.js. Однако значение дляotherValue будет разрешено только если вы включили buildOptimizer в вашем angular.json config, как показано ниже:

С buildOptimizer : false, значение еще не определено, оно будет во время выполнения. Таким образом, вы не можете использовать эти значения для записи своего файла json. Вenvironment переменная будет выглядеть так:

const environment = {
  production: false,
  apiUrl: "https://localhost/api/",
  otherValue: _somewhere__WEBPACK_IMPORTED_MODULE_0__["constantValue"]
};

С buildOptimizer : true, значение для констант можно определить во время сборки. Значение будет выглядеть так

const i={production:!1,apiUrl:"https://localhost/api/",otherValue:"myValue"}

Однако код в mainXXX.js минимизировано / искажено, и я сомневаюсь, что вы сможете проанализировать / извлечь указанное выше значение конфигурации...

Поэтому либо удалите весь импорт (используйте жестко закодированные значения) и используйте ответ Даниэля Риччи, либо вручную создайте свои файлы json.

Запись

Я не полностью понял вашу причину этого, но мне кажется, что в вашем коде вы должны использовать:

  • ценности из environment.ts для значений, которые не меняются после сборки
  • ценности из config.json для значений, которые могут измениться после сборки
Другие вопросы по тегам