npm run script, can't access command line args - npm

I'm an electron beginner, and I'm trying to use it to package up a react-based app. I'm trying to run electron via a script entry in my package.json:
"electron-dev": "concurrently \"cross-env BROWSER=none npm start\" \"wait-on http://localhost:3000 && electron . $npm_config_input \"",
That will run electron.js (which is what "main" is defined as earlier in the package.json file), but I need to pass in a command line argument. I've seen references that indicate $npm_config_input will have the argument passed in this way:
% npm run electron-dev --input=file.tif
But that $npm_config_input doesn't seem to get expanded for me. electron.js gets the literal string $npm_config_input. I'm confused why this isn't working.
It seems I could avoid this problem by doing this:
% npm run electron-dev -- --input=file.tif
But I don't know how to associate the input argument to the second command I'm starting using concurrently. It would be nice if I could use something like $1 or $npm_config_input in its definition. Does anyone have a solution for this?
I'm running this on Windows 10 using git bash. Other things generally work. I have nodejs 12.16.2 installed. TIA!

you almost got it right, just use process.argv.
for instance, create a file named cmd.js that looks like this
console.log(process.argv.slice(2));
now create a script hook for it by adding the following to package.json
"scripts": {
"foo": "node cmd.js"
}
now you can try it...
$ npm run foo -- arg1 arg2
> foo#1.0.0 foo /tmp/foo
> node cmd.js "arg1" "arg2"
[ 'arg1', 'arg2' ]

I believe I have found the answer. In electron.js, I printed process.argv to see if there was anything of use there. It turns out process.env.npm_config_input contains file.tif when I run this:
% npm run electron-dev --input=file.tif
That should work for me. I still don't understand why the other things I read about and tried didn't work.

Related

npm run fails for some reason

Why would the following command fail?
npm run "start:desktop -- --app word"
says:
npm ERR! Missing script: "start:desktop -- --app word"
I have ensured that start:desktop script exists in scripts section of package.json. If I remove the arguments part, it runs okay, so there is something I need to do with the -- --app word part.
Note: This need to be run from launch.json, but I was trying to run it directly in the console to see what was failing.
If it matters, this is a Yeoman-based Office.js project.
Edit
I understand that because of the use of double-quotes, npm run thinks that the entire value start:desktop -- --app word is the name of the script and therefore can't find it. The problem however is that this is being invoked as a task from my debug configuration (launch.json) and there is no way of separating the arguments from the script name there. Here is the task definition:
{
"label": "Debug: Word Desktop",
"type": "npm",
"script": "start:desktop -- --app word",
"presentation": {
"clear": true,
"panel": "dedicated",
},
"problemMatcher": []
}
This is where I'm stuck. How do I tell it where the name of script ends and the arguments begin. I thought those double-dashes served exactly that purpose, but apparently they don't.
Since your command contains quotes, it is treating everything inside the quotes as a single argument.
There is a script called start:desktop, but there is no script called literally start:desktop -- --app word
Try:
npm run start:desktop -- --app word

Does package.json support compound variables?

