From both Windows or Linux, I want a way to pass args to a npm script
, but have them be injected as environment variables
From the command line, I'd start my project in this fashion:
npm run start -- --env=dev --host=localhost --port=1234
To consume my cli args & inject them as env variables regardless of platform, I used the cross-env npm package :
package.json
"scripts": {
"start": "cross-env env=%env% host=%host% port=%port% my-app"
},
I understand the above is invalid syntax, but can that start
script somehow consume the args I pass instead of forwarding them on to my-app
?
Unfortunately npm does not, nor intends to, provide a builtin feature which allows arguments to be passed to the middle of a npm script (as stated here). Arguments can only be passed to the end of a script.
For Linux and macOS you can utilize bash functions in npm-scripts to pass arguments to the middle of a script, as per my answer here. However Windows will choke at such a solution.
As cross-platform compatibility is a requirement, consider moving the logic currently in your
start
script into a separate nodejs utility script. The nodejs script can then be invoked via the npm-script namedstart
.The following describes how to achieve your requirement in a cross-platform compatible way.
1. Custom nodejs utility script.
Create a nodejs script as follows. Let's name the script start.js and save it in the root of your project directory, i.e. at the same level where your package.json file currently resides.
Explanation:
In the first line we
require
nodes builtinexecSync()
. We'll utilize this to runcross-env
and set the environment variables.Nodes builtin
process.argv
obtains the arguments passed via the command-line. The first two items in nodesprocess.argv
are:However, we're only interested in the elements from the third item in the array onwards - as these will be your arguments passed via the CLI. These lines which read;
create an
args
variable and assigns an Array containing each argument passed via the CLI. The first two aforementioned items in point 2 are omitted from the array using thesplice()
method. In themap()
method we remove the--
prefix from each argument.The last line reading:
invokes
cross-env
and places the arguments as a string using Template Literals and the Arrayjoin()
method. Thestdio
part configures the pipes forstdin
,stdout
,stderr
in the child process.Note: If your targeting older versions of node that don't support Template Literals then you can substitute this line with the following instead. This handles string concatenation using the
+
operator:Similarly, if ES6 arrow functions aren't supported change the
map()
to use standard functions. For instance:2. package.json script.
Redefine your
start
script in package.json as follows:Here we are asking node to invoke the start.js script.
Note If you prefer to save the start.js file in a directory location which is different to the aforementioned root of your project directory, then you'll need to define the path to start.js as necessary. The path should be relative to package.json. For instance:
3. Running the npm-script.
The npm
start
script can be invoked via your CLI by running:The
run
part, i.e.npm run start ...
is not required when invoking the npm'sstart
script.