将命令行参数传递给 package.json 中的 npm 脚本
Posted
技术标签:
【中文标题】将命令行参数传递给 package.json 中的 npm 脚本【英文标题】:Pass command line args to npm scripts in package.json 【发布时间】:2018-12-25 14:25:05 【问题描述】:我的 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。这可能吗?
【问题讨论】:
【参考方案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 的限制,请考虑以下解决方案:
对于仅 Bash 的解决方案,请参阅 “解决方案 1” 部分。
如果需要跨平台支持,请遵循“解决方案 2” 部分中描述的解决方案。
解决方案 1 - Bash(MacOS/Linux/ 等):
在 package.json 的 scripts
部分中配置您的 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 函数执行以下操作:
-
首先运行
npm run vumper <arg>
。其中<arg>
将是通过 CLI 传递的 shell 参数。它在脚本中使用$1
引用(即第一个positional parameter/argument)。
随后它通过命令npm run format
运行名为format
的脚本。
这两个npm run
命令使用&&
运算符链接,因此第二个npm run format
命令只有在初始npm run vumper <arg>
命令成功完成时才会运行(即返回0
退出代码)。
正在运行my-build
脚本:
要通过 CLI 调用 my-build
,您需要运行:
npm run my-build -- dv
注意:
在这种情况下,结尾的 dv
部分是将传递给您的 vumper
脚本的参数。
必须在参数之前指定特殊选项--
。 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) => 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_<flagname>
的环境变量中,它们需要非常严格的语法,格式为--<flagname>=<flagvalue>
。
例子:
"my-build": "npm run vumper %npm_config_myflag% && npm run format",
在终端中,运行npm run my-build --myflag=my_value
执行npm run vumper my_value && 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 我的首选方法是使用环境变量:
"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
【讨论】:
以上是关于将命令行参数传递给 package.json 中的 npm 脚本的主要内容,如果未能解决你的问题,请参考以下文章
将相同的参数传递给 package.json 中多个脚本的节点