在 npm 脚本中将节点环境变量设置为动态值



我想在npm脚本中动态设置一个环境变量。

我在Windows上开发时正在使用cross-env,并且服务器是基于Unix的。我想用当前日期(new Date()(初始化一个环境变量,以便我可以在我的create-react-app中访问和渲染它:

这有效(硬编码字符串(:

"scripts": {
"start": "cross-env-shell REACT_APP_BUILD_DATE="currentDate" react-scripts-ts start",
}

显然,currentDate不应该是一个字符串,而应该是以下表达式的结果:new Date()

我怎样才能做到这一点?换句话说:如何评估一些常规的JavaScript并将其结果用作npm脚本?还是这是不可能的?

我正在使用简单的节点脚本将环境变量传递到调用的脚本中。它使用 child_process.execSync。

// File name: ./build.js
/* eslint-env node */
const execSync = require('child_process').execSync;
const env = Object.create(process.env);
env.REACT_APP_BUILD_DATE= Date.now();
console.log('Used env variables: ' + JSON.stringify(env));
console.log('Run command: react-scripts start');
execSync('react-scripts-ts start', { env: env, stdio: 'inherit' });

更新 package.json 脚本中的启动命令,如下所示:

"scripts": {"start": "node ./build.js"}

仅供记录,我现在使用以下方法:将当前日期写入 package.json 中的自定义属性,并通过导入package.json在应用程序中读取该值

包.json

"scripts": {
"start": "react-scripts-ts start",
"build": "node ./update-packagejson.js && react-scripts-ts build"
}

update-packagejson.js

const fs = require("fs");
const filePath = "./package.json";
const packageJson = JSON.parse(fs.readFileSync(filePath).toString());
packageJson.ngrvd.buildDate = new Date().toUTCString();
fs.writeFileSync(filePath, JSON.stringify(packageJson, null, 2));

元件

import { ngrvd, version } from "../../package.json";
// ... 
private static getAppInfo(): string {
const buildDate = process.env.NODE_ENV === "development" ? new Date() : ngrvd.buildDate;
return "Version " + version + "  - Built " + moment(buildDate).fromNow();
}

这适用于任何环境,简单易懂,并且可以扩展以包含其他信息。在开发模式下,我不会写信给package.json以防止每次都进行本地更改。

例如,您希望将构建时间放在 reactjs 应用程序上。 像这样编辑package.json

"scripts": {
"start": "REACT_APP_BUILD_TIME=$(date +%s) react-app-rewired start",
"build": "REACT_APP_BUILD_TIME=$(date +%s) react-app-rewired build"
}

您可以在public/index.html文件中使用REACT_APP_BUILD_TIME变量。例如:

<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico?%REACT_APP_BUILD_TIME%" />

必须用%字符包装 env 变量。还有另一个规则:您必须将REACT_APP_添加到 env 变量中。您不能添加其他环境变量来反应应用程序。

如何将所有.env变量添加到 reactjs 应用程序?

您可以使用env-cmd包。

yarn add env-cmd

"scripts": {
"start": "REACT_APP_BUILD_TIME=$(date +%s) ./node_modules/.bin/env-cmd react-app-rewired start",
"build": "REACT_APP_BUILD_TIME=$(date +%s) ./node_modules/.bin/env-cmd react-app-rewired build"
}

示例.env内容:

REACT_APP_NAME="My React App"
REACT_APP_API_ENDPOINT=https://127.0.0.1:8080/api
REACT_APP_SOCKETIO_ENDPOINT=http://127.0.0.1:3333

之后,您可以将这些变量添加到public/index.html文件中,如下所示:

<script>
window.env.REACT_APP_NAME = "%REACT_APP_NAME%";
window.env.REACT_APP_API_ENDPOINT = "%REACT_APP_API_ENDPOINT%";
window.env.REACT_APP_SOCKETIO_ENDPOINT = "%REACT_APP_SOCKETIO_ENDPOINT%";
</script>

在 reactjs 端,你可以像这样使用这些变量:

alert(window.env.REACT_APP_SOCKETIO_ENDPOINT);

就这样。

编辑:通常没有此属性:window.env,但我们现在设置它以方便使用。您可以将 env 变量分配给index.html文件中的任何位置。

在这种特殊情况下,你最好使用 shell 命令而不是 JavaScript,所以它应该是这样的:

"scripts": {
"start": "cross-env-shell REACT_APP_BUILD_DATE=$(date '+%F %H:%M:%S') react-scripts-ts start",
}

我会创建一个自定义的javascript脚本来为你做这件事:

执行.js

var spawn = require('child_process').spawn;
// because first arg will actually be something like "./execute.js"
// this is the "regular javascript" you want to evaluate
var arg1 = process.argv[1];
// so lets eval it
var res = eval(arg1);
// this is the remaining args, that is the command you want to run (and its args)
var command = process.argv[2];
var commandArgs = process.argv.slice(3);
// if arg1 evaluation resulted in a value, append this value to the list of args
if (res) {
commandArgs.push(res);
}
// execute the command
var prc = spawn(command, commandArgs);

您的脚本定义将变为:

"scripts": {
"start": "cross-env-shell ./execute.js "process.env.REACT_APP_BUILD_DATE = new Date();" react-scripts-ts start",
}

或类似的东西。

这是未经测试的,但应该让你开始一个解决方案,">评估一些常规的JavaScript并使用它的结果一个npm脚本">

但是,如果您只想在 env 变量中设置日期,则 @bredikhin 的解决方案更好。

处理环境变量的替代解决方案

如果您有能力在项目的根目录下写入.env文件(手动或编程(,则可以使用 dotenv 用它填充环境变量(来自 dotenv 文档(:

// Usage
// As early as possible in your application, require and configure dotenv.
require('dotenv').config()
/* Create a .env file in the root directory of your project. Add environment-specific variables on new lines in the form of NAME=VALUE. For example:
DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3
That's it.
process.env now has the keys and values you defined in your .env file.
*/
const db = require('db');
db.connect({
host: process.env.DB_HOST,
username: process.env.DB_USER,
password: process.env.DB_PASS
});

最新更新