これは、なにをしたくて書いたもの?
今まで、npx
コマンドはローカルインストールされたnode_modules
内の実行ファイルにパスを通して実行してくれるものだと思って
いたのですが、どうやら異なるようなのでちょっと確認しておきたいなと思いまして。
npxコマンド
そもそも、npx
コマンドのドキュメントをちゃんと読んだことがなかったので、見てみます。
ローカルにインストールされたnpmパッケージ、またはリモートからフェッチしたnpmパッケージから任意のコマンドをnpm run
のように
実行できるコマンドというのが概要になっています。
This command allows you to run an arbitrary command from an npm package (either one installed locally, or fetched remotely), in a similar context as running it via npm run.
要求されたパッケージがローカルプロジェクトの依存関係にない場合は、npmキャッシュ内のフォルダにインストールされ、環境変数PATH
に
追加するようです。
If any requested packages are not present in the local project dependencies, then they are installed to a folder in the npm cache, which is added to the PATH environment variable in the executed process.
実行したいコマンドとパッケージ名が一致しない場合は、--package
または-p
で対象のnpmパッケージを指定する必要があります。
npm exec
というコマンドとも関連があるようです。
では、ちょっと試してみましょう。
環境
今回の環境は、こちら。
$ node --version v16.16.0 $ npm --version 8.11.0 $ npx --version 8.11.0
ヘルプを見てみる
npx
コマンドのヘルプを見てみます。
$ npx --help Run a command from a local or remote npm package Usage: npm exec -- <pkg>[@<version>] [args...] npm exec --package=<pkg>[@<version>] -- <cmd> [args...] npm exec -c '<cmd> [args...]' npm exec --package=foo -c '<cmd> [args...]' Options: [--package <pkg>[@<version>] [--package <pkg>[@<version>] ...]] [-c|--call <call>] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] alias: x Run "npm help exec" for more info
npm exec
のヘルプに、より多くの情報があるようですね。
Run "npm help exec" for more info
どうやら、関連のあるコマンドのようです。
指示どおりに以下のコマンドを実行すると、もっと多くの情報が得られます。
$ npm help exec
npx
のドキュメントに記載されているものの、npx --help
では表示されないオプションもありましたし、
より深く知ろうとすると、npm exec
のドキュメントを見るのが良いのでしょう。
パッケージ名とコマンド名が一致する場合
たとえば、create-react-app
を使ってみます。
Getting Started | Create React App
npx create-react-app
コマンドを実行。
$ npx create-react-app my-react-app
すると、create-react-app
パッケージをインストールするかどうかを聞かれます。
Need to install the following packages: create-react-app Ok to proceed? (y)
y
を入力すると、create-react-app
コマンドが実行されます。
作成されたプロジェクト内に移動して
$ cd my-react-app
package.json
を見てみます。
"dependencies": { "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.3.0", "@testing-library/user-event": "^13.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" },
create-react-app
パッケージは依存関係にはいなかったりします。
どこにあるかというと、$HOME/.npm/_npx
ディレクトリ内にあるようです。
$ ll $HOME/.npm/_npx/c67e74de0542c87c 合計 64 drwxrwxr-x 3 xxxxx xxxxx 4096 8月 3 01:17 ./ drwxrwxr-x 3 xxxxx xxxxx 4096 8月 3 01:16 ../ drwxrwxr-x 65 xxxxx xxxxx 4096 8月 3 01:17 node_modules/ -rw-rw-r-- 1 xxxxx xxxxx 45128 8月 3 01:17 package-lock.json -rw-rw-r-- 1 xxxxx xxxxx 61 8月 3 01:17 package.json
package.json
を見ると、こんな感じになっていました。
$HOME/.npm/_npx/c67e74de0542c87c/package.json
{ "dependencies": { "create-react-app": "^5.0.1" } }
なるほど、と。
ちなみに、パッケージのインストールを対話形式で聞かれないようにするのは、以下のように--yes
または-y
オプションを使います。
$ npx --yes create-react-app my-react-app ### または $ npx -y create-react-app my-react-app
パッケージ名とコマンド名が一致しない場合
もうひとつ、NestJSで試してみましょう。
First steps | NestJS - A progressive Node.js framework
npx nest
で実行してみようとするものの、エラーになりました。
$ npx nest new my-nestjs-app npm ERR! could not determine executable to run npm ERR! A complete log of this run can be found in: npm ERR! $HOME/.npm/_logs/2022-08-02T16_27_07_177Z-debug-0.log
パッケージ名と実行コマンド名が異なるので、解決できないからですね。
この場合、--package
または-p
オプションを使用します。
$ npx --package @nestjs/cli nest new my-nestjs-app ### または $ npx -p @nestjs/cli nest new my-nestjs-app
パッケージのインストールにy
と答えれば、npx
がパッケージをインストールして進んでいきます。
Need to install the following packages: @nestjs/cli Ok to proceed? (y)
--yes
オプションを使用してもOKです。
$ npx --package @nestjs/cli --yes nest new my-nestjs-app ### または $ npx -p @nestjs/cli -y nest new my-nestjs-app
完了したら、プロジェクト内に移動して作業をしていきます。
$ cd my-nestjs-app
なお、今回のnpx
で自動的にインストールしたNestJSのCLIは、先ほどのcreate-react-app
とはまた別のディレクトリにインストールされて
いました。
$ ll $HOME/.npm/_npx/ccf722f030a36e55 合計 204 drwxrwxr-x 3 xxxxx xxxxx 4096 8月 3 01:28 ./ drwxrwxr-x 4 xxxxx xxxxx 4096 8月 3 01:28 ../ drwxrwxr-x 199 xxxxx xxxxx 12288 8月 3 01:28 node_modules/ -rw-rw-r-- 1 xxxxx xxxxx 182699 8月 3 01:28 package-lock.json -rw-rw-r-- 1 xxxxx xxxxx 56 8月 3 01:28 package.json
package.json
の内容は、こちら。
$HOME/.npm/_npx/ccf722f030a36e55/package.json
{ "dependencies": { "@nestjs/cli": "^9.0.0" } }
だいたい、動作はわかりましたね。
ところで
ローカルまたはグローバルにインストールされていないパッケージは、npx
コマンドでnpm
キャッシュ内にダウンロードしてから実行する
ことができることを確認しました。
ところで、npm
キャッシュにインストールしたパッケージは、結局npx
経由だとグローバルインストールに近い状態にも見えるのですが、
どうなんでしょうね?
$ npx create-react-app --version 5.0.1 $ npx -p @nestjs/cli nest --version 9.0.0
定期的に削除したり、アップデートしたりした方がいいんでしょうか?
この話は、npm exec
コマンドのドキュメントで、キャッシュに関する注意事項として記載があります。
指定方法は、こんな感じでしょうか。
$ npx --package @nestjs/cli --yes --prefer-online nest new my-nestjs-app
個人的には、時々キャッシュを削除する、でいいかなと思わなくもないですが…。