◆ ツールのバージョン管理ツール
◆ Node.js や npm 以外に Deno や Python や Rust なども対象になってる
◆ プラグイン式なので管理するツールを増やせるし自作もできる
◆ 使い勝手は Volta に近く フォルダごとにバージョンが設定できたりして便利

Node.js のバージョン管理

Node.js で特定のバージョンを使いたいときがあります
Node.js はわりと互換性はある方ですが ときどき新しくして動かなくなることもあります

Docker

最近は Docker で指定バージョンを使うようにしていたのですが 手間も多かったりします
あと WSL と Docker を経由するのでパフォーマンスなどに問題が出ることもあります
例えばビルドするときだと Docker コンテナから WSL 経由で Windows のファイルシステムを見に行く場合かなり遅いです
Windows 上で実行するのに比べ数倍の時間がかかり 10 分以上かかるとかが普通になるほどに遅かったりします

Nodist

やっぱり Windows 環境でも Node.js のバージョン管理ツールを入れておいたほうが便利です
Windows となると昔使っていたのは Nodist です
ただ結構前からメンテされてなくてインストールに問題が起きるなどがあり 使わなくなりました

数年前にメンテナが変わって Go に置き換えたバージョンの 0.10.3 がつい先週 stable リリースになりましたが 出たばかりなのでまだ様子見です
https://github.com/nodists/nodist

サンドボックス環境みたいな Linux 環境なら別にいいですが 普段使いの Windows にインストールとなると出たばかりは不安がありますし
これは近いうちに Windows Sandbox 内で試してみるとして 今は選択肢から外します

Volta

Docker 移行前に使ってたバージョン管理ツールです
https://github.com/volta-cli/volta

Rust 製で高速かつ Node.js 以外のツールも管理できたりフォルダごとにバージョンを指定するピン機能があったり便利でした
Linux での使用でしたが たしか Windows もサポートしていたはずです

きっと色々更新されてるだろうし 最新版を Windows に入れてみようかとリポジトリを覗いたのですが あまり更新されてないようです
Issue も溜まってますし 案の定プロジェクトステータスはどんな状態?という issue が立っていました

サポートしてた会社が積極的に資金提供しなくて停滞気味のようです
ただ今後の方針などについて関係者で話し合ったりしたようで今後また活発に開発が再開される可能性はあるようです

とはいえ バグ報告などを見てると 現状は最近のバージョンのインストールで問題が起きるなど あまり安定していなさそうです

proto

そんな状況だったので Volta の issue で紹介されていた proto を使ってみることにしました
https://moonrepo.dev/proto

これも Rust 製で Node.js のバージョン管理ができるツールです
Node.js に限らず Deno/Bun/Python/Rust/Yarn/pnpm など色々なツールに対応してるようです
プラグイン式なので自作ツールでもプラグインを作れば対応できるようです

proto 自体のインストールは curl でダウンロードしたスクリプトを実行する形で行なえます

curl -fsSL https://moonrepo.dev/install/proto.sh | bash

Windows 版も ps1 ファイルで用意されていて iex にパイプする形で実行します

irm https://moonrepo.dev/install/proto.ps1 | iex

まずは試しに Linux のコンテナ内でどんな事ができるのか試してみます

ちなみにインストール後には自動で .bashrc にパスの export が追加されました
自分で設定する手間がかからないのでいいですね
bash に限らずシェルを判定して fish を使ってるなら config.fish ファイルを更新してくれます
内部的には 「proto setup --profile」 コマンドが使われてるようでした

ツールのインストール

「proto install」 のあとにツール名を指定します
バージョンも指定するならスペースを入れて指定します

proto install node
proto install node 18

インストールすると node コマンドが使えるようになります
「proto run node」 を使うこともできます
「proto run」 を使うとツール名の後はバージョンを指定することになるので ツールに引数を渡す場合は 「--」 をはさみます

[root@2b5acc089974 opt]# node -v
v21.4.0
[root@2b5acc089974 opt]# proto run node -- -v
v21.4.0

このときの node コマンドは .proto/shims/node にあって 中身は shell script で 「proto run」 を呼び出しています

[root@2b5acc089974 opt]# type node
node is hashed (/root/.proto/shims/node)

[root@2b5acc089974 opt]# cat /root/.proto/shims/node
#!/usr/bin/env bash
set -e

if [ -n "$PROTO_DEBUG" ]; then
set -x
echo "Running with node.sh shim"
fi

exec proto run node -- "$@"

この仕組みでバージョンを切り替えれるわけですね

