在npm脚本中使用空格*设置环境变量的跨平台方式

时间:2020-08-14 21:17:16

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

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

  "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"
  }
}

1 个答案:

答案 0 :(得分: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.json scripts部分中,重新定义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变量。

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

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

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

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

    • shell选项设置为true

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