How to suppress output when running npm scripts - node.js

I have decided to experiment with npm scripts as a build tool and so far I like it. One issue I'd like to solve is when running a script to run jshint when something doesn't pass linting I get a ton of "npm ERR!" lines. I would like to suppress these as the output from the linter is more meaningful.
Is there a good way to set this globally and is there a way to set it for each script run?

All scripts:
You can fix this by suppressing the output of npm overall, by setting the log level to silent in a couple ways:
On each npm run invocation:
npm run --silent <your-script>
Or by creating a .npmrc file (this file can be either in your project directory -local- or your home folder -global-) with the following:
loglevel=silent
Resources:
npm log level config: https://docs.npmjs.com/misc/config#loglevel
npmrc: https://docs.npmjs.com/misc/config#loglevel
Each script, individually:
A simple trick I've used to get around this issue on certain scripts like linting is to append || true at the end of such scripts. This will work without any npm config changes.
This will ensure that the script will always exit with a 0 status. This tricks npm into thinking the script succeed, hence hiding the ERR messages. If you want to be more explicit, you can append || exit 0 instead and it should achieve the same result.
{
"scripts": {
"lint": "jshint || true",
}
}

You should be able to use both the --quiet and --silent options, as in
npm install --quiet
--quiet will show stderr and warnings, --silent should suppress nearly everything
You can also send stdout/stderr to /dev/null, like so:
npm install > '/dev/null' 2>&1
or less versbose
npm install &> '/dev/null'

npm install --quiet --no-progress
Will keep warnings and errors, and suppress the ADHD progress bar on terminals that support it.

for an individual script that you want to keep silent without having to add --silent each time, you can make a new script that calls your previous one and adds --silent.
My example scripts in package.json:
"dev-loud": "npm run build && nodemon -r dotenv/config dist/index.js",
"dev": "npm run dev-loud --silent"

You can do this inside your script by removing the event listeners
#!/usr/bin/env node
process.removeAllListeners('warning');
// Do your thang without triggering warnings

Related

Set environment variables in package.json

I've had a look at quite a number of answers to questions similar to mine but i've not been able to find a working solution for my use case yet.
I've got an environment variable of lets say auth=false. i'd like to set auth=true when i run a particular script in my package.json.
Script in package.json looks like this:
"dev-use-auth": "auth=true && npm run dev"
After running this script, process.env.auth is still set to false. I've also tried using the cross-env package with no luck
This, most likely, would depend on the OS, but for Linux environments you should get rid of the &&.
The && indicates that you wish to run the commands serially.
Try this, instead:
"dev-use-auth": "auth=true npm run dev"
it depends on the operative system you are working on, cross-env will help you running on multiple operative systems by calling it:
"dev-use-auth": "cross-env auth=true npm run dev"
on windows:
"dev-use-auth": "set auth=true && npm run dev"
on unix (mac, linux, etc..c)
"dev-use-auth": "auth=true npm run dev"

How to print out multi-line message from npm script

Is it possible to print out a multi-line message from an npm script?
My team has an alternative script that needs to run in place of npm publish.
So instead of running npm publish from the terminal, we should be running npm run publish:lib. But, some team members forget about the alternative script and end up just running npm publish.
So what I've done so far is added this to my package.json:
"scripts": {
"postpublish": "node -e \"console.log('Did you mean npm run publish:lib?')\"",
}
That way when they do run npm publish, they'll be reminded about the alternative script. However, I'm not satisfied with it because it's not very noticible, and also the words console.log get's printed out, which is kind of ugly.
My goal is to have something printed out that looks like this:
The solution I ended up using was the following:
package.json
"scripts": {
"postpublish": "node publishWarning.js"
}
publishWarning.js
console.log('***************************************')
console.log('***************************************')
console.log('** Did you mean npm run publish:lib? **')
console.log('***************************************')
console.log('***************************************')

Use an npm script as "bin"