実際のバージョンの実行ファイルは 「proto bin」 コマンドで見れます

[root@2b5acc089974 opt]# proto bin node
/root/.proto/tools/node/21.4.0/bin/node

リスト

「proto tool list」 でツールのリストを見れます

[root@2b5acc089974 opt]# proto tool list
[ INFO 2023-12-15 13:19:52] proto::commands::tool::list:list Loading tools...

node - Node.js
Store: ~/.proto/tools/node
Aliases:
4.9.1 - argon
6.17.1 - boron
8.17.0 - carbon
10.24.1 - dubnium
12.22.12 - erbium
14.21.3 - fermium
16.20.2 - gallium
18.19.0 - hydrogen
20.10.0 - iron
21.4.0 - latest
20.10.0 - stable
Versions:
20.10.0 - installed 12/15/23
21.4.0 - installed 12/15/23, last used 12/15/23, default version

npm - npm
Store: ~/.proto/tools/npm
Aliases:
10.2.5 - latest
1.4.29 - latest-1
2.15.12 - latest-2
3.10.10 - latest-3
4.6.1 - latest-4
5.10.0 - latest-5
6.14.18 - latest-6
7.24.2 - latest-7
10.2.5 - next-10
2.15.12 - next-2
3.10.10 - next-3
4.6.1 - next-4
5.10.0 - next-5
6.14.18 - next-6
7.24.2 - next-7
8.19.4 - next-8
9.9.2 - next-9
6.14.18 - v6.14-next
Versions:
10.2.3 - installed 12/15/23
10.2.4 - installed 12/15/23, default version

インストール済みバージョンは Versions に並んでいます
コマンドの list のあとに node などのツール名を指定すると絞り込めます
この一覧に並ぶのは一つ以上のバージョンがインストールされているツールのみです
インストールされてないと名前を指定しても alias の確認はできないです

単純にインストールされてるバージョンを見たいだけなら 「proto list node」 のように書けます

[root@2b5acc089974 opt]# proto list node
20.10.0
21.4.0

インストール可能なバージョンを見たいなら 「proto list-remote npm」 のように書けます

[root@2b5acc089974 opt]# proto list-remote npm
(長いので略)
10.0.0-pre.0
10.0.0-pre.1
10.0.0
10.1.0
10.2.0
10.2.1
10.2.2
10.2.3
10.2.4
10.2.5

これらのコマンドの場合はツール名が必須です

プラグイン

プラグインのリストも確認できます
デフォルトでこうなっています

[root@2b5acc089974 opt]# proto tool list-plugins
[ INFO 2023-12-15 13:31:48] proto::commands::tool::list_plugins:list_plugins Loading plugins...

bun - Bun v0.6.0
Source: https://github.com/moonrepo/bun-plugin/releases/download/v0.6.0/bun_plugin.wasm

deno - Deno v0.6.0
Source: https://github.com/moonrepo/deno-plugin/releases/download/v0.6.0/deno_plugin.wasm

go - Go v0.6.0
Source: https://github.com/moonrepo/go-plugin/releases/download/v0.6.0/go_plugin.wasm

node - Node.js v0.6.1
Source: https://github.com/moonrepo/node-plugin/releases/download/v0.6.1/node_plugin.wasm

npm - npm v0.6.1
Source: https://github.com/moonrepo/node-plugin/releases/download/v0.6.1/node_depman_plugin.wasm

pnpm - pnpm v0.6.1
Source: https://github.com/moonrepo/node-plugin/releases/download/v0.6.1/node_depman_plugin.wasm

python - Python v0.4.0
Source: https://github.com/moonrepo/python-plugin/releases/download/v0.4.0/python_plugin.wasm

rust - Rust v0.5.0
Source: https://github.com/moonrepo/rust-plugin/releases/download/v0.5.0/rust_plugin.wasm

yarn - yarn v0.6.1
Source: https://github.com/moonrepo/node-plugin/releases/download/v0.6.1/node_depman_plugin.wasm

これがインストールできるツールの一覧ということになります
自分で wasm を作ってプラグインとして追加するとここにないものも proto で管理できるようになります
deno のプラグインはこんな感じなので参考に作ってみることもできそうですね
https://github.com/moonrepo/deno-plugin

高度なことをしないなら wasm にしなくても toml ファイルで設定を書くだけでも良いみたいです

ピン

Volta と同じようにピン機能があります
フォルダに対してツールとバージョンを設定できます
そのフォルダの中にいれば指定されたバージョンが使えます