A project that respects the semver directory structure for build artefacts is beginning soon, and package.json or .nmprc would seem to be the right place to define this metadata. This is some preliminary code that demonstrates how the goal is intended to be achieved:
{
"name": "com.vendor.product"
, "version": "0.0.0"
, "directories": {
"build": "./out"
}
, "main": "./${npm_directories_build}/${npm_package_name}/${npm_package_version}/${npm_package_name}.js"
, "exports": "${npm_package_main}"
, "scripts": {
"echo": "echo\"${npm_package_exports}\""
}
}
I expected
npm run echo
to print the compound variable result to standard output,
./out/com.vendor.product/0.0.0/com.vendor.product.js
but instead, it prints the literal text
${npm_package_export}
I attempted to use array variables in .npmrc
outpath[]=./out
outpath[]=/${npm_package_name}
outpath[]=/${npm_package_version}
But
...
{
"echo": "echo \"${npm_config_outpath}\""
}
Simply prints an empty newline
It was expected that package.json supports compound variables, but this assumption is now in question. I have checked documentation, but either I am missing something or such is not defined. Long hand repetition of the same data is to be avoided (e.g. multiple references to package variables in order to make a single path). It is intended for package name and version to always dictate the location of the build files in a reliable and predictable manner.
If compound variables are not supported, could you clarify how .npmrc array variables actually work? Failing that, could you recommend an alternative method to achieve the same ends? Many thanks!
Searched documentation:
https://docs.npmjs.com/misc/config
https://docs.npmjs.com/files/npmrc
https://docs.npmjs.com/configuring-npm/npmrc.html
https://docs.npmjs.com/files/package.json#config
http://doc.codingdict.com/npm-ref/misc/config.html#config-settings
https://github.com/npm/ini
Short Answer:
"Does package.json support compound variables?"
Unfortunately no, not for the way you are wanting to use them. It only has package json vars which can be used in npm scripts only. For example on *Nix defining the echo script as:
"echo": "echo $npm_package_version"
or on Windows defining it as:
"echo": "echo %npm_package_version%"
will print the version e.g. 0.0.0.
Note: cross-env provides a solution for a single syntax that works cross-platform.
You certainly cannot include parameter substitution ${...} elsewhere in package.json fields except for the scripts section.
Additional info:
Regarding your subsequent comment:
How array values defined in .npmrc can be used in package.json
AFAIK I don't think you can. For example let's say we;
Save this contrived .npmrc in the root of the project directory.
.npmrc
quux[]="one"
quux[]="two"
quux[]="three"
foo=foobar
Then cd to the project directory and run the following command to print all environment variables:
npm run env
As you can see, the npm_config_foo=foobar environment variable has been added by npm. However for the quux array there is no npm_config_quux=[ ... ] environment variable added.
So, in npm scripts using package.json vars the following does work:
"echo": "echo $npm_config_foo"
However the following, (for referencing the array), does not - simply because it does not exist;
"echo": "echo $npm_config_quux"
The ini node.js package:
Maybe consider investigating the ini node.js package that npm utilizes for parsing .npmrc files. For example:
If you run the following command to install the package in your project:
npm i -D ini
Then define the npm echo script as per this:
"scripts": {
"echo": "node -e \"var fs = require('fs'), ini = require('ini'); var config = ini.parse(fs.readFileSync('./.npmrc', 'utf-8')); console.log(config.quux)\""
}
Note it uses the nodejs command line option -e to evaluate the JavaScript code. It essentially executes the following:
var fs = require('fs'),
ini = require('ini');
var config = ini.parse(fs.readFileSync('./.npmrc', 'utf-8'));
console.log(config.quux);
Then given the contrived .npmrc file that I mentioned previously when running:
npm run echo
it will print:
[ 'one', 'two', 'three' ]

Passing arguments via npm scripts

I've read a bunch of answers suggesting to do something like
npm run dev -- --nodebug:true
but what I then see executed is
webpack-dev-server --hot --colors --port 3000 "--nodebug:true"
I do not want these quotes as then the next part of the passing of arguments does not work. Any suggestions?
I figured it out. You can run:
npm run dev nodebug=true
On your main js file you can use the following code to retrieve the parameters.
process.argv.forEach((val, index) => {
console.log(`${index}: ${val}`)
})
And it will print something like this in your console:
0: /usr/local/lib/nodejs/node-v9.11.2/bin/node
1: /var/www/html/project/backend/bin/www
2: nodebug=true

Pass parameter to npm script and then gulp-task [duplicate]

