Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass command line args to npm scripts in package.json

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?

like image 703
Tony Scialo Avatar asked Jul 17 '18 19:07

Tony Scialo


People also ask

How do I run a script in a package json?

json file: To execute your Script, use the 'npm run <NAME-OF-YOUR-SCRIPT>' command. Some predefined aliases convert to npm run, like npm test or npm start, you can use them interchangeably.

What is scripts in package json?

Scripts are stored in a project's package. json file, which means they're shared amongst everyone using the codebase. They help automate repetitive tasks, and mean having to learn fewer tools. Node npm scripts also ensure that everyone is using the same command with the same flags.

What is npm Run command?

npm run sets the NODE environment variable to the node executable with which npm is executed. If you try to run a script without having a node_modules directory and it fails, you will be given a warning to run npm install , just in case you've forgotten.


2 Answers

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:

  1. For a Bash only solution refer to the "Solution 1" section.

  2. 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:

  1. 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).
  2. Subsequently it runs the script named 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:

  1. In this instance the trailing dv part is the argument that will be passed to your vumper script.

  2. The special option -- must be specified before the argument. The docs describe the -- option as:

    ... The special option -- is used by getopt 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 after npm 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 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.

like image 95
RobC Avatar answered Sep 23 '22 00:09

RobC


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.

like image 34
Mabsten Avatar answered Sep 27 '22 00:09

Mabsten