proto では .prototools というファイルに設定を書きます
ピンの設定なら 「proto pin」 コマンドを使って .prototools ファイルを作ることもできます

[root@2b5acc089974 opt]# proto pin node 20
[ INFO 2023-12-15 13:29:03] proto::commands::pin:pin Set the Node.js version to ~20
[root@2b5acc089974 opt]# cat .prototools
node = "~20"
[root@2b5acc089974 opt]# node -v
v20.10.0
[root@2b5acc089974 opt]# proto bin node
/root/.proto/tools/node/20.10.0/bin/node
[root@2b5acc089974 opt]# cd /
[root@2b5acc089974 /]# node -v
v21.4.0
[root@2b5acc089974 /]# proto bin node
/root/.proto/tools/node/21.4.0/bin/node

Node.js バージョンを 20 にした フォルダ内では 20.10.0 が使われて そのフォルダの外に出ると 21.4.0 が使われています

use

「proto use」 を使うことで .prototools からツールをインストールできます

[root@2b5acc089974 node16]# cat .prototools
node = "16.0.0"
yarn = "3.0"
[root@2b5acc089974 node16]# proto use
(略)
[root@2b5acc089974 node16]# proto bin node
/root/.proto/tools/node/16.0.0/bin/node
[root@2b5acc089974 node16]# proto bin yarn
/root/.proto/tools/yarn/3.0.2/bin/yarn.js

バージョンの検出は .prototools 以外からもしてくれます
例えば package.json に engines を書いておくと

{
"engines": {
"node": "18.x"
}
}

「proto use」 時に Node.js の 18 をインストールしてくれます

Git が必要

一部プラグインはインストール時に Git を使うので Git コマンドにパスが通ってる必要があります
ドキュメントのインストール方法をちゃんと読むと Git が必要と記載されているのですが それに気づいてなくて困りました

Node.js はインストールできるのに Deno では失敗してこんなエラーになります

Error: plugin::call_func::failed

× Call failed

│ Caused by:
│ 0: error while executing at wasm backtrace:
│ 0: 0x5e754 - <unknown>!<wasm function 841>
│ 1: No such file or directory (os error 2)

No such file or directory と言われますがこれだけだと何が無いのかわかりません
issue で検索してもそれらしいのがなかったので まだ未完成なのかと半分あきらめてました
ただログの表示方法を設定できて 「--log trace」 にすると trace レベルのログまで表示できます

proto install deno --log trace

にしてエラー直前のログを見るとこんなのがありました

[TRACE 38:06.978] proto_wasm::exec_command:install  Executing command from plugin  command="git" args=["ls-remote", "--tags", "--sort", "version:refname", "https://github.com/denoland/deno"] env_vars={}
[TRACE 38:06.979] starbase::app Running shutdown phase with 1 systems

git コマンドを実行してそうです
git 入ってなかったかもと思って git コマンドを実行したらエラーでした
git を入れて無事解決できました
ありがちなエラーだと思うので もう少し親切なエラーになってくれるといいのですけどね

proto の更新

proto 自身をアップデートするコマンドも用意されています

proto upgrade

アンインストール

アンインストールは uninstall コマンドです

proto uninstall node 16
proto uninstall yarn

バージョンを指定しない場合は全てのバージョンのアンインストールです
この場合は確認のプロンプトが出ます

[root@2b5acc089974 opt]# proto uninstall yarn
Purge all of yarn at ~/.proto/tools/yarn? [y/n]

これでいいかもと思ったけど

Volta だと npm パッケージのコマンドラインツールもインストールできたので その点では不足しています
ですが個人的にはその機能はほぼ使ってなかったので Volta の代わりに proto で良さそうです
と思っていたのですが Windows で試すと Node.js のインストール時に証明書エラーです

Error: plugin::http

× Failed to make HTTP request for https://nodejs.org/download/release/v21.4.0/node-v21.4.0-win-x64.zip.
├─▶ error sending request for url (https://nodejs.org/download/release/v21.4.0/node-v21.4.0-win-x64.zip): error
│ trying to connect: invalid peer certificate: UnknownIssuer
├─▶ error trying to connect: invalid peer certificate: UnknownIssuer
╰─▶ invalid peer certificate: UnknownIssuer

invalid peer certificate: UnknownIssuer

と言われます
ブラウザで直接 URL にアクセスしても証明書エラーは出ないのですけど
issue では類似の問題があったようですが 解決済になっています
https://github.com/moonrepo/proto/issues/204

これより新しい 0.25.2 なのですけどね
Windows は対応されなかったのでしょうか