[英]Sending command line arguments to npm script
我的package.json
的scripts
部分目前看起来像这样:
"scripts": {
"start": "node ./script.js server"
}
...这意味着我可以运行npm start
来启动服务器。 到目前为止,一切都很好。
但是,我希望能够运行类似npm start 8080
并将参数传递给script.js
(例如npm start 8080
=> node./script.js server 8080
)。 这可能吗?
自 npm 2 (2014) 以来,可以将 args 传递给npm run
。 语法如下:
npm run <command> [-- <args>]
注意--
分隔符,用于分隔传递给npm
命令本身的参数和传递给脚本的参数。
使用示例package.json
:
"scripts": {
"grunt": "grunt",
"server": "node server.js"
}
以下是将参数传递给这些脚本的方法:
npm run grunt -- task:target // invokes `grunt task:target`
npm run server -- --port=1337 // invokes `node server.js --port=1337`
注意:如果您的参数不以-
或--
开头,则不需要明确的--
分隔符; 但为了清楚起见,最好还是这样做。
npm run grunt task:target // invokes `grunt task:target`
请注意下面的行为差异( test.js
有console.log(process.argv)
):以-
或--
开头的参数传递给npm
而不是 script ,并在那里默默地吞下。
$ npm run test foobar
['C:\\Program Files\\nodejs\\node.exe', 'C:\\git\\myrepo\\test.js', 'foobar']
$ npm run test -foobar
['C:\\Program Files\\nodejs\\node.exe', 'C:\\git\\myrepo\\test.js']
$ npm run test --foobar
['C:\\Program Files\\nodejs\\node.exe', 'C:\\git\\myrepo\\test.js']
$ npm run test -- foobar
['C:\\Program Files\\nodejs\\node.exe', 'C:\\git\\myrepo\\test.js', 'foobar']
$ npm run test -- -foobar
['C:\\Program Files\\nodejs\\node.exe', 'C:\\git\\myrepo\\test.js', '-foobar']
$ npm run test -- --foobar
['C:\\Program Files\\nodejs\\node.exe', 'C:\\git\\myrepo\\test.js', '--foobar']
当您使用npm 实际使用的参数时,差异会更加明显:
$ npm test --help // this is disguised `npm --help test`
npm test [-- <args>]
aliases: tst, t
要获取参数值,请参阅此问题。 要读取命名参数,最好使用yargs或minimist 之类的解析库; nodejs 全局公开process.argv
,包含命令行参数值,但这是一个低级 API(空格分隔的字符串数组,由操作系统提供给节点可执行文件)。
编辑 2013.10.03:目前无法直接使用。 但是在 npm
上打开了一个相关的 GitHub 问题,以实现您要求的行为。似乎共识是实现这一点,但这取决于之前解决的另一个问题。
原始答案(2013.01):作为某种解决方法(虽然不是很方便),您可以执行以下操作:
从package.json
说你的包名是myPackage
并且你也有
"scripts": {
"start": "node ./script.js server"
}
然后添加package.json
:
"config": {
"myPort": "8080"
}
在你的script.js
中:
// defaulting to 8080 in case if script invoked not via "npm run-script" but directly
var port = process.env.npm_package_config_myPort || 8080
这样,默认情况下npm start
将使用 8080。但是您可以对其进行配置(该值将由npm
存储在其内部存储中):
npm config set myPackage:myPort 9090
然后,在调用npm start
,将使用 9090( package.json
中的默认值被覆盖)。
您要求能够运行类似npm start 8080
的东西。 这是可能的,无需修改script.js
或配置文件,如下所示。
例如,在您的"scripts"
JSON 值中,包括——
"start": "node ./script.js server $PORT"
然后从命令行:
$ PORT=8080 npm start
我已经确认这可以使用 bash 和 npm 1.4.23。 请注意,此解决方法不需要解决 GitHub npm问题 #3494 。
你也可以这样做:
在package.json
中:
"scripts": {
"cool": "./cool.js"
}
在cool.js
:
console.log({ myVar: process.env.npm_config_myVar });
在 CLI 中:
npm --myVar=something run-script cool
应该输出:
{ myVar: 'something' }
更新:使用 npm 3.10.3,它似乎小写了process.env.npm_config_
变量? 我也在使用better-npm-run
,所以我不确定这是否是普通的默认行为,但这个答案是有效的。 代替process.env.npm_config_myVar
,尝试process.env.npm_config_myvar
jakub.g的答案是正确的,但是使用 grunt 的示例似乎有点复杂。
所以我更简单的答案:
- 向 npm 脚本发送命令行参数
将命令行参数发送到 npm 脚本的语法:
npm run [command] [-- <args>]
想象一下,我们的 package.json 中有一个 npm start 任务来启动 webpack 开发服务器:
"scripts": {
"start": "webpack-dev-server --port 5000"
},
我们使用npm start
从命令行运行它
现在,如果我们想将一个端口传递给 npm 脚本:
"scripts": {
"start": "webpack-dev-server --port process.env.port || 8080"
},
运行它并通过命令行传递端口,例如 5000,如下所示:
npm start --port:5000
- 使用 package.json 配置:
正如jakub.g所提到的,您也可以在package.json的配置中设置参数
"config": {
"myPort": "5000"
}
"scripts": {
"start": "webpack-dev-server --port process.env.npm_package_config_myPort || 8080"
},
npm start
将使用配置中指定的端口,或者您可以覆盖它
npm config set myPackage:myPort 3000
- 在你的 npm 脚本中设置一个参数
读取 npm 脚本中的变量集的示例。 在这个例子NODE_ENV
"scripts": {
"start:prod": "NODE_ENV=prod node server.js",
"start:dev": "NODE_ENV=dev node server.js"
},
在prod或dev中读取server.js中的 NODE_ENV
var env = process.env.NODE_ENV || 'prod'
if(env === 'dev'){
var app = require("./serverDev.js");
} else {
var app = require("./serverProd.js");
}
从npm 2.x开始,您可以通过使用--
分隔将 args 传递到运行脚本中
终端
npm run-script start -- --foo=3
包.json
"start": "node ./index.js"
索引.js
console.log('process.argv', process.argv);
我过去一直在使用这种单线器,在离开 Node.js 一段时间后,最近不得不尝试重新发现它。 与@francoisrv 提到的解决方案类似,它利用了npm_config_*
变量。
创建以下最小的package.json
文件:
{
"name": "argument",
"version": "1.0.0",
"scripts": {
"argument": "echo \"The value of --foo is '${npm_config_foo}'\""
}
}
运行以下命令:
npm run argument --foo=bar
观察以下输出:
--foo 的值为 'bar'
所有这些都很好地记录在 npm 官方文档中:
注意: 环境变量标题解释了脚本中的变量的行为与文档中定义的不同。 在区分大小写以及参数是用空格还是等号定义时都是如此。
注意:如果您使用带连字符的参数,这些将在相应的环境变量中替换为下划线。 例如, npm run example --foo-bar=baz
将对应于${npm_config_foo_bar}
。
注意:对于非 WSL Windows 用户,请参阅下面的 @Doctor Blue 评论... TL;DR 将${npm_config_foo}
替换为%npm_config_foo%
。
在您的代码中使用process.argv
然后只需为您的脚本值条目提供一个尾随的$*
。
举个例子,用一个简单的脚本试试它,它只将提供的参数记录到标准输出echoargs.js
:
console.log('arguments: ' + process.argv.slice(2));
包.json:
"scripts": {
"start": "node echoargs.js $*"
}
例子:
> npm start 1 2 3
arguments: 1,2,3
process.argv[0]
是可执行文件(节点), process.argv[1]
是您的脚本。
使用 npm v5.3.0 和 node v8.4.0 测试
如果您想将参数传递到 npm 脚本的中间,而不是将它们附加到末尾,那么内联环境变量似乎可以很好地工作:
"scripts": {
"dev": "BABEL_ARGS=-w npm run build && cd lib/server && nodemon index.js",
"start": "npm run build && node lib/server/index.js",
"build": "mkdir -p lib && babel $BABEL_ARGS -s inline --stage 0 src -d lib",
},
在这里, npm run dev
将-w
watch 标志传递给 babel,但npm run start
只运行一次常规构建。
上面的大多数答案都只是将参数传递到由 npm 调用的 NodeJS 脚本中。 我的解决方案是通用的。
只需使用 shell 解释器(例如sh
)调用包装 npm 脚本并像往常一样传递参数。 唯一的例外是第一个参数编号是0
。
例如,您想添加 npm 脚本someprogram --env=<argument_1>
,其中someprogram
只打印env
参数的值:
"scripts": {
"command": "sh -c 'someprogram --env=$0'"
}
当你运行它时:
% npm run -s command my-environment
my-environment
对于 Windows 上的 PowerShell 用户
接受的答案对我来说不适用于 npm 6.14。 既不添加 no --
也不包括它一次确实有效。 然而,在论点前放两次或放一次"--"
--
可以了。 例子:
npm run <my_script> -- -- <my arguments like --this>
就像在 bash 中一样, --
指示 PowerShell 将所有以下参数视为文字字符串,而不是选项( 例如,请参阅此答案)。 问题似乎是该命令的解释比预期的多一次,失去了'--'
。 例如,通过做
npm run <my_script> -- --option value
npm 将运行
<my_script> value
然而,做
npm run <my_script> "--" --option value
结果是
<my_script> "--option" "value"
效果很好。
这并不能真正回答您的问题,但您始终可以使用环境变量:
"scripts": {
"start": "PORT=3000 node server.js"
}
然后在你的 server.js 文件中:
var port = process.env.PORT || 3000;
当我试图通过运行 sequelize seed:generate cli 命令来解决我的问题时,我发现了这个问题:
node_modules/.bin/sequelize seed:generate --name=user
让我进入正题。 我想在我的package.json文件中有一个简短的脚本命令并同时提供 --name 参数
经过一些实验后得到了答案。 这是我在package.json中的命令
"scripts: {
"seed:generate":"NODE_ENV=development node_modules/.bin/sequelize seed:generate"
}
...这是在终端中运行它以为用户生成种子文件的示例
> yarn seed:generate --name=user
> npm run seed:generate -- --name=user
供参考
yarn -v
1.6.0
npm -v
5.6.0
注意:此方法会即时修改您的package.json
,如果您别无选择,请使用它。
我必须将命令行参数传递给我的脚本,例如:
"scripts": {
"start": "npm run build && npm run watch",
"watch": "concurrently \"npm run watch-ts\" \"npm run watch-node\"",
...
}
因此,这意味着我使用npm run start
启动我的应用程序。
现在,如果我想传递一些论点,我可能会从以下开始:
npm run start -- --config=someConfig
它的作用是: npm run build && npm run watch -- --config=someConfig
。 问题在于,它总是将参数附加到脚本的末尾。 这意味着所有链接的脚本都没有得到这些参数(Args 可能是也可能不是所有人都需要,但那是另一回事。)。 此外,当调用链接的脚本时,这些脚本将不会获得传递的参数。 即watch
脚本不会得到传递的参数。
我的应用程序的生产用途是.exe
,因此在 exe 中传递参数可以正常工作,但如果想在开发过程中这样做,它会变得有问题。
我找不到任何合适的方法来实现这一点,所以这就是我尝试过的。
我在应用程序的父级创建了一个 javascript 文件: start-script.js
,我有一个“default.package.json”,而不是维护“package.json”,我维护“default.package.json”。 start-script.json
的目的是读取default.package.json
,提取scripts
并查找npm run scriptname
然后将传递的参数附加到这些脚本。 之后,它将创建一个新的package.json
并使用修改后的脚本从 default.package.json 复制数据,然后调用npm run start
。
const fs = require('fs');
const { spawn } = require('child_process');
// open default.package.json
const defaultPackage = fs.readFileSync('./default.package.json');
try {
const packageOb = JSON.parse(defaultPackage);
// loop over the scripts present in this object, edit them with flags
if ('scripts' in packageOb && process.argv.length > 2) {
const passedFlags = ` -- ${process.argv.slice(2).join(' ')}`;
// assuming the script names have words, : or -, modify the regex if required.
const regexPattern = /(npm run [\w:-]*)/g;
const scriptsWithFlags = Object.entries(packageOb.scripts).reduce((acc, [key, value]) => {
const patternMatches = value.match(regexPattern);
// loop over all the matched strings and attach the desired flags.
if (patternMatches) {
for (let eachMatchedPattern of patternMatches) {
const startIndex = value.indexOf(eachMatchedPattern);
const endIndex = startIndex + eachMatchedPattern.length;
// save the string which doen't fall in this matched pattern range.
value = value.slice(0, startIndex) + eachMatchedPattern + passedFlags + value.slice(endIndex);
}
}
acc[key] = value;
return acc;
}, {});
packageOb.scripts = scriptsWithFlags;
}
const modifiedJSON = JSON.stringify(packageOb, null, 4);
fs.writeFileSync('./package.json', modifiedJSON);
// now run your npm start script
let cmd = 'npm';
// check if this works in your OS
if (process.platform === 'win32') {
cmd = 'npm.cmd'; // https://github.com/nodejs/node/issues/3675
}
spawn(cmd, ['run', 'start'], { stdio: 'inherit' });
} catch(e) {
console.log('Error while parsing default.package.json', e);
}
现在,我不做npm run start
,而是做node start-script.js --c=somethis --r=somethingElse
初始运行看起来不错,但尚未彻底测试。 如果您喜欢应用程序开发,请使用它。
我发现可以像向 Node.js 一样传递变量:
// index.js
console.log(process.env.TEST_ENV_VAR)
// package.json
...
"scripts": { "start": "node index.js" },
...
TEST_ENV_VAR=hello npm start
打印出“你好”
据我所知,当人们想以更简单的方式运行脚本时,他们会使用 package.json 脚本。 例如,要使用安装在本地nodemon
中的 nodemon,我们不能直接从 cli 调用nodemon
,但可以使用./node_modules/nodemon/nodemon.js
调用它。 所以,为了简化这个冗长的输入,我们可以把这个...
... scripts: { 'start': 'nodemon app.js' } ...
...然后调用npm start
以使用以 app.js 作为第一个参数的“nodemon”。
我想说的是,如果您只想使用node
命令启动服务器,我认为您不需要使用scripts
。 键入npm start
或node app.js
具有相同的效果。
但是,如果您确实想使用nodemon
并且想要传递动态参数,也不要使用script
。 尝试改用符号链接。
例如使用带有sequelize
的迁移。 我创建了一个符号链接...
ln -s node_modules/sequelize/bin/sequelize sequelize
...而且我可以通过任何争论当我称之为...
./sequlize -h /* show help */
./sequelize -m /* upgrade migration */
./sequelize -m -u /* downgrade migration */
ETC...
在这一点上,使用符号链接是我能想到的最好方法,但我并不认为这是最好的做法。
我也希望您对我的回答提出意见。
我知道已经有一个批准的答案,但我有点喜欢这种 JSON 方法。
npm start '{"PROJECT_NAME_STR":"my amazing stuff", "CRAZY_ARR":[0,7,"hungry"], "MAGICAL_NUMBER_INT": 42, "THING_BOO":true}';
通常我有 1 个我需要的 var,例如项目名称,所以我觉得这很简单。
我的 package.json 中也经常有这样的东西
"scripts": {
"start": "NODE_ENV=development node local.js"
}
并且贪婪我想要“全部”,NODE_ENV和CMD 行 arg 的东西。
您只需在文件中访问这些内容(在我的情况下为 local.js)
console.log(process.env.NODE_ENV, starter_obj.CRAZY_ARR, starter_obj.PROJECT_NAME_STR, starter_obj.MAGICAL_NUMBER_INT, starter_obj.THING_BOO);
你只需要在它上面放一点(我正在运行 v10.16.0 btw)
var starter_obj = JSON.parse(JSON.parse(process.env.npm_config_argv).remain[0]);
Anyhoo,问题已经回答了。 想我会分享,因为我经常使用这种方法。
我解决了这样的问题,看看test-watch
脚本:
"scripts": {
"dev": "tsc-watch --onSuccess \"node ./dist/server.js\"",
"test": "tsc && cross-env NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 jest",
"test-watch": "cross-env NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 tsc-watch --onSuccess",
},
您可以像这样调用test-watch
脚本:
// Run all tests with odata in their name
npm run test-watch "jest odata"
npm run script_target -- <argument>基本上这是传递命令行参数的方式,但它只在脚本只有一个命令运行的情况下才有效,就像我正在运行一个命令,即npm run start -- 4200
"script":{
"start" : "ng serve --port="
}
这将运行以传递命令行参数,但是如果我们一起运行多个命令,例如npm run build c:/workspace/file
"script":{
"build" : "copy c:/file <arg> && ng build"
}
但它会在运行copy c:/file && ng build c:/work space/file时像这样解释,我们应该像这样copy c:/file c:/work space/file && ng build
注意:-因此命令行参数仅在脚本中只有一个命令的情况下才起作用。
我读了上面的一些答案,其中一些人正在写你可以使用 $ 符号访问命令行参数,但这不会起作用
尝试跨环境 NPM 包。
便于使用。 易于安装。 跨平台。
// package.json
"scripts": {
“test”: “node test.js”,
“test-with-env-arg”: “cross-env YourEnvVarName=strValue yarn test,
}
process.env
获取参数// test.js
const getCommandLineArg = Boolean(process.env.YourEnvVarName === 'true') // Attention: value of process.env.* is String type, not number || boolean
当我需要部署到不同的环境时,我遇到了同样的问题,这里是 package.json 前后更新。
scripts:
{"deploy-sit": "sls deploy --config resources-sit.yml",
"deploy-uat": "sls deploy --config resources-uat.yml",
"deploy-dev": "sls deploy --config resources-dev.yml"}
但这是采用环境变量而不是重复自己的正确方法
scripts:{"deploy-env": "sls deploy --config resources-$ENV_VAR.yml"}
最后你可以通过运行ENV_VAR=dev npm run deploy-env
使用--
从脚本中分离您的 arguments 并添加所有必需的 arguments,我们稍后可以通过索引访问它们。
npm run start -- myemail@gmail.com 100
您可以使用获取节点中的参数
const params = process.argv.slice(2);
console.log(params);
Output
['myemail@gmail.com', '100']
我使用以下方式进行测试
"scripts": {
"test-one": "mocha --timeout 90000 --watch --require ts-node/register --watch-extensions ts $1"
}
要运行测试使用以下命令
npm run test-one ./e2e/<test_file_path>
我不必使用任何配置。 我觉得您可以像在这里一样进行辩论。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.