I have package.json scripts with the following structure:
"scripts": {
"watch:build": "tsc --watch",
"watch:server": "nodemon ./src/app.js --watch 'app'",
"build": "tsc && gulp do_something",
"start": "npm-run-all clean build --parallel watch:build",
"watch:server --print-label"
}
I would like to start the application as npm run start with_argument
and pass it to build script, to perform actions in the gulp task based on that argument.
I read a lot of tutorial and how to articles, but without result. It is possible somehow to pass argument from one script to another(which starts a gulp task).
Thanks in advance!
npm-run-all provides a its own custom mechanism for handling arguments by utilizing placeholders in npm-scripts, as stated in the Argument Placeholders section of its documentation found here.
npm-script:
Given your current npm-script named start you'll need to redefine it as follows:
"scripts": {
...
"start": "npm-run-all clean \"build -- {#}\" --parallel watch:build --"
...
}
Notes:
-- {#} must be added after build.1
build -- {#} must be wrapped in escaped double quotes \"...\"
-- must also be added after last script invocation, namely: watch:build
gulpfile.js
To obtain the arguments passed via the CLI inside your gulpfile.js you''ll need to utilize nodes process.argv
For the purpose of demonstration lets say our gulpfile.js is as follows:
var gulp = require('gulp');
var args = process.argv.splice(3, process.argv.length - 3);
gulp.task('doSomething', function() {
// For testing purposes...
if (args.indexOf('--foo') > -1) {
console.log('--foo was passed via the CLI.')
}
if (args.indexOf('--quux') > -1) {
console.log('--quux was passed via the CLI.')
}
});
Notes:
The first three items in nodes process.argv are:
The path to the executable running the JavaScript file.
The path of the JavaScript file being executed.
The name of the gulp task, i.e. doSomething
However, we're only interested in the elements from the fourth item in the array onwards - as these will be the arguments passed via the CLI. The line which reads:
var args = process.argv.splice(3, process.argv.length - 3);
creates an args variable and assigns an Array containing each argument passed via the CLI, i.e. we omit the first three aforementioned items in point 1 above using the Arrays splice() method.
Running your start script:
You invoke your start script via your CLI as follows:
$ npm start -- --foo --quux
Note You must provide the -- which precedes npm start before providing your own arguments.
Output:
Using the contrived gulpfile.js above, in combination with your current scripts defined in your package.json, and of course the necessary changes made to your start script. When you run:
$ npm start -- --foo --quux
you will see the following printed to the console:
--foo was passed via the CLI.
--quux was passed via the CLI.
Running:
$ npm start -- --quux
you will see just the following printed to the console:
--quux was passed via the CLI.
And of course, running:
$ npm start
Does not print either of the messages defined in gulpfile.js.
Footnotes:
1 -- {#} can be replaced with -- {1} if you only intend to pass one argument. However, -- {#} handles multiple arguments, so it's fine to use it for one argument too.

npm run: how to pass parameter and replace placeholder by param in script call

I want to to define a scripts entry in my package.json to simplify building for several environments.
In the script execution I need to replace $1 (or whatever syntax I need for a placeholder) by a parameter I would pass to npm run build-script like for example --env=prod or even simpler, --prod. How can I do that? Other questions and answers I found here didn't help me solve the problem.
"scripts": {
"build-for": "ng build --output-path=../../web/admin-v2 --env=$1 --base-href=\"/admin-v2/\""
}
I often resort to creating a utility node script for this kind of scenario and invoke it via the scripts section of package.json.
build-for.js
var nodeCLI = require('shelljs-nodecli');
var env = '--env=foo'; // <-- Default env flag/value when no arg provided.
if (process.argv.indexOf('--prod') !== -1) {
env = '--env=prod';
}
// Check for other possible env values
if (process.argv.indexOf('--quux') !== -1) {
env = '--env=quux';
}
// Run the ng build command
nodeCLI.exec('ng', 'build', '--output-path=../../web/admin-v2', env, '--base-href=\"/admin-v2/\"');
build-for.js utilizes nodes process.argv to ascertain the argument/flag passed via the CLI and then invokes the ng command (the one currently defined in your package.json) using shelljs-nodecli.
npm i -D shelljs-nodecli
Lets assume that build-for.js is saved to a hidden folder named .scripts in your projects root directory; then your scripts section of package.json will be defined as follows:
package.json
{
...
"scripts": {
"build-for": "node ./.scripts/build-for"
},
...
}
Running the script
Invoke the npm script by running:
npm run build-for -- --prod
Note the special -- before the argument --prod must be included as explained here
As of npm#2.0.0, you can use custom arguments when executing scripts. 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:
Given the logic curently in the build-for.js - when no arguments are passed, for example:
npm run build-for
...the env flag will be set to --env=foo
Running the following:
npm run build-for -- --quux
...will result in the env flag will be set to --env=quux
Caveat
I haven't fully tested build-for.js, so you may find that you don't need to escape the double-quotes in this part '--base-href=\"/admin-v2/\"' of the following command (nodeCLI may handle that for you.):
// Run the ng build command
nodeCLI.exec('ng', 'build', '--output-path=../../web/admin-v2', env, '--base-href=\"/admin-v2/\"');
Not exactly what you're looking for but you can use environment variables & provide them inline:
package.json script:
"<script>": "echo ${ENV1} ${ENV2}"
run like so:
ENV1=a ENV2=b npm run <script>
$ npm run <script>
a b