【问题标题】:Pass command line args to npm scripts in package.json将命令行参数传递给 package.json 中的 npm 脚本
【发布时间】:2020-05-09 14:56:30
【问题描述】:

我的 package.json 中有以下脚本:

"scripts": {
    "vumper": "node node_modules/vumper/index.js",
    "format": "prettier --single-quote -width=80 --write package.json"
 },

“vumper”包接受命令行参数(例如“dv”)。我想做的是有一个命令可以连续运行这两个命令。

基本上,我希望能够运行:

npm run vumber dv

然后

npm run format

但在一个命令中,类似于

npm run my-build dv

它将运行上述两个命令,正确接受命令行参数“dv”并将其传递给第一个 npm run vumper。这可能吗?

【问题讨论】:

    标签: npm package.json npm-scripts


    【解决方案1】:

    简答:

    基本上,您想要的是有一个类似这样的 npm 脚本,其中 <arg-here> 是通过 CLI 提供的;

    ...
    "scripts": {
      "my-build": "npm run vumper <arg-here> && npm run format",
      ...
    },
    ...
    

    但是,不幸的是,npm 没有内置功能来实现这一点。

    特殊的 npm 选项 --,(有关此选项的更多信息,请参阅下面解决方案 1 的末尾),只能用于将参数传递给 END 的脚本,但不进入中间。因此,如果您的两个命令的顺序相反,则可以像这样使用 -- 选项:

    ...
    "scripts": {
      "my-build": "npm run format && npm run vumper --",
      ...
    },
    ...
    

    要克服没有内置功能将参数传递到脚本的 MIDDLE 的限制,请考虑以下解决方案:

    1. 对于仅 Bash 的解决方案,请参阅 “解决方案 1” 部分。

    2. 如果需要跨平台支持,请遵循“解决方案 2” 部分中描述的解决方案。


    解决方案 1 - Bash(MacOS/Linux/ 等)

    package.jsonscripts 部分中配置您的 my-build 脚本以调用 Bash shell function,如下所示:

    package.json

    ...
    "scripts": {
      "my-build": "func() { npm run vumper \"$1\" && npm run format; }; func",
      "vumper": "node node_modules/vumper/index.js",
      "format": "prettier --single-quote -width=80 --write package.json"
    },
    ...
    

    说明:

    名为 func 的 Bash 函数执行以下操作:

    1. 首先运行npm run vumper &lt;arg&gt;。其中&lt;arg&gt; 将是通过 CLI 传递的 shell 参数。它在脚本中使用$1 引用(即第一个positional parameter/argument)。
    2. 随后它通过命令npm run format 运行名为format 的脚本。

    这两个npm run 命令使用&amp;&amp; 运算符链接,因此第二个npm run format 命令只有在初始npm run vumper &lt;arg&gt; 命令成功完成时才会运行(即返回0 退出代码)。

    正在运行my-build 脚本:

    要通过 CLI 调用 my-build,您需要运行:

    npm run my-build -- dv
    

    注意:

    1. 在这种情况下,结尾的 dv 部分是将传递给您的 vumper 脚本的参数。

    2. 必须在参数之前指定特殊选项--docs-- 选项描述为:

      ...getopt 使用特殊选项-- 来分隔选项的结尾。 npm 会将-- 之后的所有参数直接传递给你的脚本:...参数只会传递给npm run 之后指定的脚本,而不是任何前置或后置脚本。


    解决方案 2 - 跨平台

    对于跨平台解决方案(与 Bash、Windows 命令提示符/cmd.exe 和 PowerShell 等一起成功运行的解决方案),您需要使用 nodejs 帮助脚本,如下所示。

    run.js

    让我们将nodejs脚本命名为run.js并将其保存在项目根目录中,与package.json处于同一级别。

    const execSync = require('child_process').execSync;
    
    const arg = process.argv[2] || 'dv'; // Default value `dv` if no args provided via CLI.
    
    execSync('npm run vumper ' + arg, {stdio:[0, 1, 2]});
    execSync('npm run format', {stdio:[0, 1, 2]});
    

    package.json

    配置您的 my-build 脚本以调用 run.js,如下所示:

    ...
    "scripts": {
      "my-build": "node run",
      "vumper": "node node_modules/vumper/index.js",
      "format": "prettier --single-quote -width=80 --write package.json"
    },
    ...
    

    正在运行my-build 脚本:

    根据解决方案 1,要通过 CLI 调用 my-build,您需要运行:

    npm run my-build -- dv
    

    说明:

    • run.js 利用process.argv 获取通过CLI 传递的参数(例如dv)。如果在运行npm run my-build 时未提供参数,则默认值(即dv)将传递给vumper npm-script。

    • run.js 还利用child_process.execSync(...)shell-out/调用两个npm run 命令。

    【讨论】:

    • 难道没有一个cli npm包可以简单地做类似const args = process.argv.slice(3);const command = args.reduce((res, arg, index) =&gt; res.replace(new RegExp(`\\$${ index + 1 }`, 'g'), arg),process.argv[2]);const execSync = require('child_process').execSync;execSync(command, { stdio: [0, 1, 2] });之类的事情吗?这样我就可以用 \" 包装任何脚本,并在它前面加上这样的 cli 并运行任何带有有序参数的脚本......
    【解决方案2】:

    Npm 现在 内置选项可将 cli 参数直接传递给脚本。 cli 参数存储在前缀为npm_config_&lt;flagname&gt; 的环境变量中,它们需要非常严格的语法,格式为--&lt;flagname&gt;=&lt;flagvalue&gt;

    例子:

     "my-build": "npm run vumper %npm_config_myflag% && npm run format",
    

    在终端中,运行npm run my-build --myflag=my_value执行npm run vumper my_value &amp;&amp; npm run format

    注意:

    要在 npm 脚本中引用环境变量,您必须使用特定于平台的语法,即 Windows 中的 %npm_config_myflag% 或 Linux 中的 $npm_config_myflag

    更新:

    为避免与用于配置 npm 本身的 npm_config 变量发生冲突风险,只需为您的参数添加一个唯一前缀,例如您的应用程序名称。

    潜在的冲突是一个非常常见的问题,它适用于许多情况:任何应用程序都可以使用其他应用程序已经使用的环境变量;因此,环境变量通常以应用程序名称为前缀(例如 NVM_HOME、JAVA_HOME)。但是这种潜在的冲突并不是避免使用环境变量的好理由。我认为这同样适用于 npm params / npm_config env vars。 The doc 没有提及冲突的风险,暗示我想他们应该像往常一样管理。

    【讨论】:

    • 平台特定对我来说很关键。我在 Windows 上尝试 $npm_config_myflag 并失去了理智
    • npm 也为内部目的创建了自己的名为 npm_config_* 的环境变量。确保为标志/选项选择一个名称(例如--myflag=*),该名称不会覆盖内部使用的名称,因为这可能会产生不需要的结果。您可以 cd 到您的项目目录并运行 npm run env 以列出 npm 添加的环境变量。例如。传递--tag=foo 不是一个好主意,因为npm 添加了npm_config_tag 环境变量(它的值通常设置为latest)。通过使用这种方法,不确定将来可能会添加哪个内部 npm_config_* vars npm,而您最终可能会被覆盖。
    • 您可以参考这种方法,但正如@RobC 在评论中所解释的那样,使用这种方法可能很危险。所以不是关于这个问题的解决方案,但一般来说,如果某人的要求是在命令末尾附加参数,那么在这种情况下不要使用环境变量方法,他/她可以使用 npm run -- .
    【解决方案3】:

    我的首选方法是使用环境变量:

    {
      "scripts": {
        "ncc-build": "ncc build $ACTION/src/index.ts -o $ACTION/dist",
        "build:pr-changelog": "ACTION=pr-changelog npm run ncc-build",
      }
    }
    

    它应该在 UNIX 系统中工作。我不确定 Windows 平台的兼容性。

    【讨论】:

    • 是的,它在 windows 平台上不起作用
    【解决方案4】:

    执行此操作的不同方法 - 深入您的依赖链:

    npm 脚本部分:

    "test:local": "cross-env-shell UPDATE_BASELINE=false UPDATE_MODULE=%npm_config_vizdifsingle% run-p koa:ci wdio:local",
    "test:remote": "cross-env-shell UPDATE_BASELINE=false  UPDATE_MODULE=%npm_config_vizdifsingle% run-p localtunnel:start koa:ci wdio:remote"
    

    通过使用 crossenv 和 npm 的值放置,您可以将 args 传递给 env.args

    像这样:

    npm run test:local --vizdifsingle=some,value,or,values
    

    它将提供给您

    process.env.npm_config_update_module
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-21
      • 2016-05-15
      • 2018-09-24
      • 2017-07-18
      • 2018-05-13
      • 2018-01-11
      相关资源
      最近更新 更多