npm run XXX を実行する時、何が発生した?
はじめに
こんにちは。
full-stack developerを目指しているShenです。
かなり前に、面接する時に、「npm run XXX を実行する時、何が発生しましたか?」という質問ありました。この件について、ちょっと深く探りたいと思います。
npm run XXX を実行する時
以下のpackage.jsonがあるとしたら、ターミナルにnpm run dev
を入力した時、何が発生しますか?
{
"name": "bookmanagement",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "nodemon -e ts --exec \"npm run build && npm start\"",
"start": "node ./dist/app.js",
"build": "tsc"
}
}
はい、scripts
にdev
のコマンドを探して、nodemon -e ts --exec \"npm run build && npm start\"
を実行しますね。
追加質問
nodemon .....
を直接実行しなくて、npm run dev
を実行しますか?
なぜ当時は、「うん、npm run dev
はかなり短くて、実行しやすいではないでしょうか? 毎回長いコマンドを打つと結構効率が悪いと思います」と答えました。
面接終了後、ターミナルにnodemon -e ts --exec \"npm run build && npm start\"
を実行してみました。
Unknown command: nodemon
え?
そうか、そうか。OSにnodemonをインストールされていないから、怒られているか。
npm run dev
は効きますか?
なんでOSに存在しないのに、それでは、めっちゃでデカいnode_modules
フォルダを開きましょうか。
その中に、./bin
というデレクトリがあります。
そして、パッケージ名のjsファイルを開きましょう。今回はnodemon.js
です。
#!/usr/bin/env node
const cli = require('../lib/cli');
const nodemon = require('../lib/');
const options = cli.parse(process.argv);
nodemon(options);
const fs = require('fs');
// checks for available update and returns an instance
const pkg = JSON.parse(fs.readFileSync(__dirname + '/../package.json'));
if (pkg.version.indexOf('0.0.0') !== 0 && options.noUpdateNotifier !== true) {
require('simple-update-notifier')({ pkg });
}
npm run dev
が実行されると、package.json
と同じ階層のnode_modules/.bin
フォルダの中に、nodemon
の実行スクリプトを見つけたら、該当ファイルを実行します。
node xxxx がないのに、.jsファイルはどうやって実行されますか?
以下のshebangという記述があるためです。ここで、OS環境に入れているnodeで該当.jsファイルを実行してます。
#!/usr/bin/env node
ターミナルを開いて、以下のコマンドを入力してみてください。
whereis node
あれ、なんでうちのnodeが/usr/local/bin
にインストールされていて、/usr/bin/env
は何んですか?という質問があるかもしれないです。
npm
は「ユーザはどのpathにnodeをインストールしている」ということはわかりません。そして、/usr/bin/env
を使って、ユーザがインストールしているnodeを見つけて、実行しています。
ちなみに、以下のコマンドを実行したら、nodeにはいれます。
env node
終わりに
npm run XXX を叩いた時、以下の順序で実行処理発生します。
-
package.json
と同じ階層のnode_modules/.bin
フォルダに実行できるファイルを探しに行きます。 - 1が見つけたら、実行します。
- 1が見つけられなかったら、globalでインストールされている
node_modules/.bin
に実行できるファイルを探しに行きます。 - 3が見つけられなかったら、pathの環境変数の中で、実行できるものを探しに行きます。
Discussion