🚀

npxで実行時の@latestの必要性

に公開

npmパッケージ関連の公式ドキュメントでよく見かける以下のようなコマンド。

npx create-next-app@latest

この時の@latestに意味があるのかについて気になったので少しだけ調べてみました。

なんで気になったか

なんとなくnpxで実行する際は、

  • 直下のnode_modulesにあればそれを使用
  • グローバルインストール済みならそれを使用
  • それ以外なら一時的にダウンロードして使用

と思ってました(発端は思い出せず。。)。

3点目は以下のイメージでした。

(1)download packageA if not exist
(2)run packageA
(3)remove packageA (最後に削除)

そうすると、1点目、2点目はインストール済み = バージョンは確定であり、3点目は毎回再インストール(バージョン未指定なら最新を)すると思っており、@latestの指定は冗長じゃないか?と考えてました。

3点目は一時的なダウンロードではなかった

npxのドキュメントを見ると以下の記載があった。
https://docs.npmjs.com/cli/v8/commands/npx

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.

3点目の場合、パッケージはnpmキャッシュディレクトリ(macの場合は$HOME/.npm/_npx)にインストールされてそれが実行されるらしい。そしてキャッシュというだけあって、2回目以降のnpx実行時は、キャッシュにインストール済みのパッケージ(及びバージョン)の場合は、再インストールせずにキャッシュのものが使われるらしい。

つまりnpm i -gのようにグローバルディレクトリにインストールする訳ではないが、代わりにnpmキャッシュディレクトリにインストールするという挙動(そして実行完了後も削除しないで再利用する)。

したがって、npx create-next-appのように@latestを付けないで実行した場合、

  • npmキャッシュディレクトリにcreate-next-app(バージョン未指定)が存在すればそれを使用
  • npmキャッシュディレクトリにcreate-next-app(バージョン未指定)が存在しなければ、最新版をダウンロードしてきて実行

という挙動になる。

このため、キャッシュの有無に関わらず最新版を使いたい場合は@latestを付ける必要がある、ということらしい。

試してみた

以前(と言っても数日前)にnpxで実行したpod-installが確かに$HOME/.npm/_npx配下に存在した。

~ $ cat ~/.npm/_npx/7cf525d1e16b4e35/package.json
{
  "dependencies": {
    "pod-install": "^1.0.7"
  },
  "_npx": {
    "packages": [
      "pod-install"
    ]
  }
}

この状態でnpx pod-install --versionを実行してみる。

~ $ npx pod-install --version
1.0.7

pod-installのダウンロードは走ってなさそう = npmキャッシュから実行されてそう。

次に@latestを付けて実行してみる。

~ $ npx pod-install@latest --version
Need to install the following packages:
pod-install@1.0.7
Ok to proceed? (y)

1.0.7

数日前に実行したばかりなのでバージョンは変わってないが、@latestを付けると最新版(1.0.7)のインストール手順が増えた。

補足

今回、latestの都合上、npx xxx@latest実行後に新しいバージョンがリリースされてから再度npx xxx@latestを実行して再インストールが走るかの実験は出来ていない(これが一番重要なんだけども。。そこまで頑張るモチベもなかった)。上手いことバージョン差異を検知して最新版をインストールしてくれるのか。
pod-installの新しいバージョンが出たら試してみようと思う。

Discussion