Pass command line args to npm scripts in package.json
a different approach for doing this - to reach super deep into you dependency chain:
npm scripts section:
"test:local": "cross-env-shell UPDATE_BASELINE=false UPDATE_MODULE=%npm_config_vizdifsingle% run-p koa:ci wdio:local",
"test:remote": "cross-env-shell UPDATE_BASELINE=false UPDATE_MODULE=%npm_config_vizdifsingle% run-p localtunnel:start koa:ci wdio:remote"
by using crossenv and npm's value placement you can pass args to env.args
like this:
npm run test:local --vizdifsingle=some,value,or,values
it will be available to you in
process.env.npm_config_update_module
My preferred method is by using environment variables:
{
"scripts": {
"ncc-build": "ncc build $ACTION/src/index.ts -o $ACTION/dist",
"build:pr-changelog": "ACTION=pr-changelog npm run ncc-build",
}
}
It should work in UNIX systems. I'm not sure about windows platfrom compatibility though.
Npm now has a built-in option to pass cli arguments directly to scripts.
The cli arguments are stored in environmenet variables with prefix npm_config_<flagname>
, and they required a very strict syntax, with the form --<flagname>=<flagvalue>
.
Example:
"my-build": "npm run vumper %npm_config_myflag% && npm run format",
In the terminal, run npm run my-build --myflag=my_value
to execute npm run vumper my_value && npm run format
.
Note:
To refer the environment variable in the npm script, you have to use the platform specific syntax, ie %npm_config_myflag%
in Windows or $npm_config_myflag
in Linux.
UPDATE:
To avoid risks of conflict with the npm_config variables used to configure npm itself, just prefix your arguments with a unique prefix, such as the name of your app.
The potential conflict is a very common problem, which applies in many contexts: any application could use environment variables already used by other applications; for this reason, the environment variables are usually prefixed with the name of the application (eg NVM_HOME, JAVA_HOME). But this potential conflict is not a good reason to avoid using environment variables. The same in my opinion applies to npm params / npm_config env vars. The doc does not say anything about the risk of conflicts, implying I guess they should be managed as usual.
Short Answer:
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.
Solution 1 - Bash (MacOS/Linux/ etc..):
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:
- Firstly runs
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). - Subsequently it runs the script named
format
via the commandnpm 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 yourvumper
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.
Solution 2 - Cross-platform:
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 runningnpm run my-build
the default value, (i.e.dv
), is passed to thevumper
npm-script.run.js also utilizes
child_process.execSync(...)
to shell-out/invoke the twonpm run
commands.