基于环境变量更新 config.json 的预构建脚本

Posted

技术标签:

【中文标题】基于环境变量更新 config.json 的预构建脚本【英文标题】:pre-build script to update config.json based on the environment variable 【发布时间】:2020-10-05 11:44:17 【问题描述】:

我有一个 Angular 9 应用程序,我在其中从资产文件夹中读取 api url:

@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()`);
    
  

读取配置文件的方法见Configuring angular production files after build。

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) 读入对象并根据源environment 对象更新config.json。我怎样才能做到这一点?

【问题讨论】:

所以你从environment.ts 的环境特定值构建你的config.json,然后修改一些值?为什么不使用来自 environment.ts 的构建时间值和来自 config.json 的值作为动态值? 我使用环境值来创建default config.json files,它将进入准备分发的安装程序。我需要有两个不同的构建,这就是为什么我把它们放在不同的文件中。 为什么不同时使用environments 和config.json 进行url 配置?您可以通过environment 提供默认的url,同时允许最终用户更改config.json 中的url 更改属性? @Sergey,用户已经可以手动编辑 config.json。挑战是根据问题中描述的不同构建将默认值从 environment.xxx.ts 文件复制到 config.json 中。我希望在运行 ng build --prod --configuration=xxx 之类的内容时自动将默认值复制到 config.json 文件中 @MHOOS 为什么不适合您在config.json 中将此属性留空?因此,在您的配置服务中,如果不是通过config.json 提供的,则使用来自environment 的url。使用config.json 看起来很简单,不需要额外的操作 【参考方案1】:

将预构建脚本更改为:

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/",

希望这会有所帮助。

【讨论】:

我使用 ng lint 构建项目。话虽如此,让我们调用上面的文件配置 update-config.js。我需要对我的 package.json 进行哪些更改才能在 ng build --prod 之前自动运行 update-config.js ?我将 package.json 的脚本部分添加到问题中,以防有帮助。 我没能成功。正如你提到的,我的环境是 Windows。我也创建了 .npmrc 文件。此外,我的脚本部分与您的相匹配。然而,当我运行npm run build-prod 时,我得到'CONFIG' is not recognized as an internal or external command。显然 Config 没有定义。现在,我应该在 Windows 命令提示符的哪里定义这个 CONFIG? @MHOOS CONFIG=prod 实际上是 bash 初始化它的地方。你得到的错误是我们在不使用 bash 时得到的,所以你只需要修复它。 1) 确保在您的系统中安装了 bash (git for windows 应该安装它) 2) 如果您有它,您可以尝试使用 bash 的完整路径更改 .npmrc 文件中的字符串 bash。 exe 可执行文件 3)如果仍然无法正常工作,您可以使用 bash.exe 可执行文件的实际路径尝试此命令npm config set script-shell "C:\\Program Files\\git\\bin\\bash.exe"(注意这是一个全局设置)4)询问谷歌;) 您可以尝试将utf8 作为encoding 参数添加到readFilewriteFile 函数。不,我没有测试过 我更新了我的问题,你可以查看进度。现在我设法读取环境的内容,但我仍然不知道如何忽略导入部分并仅读取环境对象本身。【参考方案2】:

根据您在更新的帖子和 cmets 中指出的内容,您想要实现的目标是不可能的。

基本上,您想将对象 (environment) 值复制到 json 文件中,但该对象从其他地方导入了一些值

所以你有这样的东西

somewhere.ts

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 的值只有在 angular.json 配置中启用 buildOptimizer 时才会被解析,如下所示:

使用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 中的代码被缩小/丑化了,我怀疑您是否能够解析/提取上面的配置值...

因此要么删除所有导入(使用硬编码值)并使用 Daniele Ricci 的答案,要么手动创建您的 json 文件。

注意

我不完全理解你这样做的原因,但我的感觉是你应该在你的代码中使用:

来自environment.ts 的值用于构建后不会更改的值 来自config.json 的值,用于在构建后可以更改的值

【讨论】:

您的回答很有见地。最后两个要点是使用混合配置的确切原因(同时使用 environment.xxx.ts 和 config.json)。 是的,我建议这样做

以上是关于基于环境变量更新 config.json 的预构建脚本的主要内容,如果未能解决你的问题,请参考以下文章

Java详解:docker环境变量写入config.json

在 Android NDK 项目中使用我自己的预构建共享库

使用环境变量进行本地 sequelize 配置

如何在 Jenkins/Hudson 中以编程方式设置环境变量?

云环境下如何处理 Whisper 的预分配?

Maven基础