I have a command line application written in TypeScript with some npm scripts defined in package.json.
"scripts": {
"start": "ts-node src/index.ts",
"start-args": "ts-node src/index.ts -- some args"
},
I would like to link and alias the TypeScript file so that I can call the program easily, so I am looking for something like a "bin" key in the package.json file.
"scripts": {
"start": "ts-node ./src/index.ts",
"start-args": "ts-node src/index.ts -- some args"
},
"bin": {
"foobar": "./src/index.ts",
"bazqux": "./src/index.ts some args"
}
ts-node is installed locally.
However, since TypeScript is not natively supported by node, just putting a shebang on ./src/index.ts won't work.
I would also like to be able to create an aliased command with default arguments, like bazqux above. When I link or install the package as global, I can run "foobar" globally as if I run "npm run start" inside the repository; or run "bazqux" globally as it's "npm run start-args".
How to achieve this?
Update: The issue described below has been fixed in ts-node#8.9.0 thanks to my report. --script-mode now resolves symlinks before looking for the tsconfig.json file. The correct shebang to use is #!/usr/bin/env ts-node-script, which is now also documented. Make sure you have the newest version installed globally with npm -g install ts-node. (I'm not sure whether you also/still need TypeScript installed globally for this. If yes: npm -g install typescript.)
Outdated: For those who also still stumble across this problem, I documented my current approach in detail in this issue. In short, many modules (including those of Node.js itself) require that you use the --esModuleInterop option for the TypeScript compiler. (You can specify this in your tsconfig.json file.) In order to be able to use your command from anywhere and not just from within your package directory, you have to use the undocumented --script-mode option for ts-node or the undocumented ts-node-script command, which does the same.
In other words, your shebang should either be #!/usr/bin/env -S ts-node --script-mode or #!/usr/bin/env ts-node-script. (The former uses -S to pass arguments to the specified interpreter. If this doesn't work on your platform, you can try to hack around this limitation.)
If you want to use the bin functionality of npm (e.g. by running npm link from the package directory), the above doesn't work because --script-mode does not (yet?) follow symbolic links. To work around this, you can use #!/usr/bin/env -S ts-node --project /usr/local/lib/node_modules/<your-project>/tsconfig.json on the first line of your script. This is not ideal, though, as it breaks platform independence. The only other option I see at the moment is to use a bash script instead and call your script from there.
It will work, if ts-node is in path variable use
#!/usr/bin/env ts-node
console.log("Hello World");
Checkout repo:
https://github.com/deepakshrma/ts-cli
Try out:
$ npm i -g https://git#github.com:deepakshrma/ts-cli.git
$ ts-test

npm and node slow to exit on Windows

I have a build process using npm with several tasks registered in a chain.
package.json looks like this (the http/https stuff is because of a proxy server certificate that upsets npm):
"scripts": {
"git-config": "git config --global --replace-all url.\"https://\".insteadOf git://",
"bower-install": "node_modules/.bin/bower install",
"bower": "npm run git-config && npm run bower-install",
"build": "npm config set registry http://registry.npmjs.org/ && npm config set strict-ssl false && npm install && npm run bower && node build-bundles"
},
Every time npm or node is launched, there seems to be about a .5 second hang to launch, and another 1.5 second hang AFTER the command has finished but before the npm/node process exits. In the above script, there are many calls to npm/node, and this ends up adding 15-20 seconds onto our build time (even if there are no changes).
Is there any way to:
Eliminate at least the 2 second hang before npm/node exits
Make the above script(s) only execute when one of the project files changes (I do not want to use watchify)
Otherwise improve the speed of these scripts
Please note that this question doesn't have anything to do with the speed of npm install, package caching, package download speed or the like.
Thanks.

Running npm scripts conditionally

I have 2 main build configurations - dev and prod.
I push updates to a heroku server that run npm install --production to install my app.
In the package.json I have the following segment:
"scripts": {
"postinstall": "make install"
}
that runs a make file that is responsible for uglifying the code and some other minor things.
However, I don't need to run this makefile in development mode. Is there any way to conditionally run scripts with npm?..
Thanks!
You can have something like this defined in your package.json (I'm sure theres a better shorthand for the if statement.)
"scripts": {
"postinstall":"if test \"$NODE_ENV\" = \"production\" ; then make install ; fi "
}
Then when you execute npm with production flag like you stated you already do
npm install --production
it will execute your make install because it will set $NODE_ENV = production
When I need to conditionally execute some task(s), I pass environment variables to the script/program and which takes care of that logic. I execute my scripts like this
NODE_ENV=dev npm run build
and in package.json, you would start a script/program
"scripts": {
"build":"node runner.js"
}
which would check the value of the environment variable to determine what to do. In runner.js I do something like the following
if (process.env.NODE_ENV){
switch(process.env.NODE_ENV){
....
}
}
For conditional npm scripts, you can use cross-platform basic logical operators to create if-like statements ( || and && ).
I've run into needing to run scripts to only generate helpers once on any machine. You can use inline javascript to do this by using process.exit() codes.
"scripts": {
"build":"(node -e \"if (! require('fs').existsSync('./bin/helpers')){process.exit(1)} \" || npm run setup-helpers) && npm run final-build-step"
}
So for testing envs you might do:
"scripts": {
"build":"node -e \"if (process.env.NODE_ENV === 'production'){process.exit(1)} \" || make install"
}
Can't you add another section in your .json under devDependencies? Then if you do npm install it'd install the packages specified under devDependincies and npm install --production would install the regular dependcies.
I would encourage you to take a different tack on uglifying your code. Take a look at connect-browserify or the even more powerful asset-rack.
These can automatically uglify your code on launch of the Express server, rather than on install. And you can configure them to do different things in development and production.

Resources