I have the below scripts in my package.json:
"scripts": {
"vumper": "node node_modules/vumper/index.js",
"format": "prettier --single-quote -width=80 --write package.json"
},
The 'vumper' package takes in a command line argument (such as 'dv'). What I would like to be able to do is have a command that runs both of these in succession.
Essentially, I would like to be able to run:
npm run vumber dv
and then
npm run format
but in one command, something like
npm run my-build dv
which would run both of the above commands, correctly accepting the command line argument 'dv' and passing it to the first npm run vumper. Is this possible?
Essentially, what you're wanting is to have an npm-script something like this, whereby <arg-here>
is provide via the CLI;
...
"scripts": {
"my-build": "npm run vumper <arg-here> && npm run format",
...
},
...
However, unfortunately npm does not have a built-in feature to achieve this.
The special npm option --
, (refer to the end of Solution 1 below for further info about this option), can only be used to pass an argument to the END of a script but NOT into the MIDDLE. So, if your two commands were in the opposite order, the --
option could be used like this:
...
"scripts": {
"my-build": "npm run format && npm run vumper --",
...
},
...
To overcome the limitation of there being no built-in feature to pass an argument into the MIDDLE of a script consider the following solutions:
For a Bash only solution refer to the "Solution 1" section.
If cross platform support is required then follow the solution described in the "Solution 2" section.
Configure your my-build
script in the scripts
section of package.json to invoke a Bash shell function, as shown below:
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"
},
...
Explanation:
The Bash function named func
does the following:
npm run vumper <arg>
. Whereby <arg>
will be the shell argument passed via the CLI. It is referenced in the script using $1
(i.e. the first positional parameter/argument).format
via the command npm run format
.These two npm run
commands are chained using the &&
operator, so the second npm run format
command will only run if the initial npm run vumper <arg>
command completes successfully (i.e. returns a 0
exit code).
Running my-build
script:
To invoke my-build
via your CLI you'll need to run:
npm run my-build -- dv
Note:
In this instance the trailing dv
part is the argument that will be passed to your vumper
script.
The special option --
must be specified before the argument. The docs describe the --
option as:
... The special option
--
is used bygetopt
to delimit the end of the options. npm will pass all the arguments after the--
directly to your script: ... The arguments will only be passed to the script specified afternpm run
and not to any pre or post script.
For a cross-platform solution, (one which works successfully with Bash, Windows Command Prompt / cmd.exe, and PowerShell etc..), you'll need to utilize a nodejs helper script as follows.
run.js
Let's name the nodejs script run.js and save it in the projects root directory, at the same level as 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
Configure your my-build
script to invoke run.js as follows:
...
"scripts": {
"my-build": "node run",
"vumper": "node node_modules/vumper/index.js",
"format": "prettier --single-quote -width=80 --write package.json"
},
...
Running my-build
script:
As per Solution 1, to invoke my-build
via your CLI you'll need to run:
npm run my-build -- dv
Explanation:
run.js utilizes process.argv
to obtain the argument passed via the CLI (e.g. dv
). If no argument is provided when running npm run my-build
the default value, (i.e. dv
), is passed to the vumper
npm-script.
run.js also utilizes child_process.execSync(...)
to shell-out/invoke the two npm run
commands.