npm 経由で scripts のコマンドを実行すると $(npm bin) が PATH に追加されるらしい

package.json の scripts のところには $(npm bin)/mocha のようにローカルの mocha を明示的に指定しないといけないのかと思いきや、$(npm bin) が勝手に PATH に追加されるみたいです。
なので、mocha と記述するだけでローカルに mocha が存在すればそちらが使われます。

実際に $PATH の値を見てみます。

% cd /tmp/
% npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (tmp)
version: (0.0.0)
entry point: (index.js)
test command: echo $PATH
git repository:
license: (ISC)
About to write to /private/tmp/package.json:

  "name": "tmp",
  "version": "0.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo $PATH"
  "author": "",
  "license": "ISC"

Is this ok? (yes) yes
% npm test | sed "s|$HOME|\$HOME|g"

> tmp@0.0.0 test /private/tmp
> echo $PATH

% echo $PATH | sed "s|$HOME|\$HOME|g"

上記の例では npm test で echo $PATH を実行するようにしています。
元の $PATH と比べると /usr/local/Cellar/node/0.10.24/lib/node_modules/npm/bin/node-gyp-bin:/private/tmp/node_modules/.bin:/usr/local/Cellar/node/0.10.24/bin が追加されていることがわかります。

パスの追加は npm の utils/lifecycle.js で行われているようです。

なので、require(“./utils/lifecycle.js”) を実行している buiild, install, publish, restart, run-script, start, test, unbuild, update コマンド経由の場合はローカルのパッケージが優先されそうです。

Executing A Project-Specific Node/NPM Package A-la “bundle exec” | :derick_bailey