【问题标题】:Cross-platform way to set environment variables *with spaces* in npm scripts在 npm 脚本中使用空格*设置环境变量的跨平台方法
【发布时间】:2020-12-04 18:37:41
【问题描述】:

我正在开发一个无服务器 NodeJS 应用程序,需要在离线模式下对其进行测试。我在package.json 文件中有一个npm 脚本,如下所示:

  "scripts": {
    "serve": "cross-env AUTHORIZER='{\\\"claims\\\":{\\\"permissions\\\":\\\"[view:accounts manage:accounts]\\\",\\\"sub\\\":\\\"auth0|5cfe0adce3c4c50ea072ea9f\\\"}}' AWS_PROFILE=elit_nonprd serverless offline start -s dev --noAuth",
...

请注意,有两个权限需要用空格分隔。在 Windows 上运行 npm run serve 会出现以下错误:

> @mypackage@1.0.0 serve C:\path
> cross-env AUTHORIZER='{\"claims\":{\"permissions\":\"[view:accounts manage:accounts]\",\"sub\":\"auth0|5cfe0adce3c4c50ea072ea9f\"}}' AWS_PROFILE=elit_nonprd serverless offline start -s dev --noAuth

The filename, directory name, or volume label syntax is incorrect.
events.js:288
      throw er; // Unhandled 'error' event
      ^

Error: spawn manage:accounts]","sub":"auth0|5cfe0adce3c4c50ea072ea9f"}} ENOENT
    at notFoundError (C:\path\node_modules\cross-spawn\lib\enoent.js:6:26)
    at verifyENOENT (C:\path\node_modules\cross-spawn\lib\enoent.js:40:16)
    at ChildProcess.cp.emit (C:\path\node_modules\cross-spawn\lib\enoent.js:27:25)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:275:12)
Emitted 'error' event on ChildProcess instance at:
    at ChildProcess.cp.emit (C:\path\node_modules\cross-spawn\lib\enoent.js:30:37)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:275:12) {
  code: 'ENOENT',
  errno: 'ENOENT',
  syscall: 'spawn manage:accounts]","sub":"auth0|5cfe0adce3c4c50ea072ea9f"}}',
  path: 'manage:accounts]","sub":"auth0|5cfe0adce3c4c50ea072ea9f"}}',
  spawnargs: [
    'AWS_PROFILE=elit_nonprd',
    'serverless',
    'offline',
    'start',
    '-s',
    'dev',
    '--noAuth'
  ]
}

如果我将cross-env 替换为cross-env-shell,也会发生这种情况,尽管没有显示堆栈跟踪。

当值包含空格时,是否有一种通用的跨平台设置环境变量的方法?

更新:我希望的结果是将AUTHORIZER 设置为以下值(感谢@RobC 要求澄清):

{
  "claims":
  {
    "permissions": "[view:accounts manage:accounts]",
    "sub": "auth0|5cfe0adce3c4c50ea072ea9f"
  }
}

【问题讨论】:

标签: node.js npm environment-variables npm-scripts


【解决方案1】:

实现跨平台兼容性是个难题。经过几次失败的尝试后,似乎无法使用 cross-env 的单一语法:

Windows (cmd) 与下面的 worksOnWin 示例一起成功,*Nix (sh) 与下面的 worksOnNix 示例一起成功。

{
  "scripts": {
    "worksOnWin": "cross-env AUTHORIZER={\\\"claims\\\":{\\\"permissions\\\":\\\"\"[view:accounts manage:accounts]\"\\\",\\\"sub\\\":\\\"auth0|5cfe0adce3c4c50ea072ea9f\\\"}} AWS_PROFILE=elit_nonprd serverless offline start -s dev --noAuth",
    "worksOnNix": "cross-env AUTHORIZER=\"{\\\"claims\\\":{\\\"permissions\\\":\\\"[view:accounts manage:accounts]\\\",\\\"sub\\\":\\\"auth0|5cfe0adce3c4c50ea072ea9f\\\"}}\" AWS_PROFILE=elit_nonprd serverless offline start -s dev --noAuth",
  }
}

解决方案

为了满足您对单一语法跨平台的要求,我会考虑使用 node.js 脚本来代替。

  1. 将此serve.js 脚本(如下)保存在项目目录的根目录中,即将它保存在 package.json 所在的同一级别。

    serve.js

    const spawn = require('child_process').spawn;
    
    const processEnv = process.env;
    
    processEnv.AUTHORIZER = '{"claims":{"permissions":"[view:accounts manage:accounts]","sub":"auth0|5cfe0adce3c4c50ea072ea9f"}}';
    processEnv.AWS_PROFILE = 'elit_nonprd';
    
    spawn('serverless', ['offline', 'start', '-s', 'dev', '--noAuth'], {
      env: processEnv,
      stdio: 'inherit',
      shell: true
    });
    
  2. package.jsonscripts 部分重新定义 serve 脚本,如下所示:

    package.json

    {
      ...
      "scripts": {
        "serve": "node serve"
      }
      ...
    }
    
  3. 运行以下命令:

    npm run serve
    

说明

下面解释了 serve.js 中发生的事情:

  • 首先我们需要child_process模块的spawn()方法。

  • 读取的部分;

    const processEnv = process.env;
    
    processEnv.AUTHORIZER = '{"claims":{"permissions":"[view:accounts manage:accounts]","sub":"auth0|5cfe0adce3c4c50ea072ea9f"}}';
    processEnv.AWS_PROFILE = 'elit_nonprd';
    

    使用process.env 获取现有环境变量,并将它们分配给processEnv 变量。

    随后,我们用AUTHORIZERAWS_PROFILE 属性及其必要的值来扩充processEnv 对象。这实质上定义了两个新的环境变量。

  • 最后我们通过child_process.spawn()“shell out”serverless offline start -s dev --noAuth 命令。

    • { env: processEnv } 部分将child_process.spawnenv 选项设置为processEnv 对象,即它为子进程设置环境变量。

    • stdio 选项为子进程中的 stdin、stdout、stderr 配置管道。这可确保您在控制台中获得任何日志记录。

    • shell 选项设置为true

注意:使用此解决方案,cross-env 包变得多余。

【讨论】:

  • 精彩的回答和解释,@RobC - 非常感谢!我还针对cross-env here 提出了针对此问题的错误,因为我相信该软件包旨在能够处理带有空格的值。
猜你喜欢
  • 2016-01-24
  • 1970-01-01
  • 1970-01-01
  • 2019-03-10
  • 2020-04-05
  • 2011-12-06
  • 2018-02-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多