The scripts
portion of my package.json
currently looks like this:
"scripts": {
"start": "node ./script.js server"
}
...which means I can run npm start
to start the server. So far so good.
However, I would like to be able to run something like npm start 8080
and have the argument(s) passed to script.js
(e.g. npm start 8080
=> node ./script.js server 8080
). Is this possible?
Edit 2014.10.30: It's possible to pass args to npm run
as of npm 2.0.0
The syntax is as follows:
npm run [command] [-- <args>]
Note the necessary --
. So if you have in package.json
"scripts": {
"grunt": "grunt"
}
Then the equivalent of
grunt task:target
run via npm would be
npm run grunt -- task:target
Edit 2013.10.03: It's not currently possible directly. But there's a related GitHub issue opened on npm
to implement the behavior you're asking for. Seems the consensus is to have this implemented, but it depends on another issue being solved before.
Original answer: As a some kind of workaround (though not very handy), you can do as follows:
Say your package name from package.json
is myPackage
and you have also
"scripts": {
"start": "node ./script.js server"
}
Then add in package.json
:
"config": {
"myPort": "8080"
}
And in your 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
That way, by default npm start
will use 8080. You can however configure it (the value will be stored by npm
in its internal storage):
npm config set myPackage:myPort 9090
Then, when invoking npm start
, 9090 will be used (the default from package.json
gets overridden).
You asked to be able to run something like npm start 8080
. This is possible without needing to modify script.js
or configuration files as follows.
For example, in your "scripts"
JSON value, include--
"start": "node ./script.js server $PORT"
And then from the command-line:
$ PORT=8080 npm start
I have confirmed that this works using bash and npm 1.4.23. Note that this work-around does not require GitHub npm issue #3494 to be resolved.
You could also do that:
In package.json
:
"scripts": {
"cool": "./cool.js"
}
In cool.js
:
console.log({ myVar: process.env.npm_config_myVar });
In CLI:
npm --myVar=something run-script cool
Should output:
{ myVar: 'something' }
From what I see, people use package.json scripts when they would like to run script in simpler way. For example, to use nodemon
that installed in local node_modules, we can't call nodemon
directly from the cli, but we can call it by using ./node_modules/nodemon/nodemon.js
. So, to simplify this long typing, we can put this...
... scripts: { 'start': 'nodemon app.js' } ...
... then call npm start
to use 'nodemon' which has app.js as the first argument.
What I'm trying to say, if you just want to start your server with the node
command, I don't think you need to use scripts
. Typing npm start
or node app.js
has the same effort.
But if you do want to use nodemon
, and want to pass a dynamic argument, don't use script
either. Try to use symlink instead.
For example using migration with sequelize
. I create a symlink...
ln -s node_modules/sequelize/bin/sequelize sequelize
... And I can pass any arguement when I call it ...
./sequlize -h /* show help */
./sequelize -m /* upgrade migration */
./sequelize -m -u /* downgrade migration */
etc...
At this point, using symlink is the best way I could figure out, but I don't really think it's the best practice.
I also hope for your opinion to my answer.
Minimist to the rescue in only 2 lines (hurray)!
var argv = require('minimist')(process.argv.slice(2));
var port = argv.port || process.env.PORT || 8080;
// package.json snippet
"scripts": {
"start": "node ./javascript/server.js --port 8081"
}
Check their homepage or npm page.
Minimist is the package in which Optimist was built on, and according to Optimist page, Optimist is being discontinued in favour of Minimist instead.
You could put it as a bin
:
"bin": {
"start": "./script.js server"
}
Then you would run start 8080
to start your server. Although if you do it this way, you probably should give it a better name than start
.
Yes, just use optimist in your app.js (or server.js file). Like:
var argv = require('optimist')
.describe('port')
.alias('p', 'port')
.default(8080)
.argv;
Or require that a port be passed in:
var argv = require('optimist')
.describe('port')
.alias('p', 'port')
.demand('p')
.argv;
And then access it with,
var port = argv.port;
Then make sure you include either -p
or --port
in your start script (if you include demand
- if you set default
you can leave it off):
"scripts": {
"start": "node ./script.js server -p 8080"
}
You might have to adjust the "server" bit here. Not sure what you're doing with that. I always run node app
or node server
but this looks like you're calling node script
with a server parameter. If that's what's happening, you can add that to argv as well.
var argv = require('optimist')
.describe('port')
.alias('p', 'port')
.default(8080)
.describe('command')
.alias('c', 'command')
.default('server')
.argv;
This doesn't really answer your question but you could always use environment variables instead:
"scripts": {
"start": "PORT=3000 node server.js"
}
Then in your server.js file:
var port = process.env.PORT || 3000;
npm 2.x support cli args
Command
npm run-script start -- --foo=3
Package.json
"start": "node ./index.js"
Index.js
console.log('process.argv', process.argv);
If you want to pass arguments to the middle of an npm script, as opposed to just having them appended to the end, then inline environment variables seem to work nicely:
"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",
},
Here, npm run dev
passes the -w
watch flag to babel, but npm run start
just runs a regular build once.