Silencing errors on failures for npm run-script - node.js

When you run npm test and it fails, you get the test outputs + a single error message, like so:
npm ERR! Test failed. See above for more details.
However, I made a custom script called lint, like so:
// package.json
{
// ...
"scripts": {
// ... definition for test ...
"lint": "./node_modules/jsxhint/cli.js src/",
}
}
Alright, simple enough. But when you run npm run lint and it fails, Rather than the nice looking error for npm test, you get a massive error message after the output of the linter:
npm ERR! Darwin 14.0.0
npm ERR! argv "node" "/usr/local/bin/npm" "run-script" "lint"
npm ERR! node v0.10.32
npm ERR! npm v2.1.7
npm ERR! code ELIFECYCLE
# and ~15 more lines...
Is there a way to silence all this junk so I can have a clean output like the npm test script? I see how they caught the error in the npm source code, but I don't think I can just add a custom command without forking npm like that... Hope I'm wrong!
But if I am, would I be better off just pushing off a task like this to a tool like Grunt? Thanks!

Use the npm run --silent option:
$ npm run --silent test
Even less typing if you define a shell alias:
$ alias run='npm run --silent'
$ run test

If you don't care about preserving the return code of the linter process, you can always configure your package.json like this:
{
// ...
"scripts": {
// ...
"lint": "eslint . || true",
}
}

