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

时间:2012-07-20 14:02:36

标签: javascript node.js npm

scripts的{​​{1}}部分目前看起来像这样:

package.json

...这意味着我可以运行"scripts": { "start": "node ./script.js server" } 来启动服务器。到目前为止一切都很好。

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

17 个答案:

答案 0 :(得分:809)

修改2014.10.30: It's possible to pass args to npm run as of npm 2.0.0

语法如下:

npm run <command> [-- <args>]

请注意必要的--。需要将传递给npm命令本身的params和传递给脚本的params分开。

所以,如果你有package.json

"scripts": {
    "grunt": "grunt",
    "server": "node server.js"
}

然后以下命令是等效的:

grunt task:target =&gt; npm run grunt -- task:target

node server.js --port=1337 =&gt; npm run server -- --port=1337

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


编辑2013.10.03:目前无法直接使用。但是有一个相关的GitHub issue opened on npm来实现你要求的行为。似乎共识是实现这一点,但这取决于之前解决的另一个问题。


原始回答:作为某种解决方法(虽然不是很方便),您可以执行以下操作:

说明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的默认值被覆盖)。

答案 1 :(得分:177)

您要求能够运行之类的内容 npm start 8080。这可以在不需要修改script.js或配置文件的情况下实现,如下所示。

例如,在您的"scripts" JSON值中,包含 -

"start": "node ./script.js server $PORT"

然后从命令行:

$ PORT=8080 npm start

我已经确认这可以使用bash和npm 1.4.23。请注意,此解决方法不需要解析GitHub npm issue #3494

答案 2 :(得分:71)

您也可以这样做:

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,所以我不确定这是否是vanilla默认行为,但这个答案 正在工作。而不是process.env.npm_config_myVar,请尝试process.env.npm_config_myvar

答案 3 :(得分:61)

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

所以我的答案更简单:

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

将命令行参数发送到npm脚本的语法:

npm run [command] [-- <args>]

想象一下,我们的package.json中有一个npm启动任务来启动webpack dev服务器:

"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 config:

jakub.g 所述,您也可以在 package.json 的配置中设置params

"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_ENV prod dev

var env = process.env.NODE_ENV || 'prod'

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

答案 4 :(得分:29)

npm 2.x support cli args

命令

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

的package.json

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

Index.js

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

答案 5 :(得分:28)

我过去一直使用这种单行代码,并且在离开Node.js一段时间后不得不最近尝试重新发现它。与@francoisrv提到的解决方案类似,它使用node_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官方文档中:

注意:Environment Variables标题说明脚本中的变量的行为与文档中定义的行为不同。当涉及到区分大小写时,以及参数是否用空格或等号定义时,都是如此。

注意::如果您使用带连字符的参数,则会在相应的环境变量中将其替换为下划线。例如,npm run example --foo-bar=baz将对应于${npm_config_foo_bar}

注意:对于非WSL Windows用户,请参阅下面的@Doctor Blue的注释... TL; DR用${npm_config_foo}替换%npm_config_foo%

答案 6 :(得分:27)

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

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

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

的package.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

进行测试

答案 7 :(得分:15)

如果要将参数传递到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只运行一次常规版本。

答案 8 :(得分:6)

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

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

然后在你的server.js文件中:

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

答案 9 :(得分:4)

从我看到的,人们在想要以更简单的方式运行脚本时会使用package.json脚本。例如,要使用安装在本地node_modules中的nodemon,我们无法直接从cli调用nodemon,但我们可以使用./node_modules/nodemon/nodemon.js来调用它。所以,为了简化这种长打字,我们可以把它......


    ...

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

    ...

...然后调用npm start使用'nodemon',它将app.js作为第一个参数。

我想说的是,如果您只想使用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 */

等...

此时,使用符号链接是我能想到的最佳方式,但我并不认为这是最好的做法。

我也希望你的意见得到我的回答。

答案 10 :(得分:3)

注意:该方法可以即时修改您的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

初始运行看起来不错,但尚未进行全面测试。如果您愿意进行应用开发,请使用它。

答案 11 :(得分:3)

适用于 Windows 上的 PowerShell 用户

接受的答案对 npm 6.14 不起作用。不添加 -- 或包含它一次都不起作用。但是,在参数之前放置两次 -- 或放置一次 "--" 可以解决问题。示例:

npm run <my_script> -- -- <my arguments like --this>

疑似原因

像在 bash 中一样,-- 指示 PowerShell 将所有以下参数视为文字字符串,而不是选项 (E.g see this answer)。问题似乎是该命令的解释次数比预期多一次,从而丢失了 '--'。例如,通过做

npm run <my_script> -- --option value

npm 将运行

<my_script> value

然而,做

npm run <my_script> "--" --option value

结果

<my_script> "--option" "value"

效果很好。

答案 12 :(得分:2)

当我试图通过运行sequelize seed来解决我的问题时,我发现了这个问题:生成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

FYI

yarn -v
1.6.0

npm -v
5.6.0

答案 13 :(得分:1)

npm run script_target-<参数> 基本上,这是传递命令行参数的方式,但是仅当脚本仅运行一个命令(如我正在运行命令)时,该方法才有效即 npm运行开始-4200

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

这将用于传递命令行参数,但是如果我们同时运行多个命令,如 npm run build c:/ workspace / file

,该怎么办?
"script":{
       "build" : "copy c:/file <arg> && ng build"
 } 

,但运行复制c:/ file && ng构建c:/ workspace / file 时,它将像这样解释程序 我们期望这样的事情 复制c:/文件c:/工作空间/文件&& ng构建

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

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

答案 14 :(得分:1)

上面的大多数答案仅涉及将参数传递到由npm调用的NodeJS脚本中。我的解决方案是通用的。

只需使用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-environment
my-environment

答案 15 :(得分:0)

我知道已经有一个批准的答案,但是我有点喜欢这种JSON方法。

npm start '{"PROJECT_NAME_STR":"my amazing stuff", "CRAZY_ARR":[0,7,"hungry"], "MAGICAL_NUMBER_INT": 42, "THING_BOO":true}';

通常,我喜欢1个变量,例如项目名称,所以我觉得这很简单。

我的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,问题已经回答。以为我会分享,因为我经常使用这种方法。

答案 16 :(得分:0)

我发现可以将变量完全传递给Node.js:

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

打印出“你好”