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をインストールされていないから、怒られているか。
なんでOSに存在しないのに、npm run devは効きますか?
それでは、めっちゃでデカい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