I've just been trying to figure out the same. Not a perfect answer but it kind of worked to specify linting as a pretest script (docs) like so:
// package.json
{
// ...
"scripts": {
// ... definition for test ...
"pretest": "./node_modules/jsxhint/cli.js src/",
}
}
Then, when you type in npm test the first time, you will only get a single-line error from NPM. Obviously, that means you won't be able to run your tests if you haven't linted.
The other option is to use some kind of third party task runner like Make, Grunt or Gulp.
I've only used Make, and I think it's the most painless to set up (at least on OSX and Linux, not sure about Windows).
Create a Makefile in your root that looks like so:
lint:
./node_modules/.bin/jslint ./*.js # or whatever your lint command is
test:
./node_modules/.bin/mocha test/*.js # or whatever your test command is
.PHONY: lint test
Then type make test and make lint to run those commands.

You can silence the errors by redirecting the stderr to /dev/null. For example:
{
"test": "karma start" (package.json)
}
running:
$ npm run test 2> /dev/null
will now send all npm errors to /dev/null but normal input will still be visible in the console.
Because the error is thrown by npm, after karma exiting with a non-zero status, doing the following is not enough:
{
"test": "karma start 2> /dev/null"
}
but you can overcome it by creating another task that calls that task with stderr redirection:
{
"test": "karma start",
"test:silent": "npm run test 2> /dev/null"
}
this will ensure that the npm error messages are hidden

Related

How can I solve this errorv - npm start - npm ERR! missing script: start

I am receiving this error when I tried to write npm start command after installing the react.
Check your package.json file. It should contain the start entry in the scripts key.
Read the npm docs for detailed information.
Your package.json should contain this entry:
"scripts": {
"start": "node main.js"
}
Replace main.js with the script name you are trying to run. You can test its execution by just running node main.js in the console and determining whether that even works.

Passing arguments to combined npm script

I have in my package.json the following
"scripts": {
...
"prod": "gulp build --production && webpack --env.config=production"
}
I now want to pass a parameter "theme" to both gulp and webpack to be able to adjust the output of the build process from the command line.
I figured out how to pass it to webpack: npm run prod -- --env.theme=themename but gulp does not take care of this. I also played around with the yargs-package, processs.argv and bash string substitution by changing the npm script to "gulp build --production \"$1\" && webpack --env.config=production" but that did not work out either.
How can this be achieved? What am I missing? Any hints highly appreciated!
If you're using Bash you can use a function in your npm-script.
For instance:
"scripts": {
...
"prod": "func() { gulp build --production \"$1\" && webpack --env.config=production \"$1\"; }; func"
}
However, for a cross-platform solution you'll need to consider invoking a nodejs script which exec's the commands - in a similar way shown in Solution 2 of my answer here.

Pass npm script command line arguments to a specific script inside it

I have a scenario where I have to run three npm script to achieve some result in my application. I combined them in one npm script. This is my package.json:
"scripts": {
"setup": "npm install && npm run some-script && npm install",
"some-script": "gulp some-other-script"
}
what I would like to do is to pass arguments to setup script from command line which will be passed further to the some-script script.
If I run npm run script -- --abc=123 the arguments are added at the end of the script but I would like to pass it to specific script (in this case to npm run some-script). I also tried to rewrite script definition like this:
"setup": "npm install && npm run some-script -- --sample=sample&& npm install" but with no luck.
I'm aware of shell functions (described here: Sending command line arguments to npm script and here https://github.com/npm/npm/issues/9627) but I need a solution which will work cross-platform.
Is there a way to do that?
Ok I found a work around.
1st goal was to be able to use some script with arguments, and cascade this to the calls of other scripts :
npm run main -- --arg1
"main": "npm run script1 && npm run script2"
Problem with this approach is that the cascading would only be done by adding the arg passed to npm run main at the END of the line "npm run script1 && npm run script2". I could find no way to pass it to the 1st element : npm run script1
Here is the work around I found :
1st you need to add in package.json:
"config": {
"arg1": "ARG_VALUE"
},
Then in your script you can add it to the call like this :
"main": "npm run script_no_arg1 && npm run scrip1 -- --%npm_package_config_arg1% && npm run script2 -- --%npm_package_config_component% && npm run script_no_arg2"
Finally, You don't need to call it with any arg : npm run main
But you need to modify ARG_VALUE before launc the script :)
Last thing : in my case I was calling gulp tasks :
"cleardown": "rimraf build lib",
"inline-build-templates": "gulp inline-build-templates",
"step1": "npm run cleardown && npm run inline-build-templates -- --%npm_package_config_arg1%",
It works you can get the argument into the gulp task that way :
gulp.task('inline-build-templates', function() {
let component = process.argv[3];
component = component.split('--')[1];
console.log('RUNNING GULP TASK : inline-build-templates for component ' + component);
// whatever task gulp
});
Hope it helps.

Reference npm script from npm script

Consider the following example package.json fragment:
{
// ...
"scripts": {
"start": "npm run b -- --watch",
"build": "builder --in src --out dest"
}
// ...
}
In this, I run build from start, and give it an extra flag. The problem with this approach is it actually creates another instance of the NPM run. It works, but it's ugly.
Is there a clean way to reference the build command from the start command without having to make another call to NPM?
Is there a clean way to reference the build command from the start command without having to make another call to NPM?
Not really.
If you just don't like npm's verbose output, you can silence that with npm run b -s -- --watch.
If you are calling multiple npm scripts from one parent script, you may want to look into an npm task runner. Here is a list of a few: https://github.com/RyanZim/awesome-npm-scripts#task-runners. (Disclaimer: awesome-npm-scripts is my personal project)

How to detect when `prepublish` script is executed as a result of running `npm install`

https://docs.npmjs.com/misc/scripts
prepublish: Run BEFORE the package is published. (Also run on local npm install without any arguments.)
I want my script to execute only in case of user executing npm publish. However, NPM will execute "prepublish" script if user runs "npm install".
The only way I have figured out is using NPM internal ENV variables:
// NPM will run prepublish script after `npm install` (https://docs.npmjs.com/misc/scripts)
// This ensures that when script is executed using `npm *` it is run only when the command is `npm publish`.
if (process.env.npm_config_argv) {
let npmConfigArgv;
npmConfigArgv = JSON.parse(process.env.npm_config_argv);
if (npmConfigArgv.original[0] !== 'publish') {
console.log('`bundle-dependencies prepublish` will not execute. It appears that `prepublish` script has been run by `npm install`.');
return;
}
}
It appears that NPM stores the original command in process.env.npm_config_argv variable.
In case you are wondering, each NPM script is being run in different process. Therefore, something like setting a custom ENV variable in preinstall script does not work.
Another solution that's also worked for me (again from this thread) is using a prepublish.sh script like the following:
get_json_val() {
python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1))";
}
get_npm_command() {
local temp=$(echo $npm_config_argv | get_json_val "['original'][0]")
echo "$temp" | tr -dc "[:alnum:]"
}
if [ $(get_npm_command) != "publish" ]; then
echo "Skipping prepublish script"
exit 0
fi
# else
echo "prepublish called"
# prepublish logic follows:
# ...
So if your package.json file is:
{
"name": "foo",
"version": "0.0.1",
"description": "",
"main": "lib/foo.js",
"scripts": {
"prepublish": "./prepublish.sh"
},
"dependencies": {
"lodash": "^4.10.0"
}
}
… then running npm install will only install the dependencies and the prepublish target will only be called when user types npm run publish.
Yet another way is to use the in-publish package (again mentioned in this thread). Place it in your development dependencies and then in your package.json have something like:
"prepublish": "(in-publish && npm run clean && flow check && npm run test && npm run build) || not-in-publish"
As of npm#4.0.0, the prepublish script is now deprecated. To run a script on both npm publish, and npm install without arguments (the bahaviour of prepublish), you should use prepare instead.
To run a script only on npm publish, you should use prepublishOnly.

Resources