跨平台传递环境变量作为npm脚本参数的方法

5

无论是在 Windows 还是 Linux 上,我希望有一种方法可以将参数传递给 npm script,但是这些参数应该作为环境变量注入。

从命令行开始,我会以以下方式启动我的项目:

npm run start -- --env=dev --host=localhost --port=1234

为了在任何平台上都能够使用我的命令行参数并将它们注入到环境变量中,我使用了cross-env npm包:

package.json

  "scripts": {
    "start": "cross-env env=%env% host=%host% port=%port% my-app"
  },

我知道上面的语法是无效的,但是那个 start 脚本能否以某种方式使用我传递的参数,而不是将它们转发到 my-app
1个回答

5
很遗憾,npm不提供(也没有打算提供)内置功能,允许在npm脚本的中间传递参数(如此处所述)。参数只能传递到脚本的末尾。
对于Linux和macOS,您可以在npm脚本中使用bash函数来将参数传递到脚本的中间,就像我的回答这里一样。但是,Windows会阻塞此类解决方案。
由于跨平台兼容性是一项要求,请考虑将当前位于您的start脚本中的逻辑移动到单独的nodejs实用程序脚本中。然后可以通过名为start的npm脚本来调用nodejs脚本。
以下描述了如何以跨平台兼容的方式实现您的要求。

1. 自定义nodejs实用程序脚本。

创建一个nodejs脚本,如下所示。我们将脚本命名为start.js,并将其保存在项目目录的根目录中,即package.json文件所在的同一级别。

const execSync = require('child_process').execSync;

const args = process.argv.splice(2, process.argv.length - 2)
    .map(arg => arg.replace(/^--/, ''));

execSync(`cross-env ${args.join(' ')} my-app`, {stdio:[0, 1, 2]});

解释:

  1. In the first line we require nodes builtin execSync(). We'll utilize this to run cross-env and set the environment variables.

  2. Nodes builtin process.argv obtains the arguments passed via the command-line. The first two items in nodes process.argv are:

    • The path to the executable running the JavaScript file.
    • The path of the JavaScript file being executed.
  3. However, we're only interested in the elements from the third item in the array onwards - as these will be your arguments passed via the CLI. These lines which read;

    const args = process.argv.splice(2, process.argv.length - 2)
        .map(arg => arg.replace(/^--/, ''));
    

    create an args variable and assigns an Array containing each argument passed via the CLI. The first two aforementioned items in point 2 are omitted from the array using the splice() method. In the map() method we remove the -- prefix from each argument.

  4. The last line reading:

    execSync(`cross-env ${args.join(' ')} my-app`, {stdio:[0, 1, 2]});
    

    invokes cross-env and places the arguments as a string using Template Literals and the Array join() method. The stdio part configures the pipes for stdin, stdout, stderr in the child process.

注意: 如果你的目标是更老版本的node,不支持模板字符串,那么可以使用以下代码替换此行。这将使用+操作符来处理字符串连接:

execSync('cross-env ' + args.join(' ') + ' my-app', {stdio:[0, 1, 2]});

同样地,如果不支持ES6箭头函数,请将map()更改为使用标准函数。例如:
.map(function(arg) {
  return arg.replace(/^--/, '');
});

2. package.json脚本。

package.json中的start脚本更改为以下内容:

"scripts": {
  "start": "node start"
},

这里我们要求Node调用start.js脚本。

注意如果你更喜欢将start.js文件保存在与项目根目录不同的目录位置中,则需要根据需要定义start.js的路径。路径应相对于package.json。例如:

"scripts": {
  "start": "node ./the/path/to/start"
},

3. 运行npm脚本

可以通过在命令行中运行npm start脚本来调用它:

$ npm start -- --env=dev --host=localhost --port=1234

run 部分,即 npm run start ... 在调用 npm 的 start 脚本时不是必需的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接