Jonah Jonah - 10 months ago 41
Node.js Question

Achieve "npm run x" behavior without a "scripts" entry?

To run a node command within the "context" of your installed

, you can make an entry in the
field of
. Eg:

"scripts": {
"test": "mocha --recursive test/**/*.js --compilers js:babel-register"

and then I can type
npm run test
in my project root, and the mocha tests will run (by calling the mocha binary installed in

Is there a way to achieve precisely the same behavior but without creating a scripts entry? Eg, for a one-off "script"?

I'm imagining something like the following, as an equivalent to
npm run test

npm cmd mocha --recursive test/**/*.js --compilers js:babel-register

Is there any way to achieve this?

NOTE: I should clarify that I'm looking for true equivalence. That is, my command should be able to access other script commands, etc. I know you can always call the binaries using node and the path to the binary within node_modules, but that's not an adequate solution.

Answer Source

Note: This answer works on Unix-like platforms, but not on Windows.

There are two (not mutually exclusive) approaches to making an npm project's dependencies' CLIs callable by name only from the shell:

  • (a) Create a per-invocation helper command that you pass your commands to, as in Frxstrem's helpful answer; see below for an alias-based alternative.

  • (b) Run a once-per-session command that (temporarily) modifies your session's $PATH environment variable; see below.

Note that both solutions below are alias-based, which in the case of (a) is a more light-weight alternative to using a script, and in the case of (b) is a prerequisite to allow modification of the current shell's environment (although a shell function could be used too).

For convenience, add these aliases to your shell profile/initialization file.

Note that both solutions are based on prepending the project directory's ./node_modules/.bin subdirectory (temporarily) to the $PATH environment variable, because when npm installs a project's dependencies, their CLIs, if any, are symlinked into that directory (when you run npm test or npm run ..., this happens automatically, behind the scenes).

(a) Per-invocation helper:


alias nx='PATH=$(npm bin):$PATH'

then allows you to invoke commands with nx as the prefix; e.g.:

nx mocha --recursive test/**/*.js --compilers js:babel-register

Better-performing alternative:
npm bin takes a noticeable amount of time to execute; if you're willing to assume that where npm installs dependent CLIs will not change over time (a pretty safe bet), this hard-coded alternative is much faster:

alias nx='PATH=$PWD/node_modules/.bin:$PATH'

(b) Once-per-session configuration command:

alias npmpath='__nxPrevPath=${__nxPrevPath:-$PATH}; PATH="$(npm bin):$__nxPrevPath"'

Every time you switch to a project folder, run npmpath, and you can then run dependent CLIs by name only for the remainder of the session; e.g.:

cd ~/some-npm-project
npmpath # after this, you can run dependent CLIs by name alone; e.g., `mocha ...`

Note how a cached version of the $PATH variable is used as the basis for prepending to prevent the $PATH from growing ever-longer and possibly unrelated CLIs getting executed.