将命令行参数发送到npm脚本

我的package.jsonscripts部分目前看起来像这样:

"scripts": {"start": "node ./script.js server"}

…这意味着我可以运行npm start来启动服务器。到目前为止一切顺利。

但是,我希望能够运行类似于npm start 8080的东西并将参数传递给script.js(例如npm start 8080=>node ./script.js server 8080)。这可能吗?

829539 次浏览

npm 2及更新版本

从npm 2(2014)开始可以将参数传递给#0。语法如下:

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`

说明如果您的参数不以#0或#1开头,则不需要显式的#1分隔符;但为了清晰起见,最好还是这样做。

npm run grunt task:target     // invokes `grunt task:target`

请注意下面的行为差异(test.jsconsole.log(process.argv)):以---传递给#4而不是脚本开头的参数,并在那里默默地吞下。

$ 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

要获取参数值,看到这个问题。对于读取命名参数,最好使用像纱线极简主义这样的解析库;nodejs全局公开process.argv,包含命令行参数值,但这是一个低级API(空格分隔的字符串数组,由操作系统提供给节点可执行文件)。

据我所知,当人们想以更简单的方式运行脚本时,他们会使用package.json脚本。例如,要使用安装在本地node_modules中的nodemon,我们不能直接从cli调用nodemon,但我们可以使用./node_modules/nodemon/nodemon.js调用它。所以,为了简化这种长键入,我们可以把这个…

...
scripts: {'start': 'nodemon app.js'}
...

…然后调用npm start来使用app.js作为第一个参数的'no的'。

我想说的是,如果你只想用node命令启动你的服务器,我认为你不需要使用scripts。键入npm startnode 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 */

等…

在这一点上,使用符号链接是我能想到的最好的方法,但我并不认为这是最好的做法。

我也希望你对我的回答有意见。

你也可以这样做:

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

这并不能真正回答你的问题,但你总是可以使用环境变量:

"scripts": {"start": "PORT=3000 node server.js"}

在您的server.js文件中:

var port = process.env.PORT || 3000;

您要求能够运行喜欢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

npm2. x开始,您可以通过与--分开来将参数传递到运行脚本中

终端

npm run-script start -- --foo=3

Package.json

"start": "node ./index.js"

Index.js

console.log('process.argv', process.argv);

如果你想将参数传递到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监视标志传递给Babel,但npm run start只是运行一次常规构建。

jakub. g的答案是正确的,但是使用grant的示例似乎有点复杂。

我简单的回答:

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

读取server.js中的NODE_ENVprod开发

var env = process.env.NODE_ENV || 'prod'
if(env === 'dev'){var app = require("./serverDev.js");} else {var app = require("./serverProd.js");}

在代码中使用process.argv,然后只需为脚本值条目提供尾随$*

作为一个例子,尝试使用一个简单的脚本,它只是将提供的参数记录到标准输出echoargs.js

console.log('arguments: ' + process.argv.slice(2));

package.json:

"scripts": {"start": "node echoargs.js $*"}

示例:

> npm start 1 2 3arguments: 1,2,3

process.argv[0]是可执行文件(节点),process.argv[1]是您的脚本。

使用npm v5.3.0和node v8.4.0进行测试

我发现这个问题,而我试图解决我的问题与运行序列化种子:生成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 -v1.6.0
npm -v5.6.0

npm runscript_target--<参数>基本上这是传递命令行参数的方式,但只有在脚本只有一个命令运行的情况下才有效,比如我正在运行一个命令,即npm运行启动--4200

"script":{"start" : "ng serve --port="}

这将用于传递命令行参数,但是如果我们像#运行构建文件##工作空间##工作空间一样一起运行多个命令呢?

"script":{"build" : "copy c:/file <arg> && ng build"}

但它会像这样解释,同时运行复制c:/file&&ng build c:/work space/file我们被期待着这样的事情复制c:/file c:/work space/file&&ng build

注意:-因此命令行参数仅在脚本中只有一个命令的情况下工作。

我读了上面的一些答案,其中一些人写道,您可以使用$符号访问命令行参数,但这将不起作用

上面的大多数答案只是将参数传递到您的NodeJS脚本中,由npm调用。我的解决方案供一般使用。

只需用shell解释器(例如sh)调用包装npm脚本并像往常一样传递参数。唯一的例外是第一个参数编号是0

例如,您想添加npm脚本someprogram --env=<argument_1>,其中someprogram仅打印env参数的值:

package.json

"scripts": {"command": "sh -c 'someprogram --env=$0'"}

当你运行它时:

% npm run -s command my-environmentmy-environment

备注:这种方法会动态修改你的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.jsonconst defaultPackage = fs.readFileSync('./default.package.json');try {const packageOb = JSON.parse(defaultPackage);// loop over the scripts present in this object, edit them with flagsif ('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 scriptlet cmd = 'npm';// check if this works in your OSif (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一段时间后,最近不得不尝试重新发现它。与@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用户,请参阅@Dr Blue下面的评论……太长别读${npm_config_foo}替换为%npm_config_foo%

我知道已经有了一个认可的答案,但我有点喜欢这种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 line 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]);

无论如何,问题已经回答了。我想我会分享,因为我经常使用这种方法。

我发现可以像Node.js一样传递变量:

// index.jsconsole.log(process.env.TEST_ENV_VAR)
// package.json..."scripts": { "start": "node index.js" },...
TEST_ENV_VAR=hello npm start

打印出“你好”

对于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"

效果不错。

我解决了这样的问题,看看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 namenpm run test-watch "jest odata"

试试跨环境NPM包

易于使用。易于安装。跨平台。

示例:

  1. 为命令设置参数
// package.json"scripts": {“test”: “node test.js”,“test-with-env-arg”: “cross-env YourEnvVarName=strValue yarn test,}
  1. process.env获取参数
// test.jsconst 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