基于环境变量更新 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
,它将进入准备分发的安装程序。我需要有两个不同的构建,这就是为什么我把它们放在不同的文件中。
为什么不同时使用environment
s 和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
参数添加到readFile
和writeFile
函数。不,我没有测试过
我更新了我的问题,你可以查看进度。现在我设法读取环境的内容,但我仍然不知道如何忽略导入部分并仅读取环境对象本身。【参考方案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