7rikazhexde’s tech log

技術的な興味関心、備忘録、アウトプットなどを書いています。

Rust製Node.js用パッケージ管理ツールのVoltaについて

はじめに

node,npmのパッケージ管理ツールとしてnodenvを使用していましたが、Voltaが良さそうなので試しに導入することにしました。Volta はNode.js環境とそのエコシステム(npmYarnpnpmなど)を効率的に管理するためのツールとして開発されています。

Voltaのインストール方法

実行環境は下記のとおりです。

wsl --version
WSL バージョン: 2.2.4.0
カーネル バージョン: 5.15.153.1-2
WSLg バージョン: 1.0.61
MSRDC バージョン: 1.2.5326
Direct3D バージョン: 1.611.1-81528511
DXCore バージョン: 10.0.26091.1-240325-1447.ge-release
Windows バージョン: 10.0.22631.4037

また、nodenvはインストール済みでそのまま残します。
後述しますが、環境変数などで注意が必要ですが、基本的には独立し、それぞれ動作に影響は与えない認識なのでそのままにします。

$ nodenv --version
nodenv 1.5.0+49.a008938

インストールは公式手順に従いします。

docs.volta.sh

$ curl https://get.volta.sh | bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 10460  100 10460    0     0  15761      0 --:--:-- --:--:-- --:--:-- 15753
  Installing latest version of Volta (2.0.1)
    Checking for existing Volta installation
    Fetching archive for Linux, version 2.0.1
######################################################################## 100.0%
    Creating directory layout
  Extracting Volta binaries and launchers
    Finished installation. Updating user profile settings.
Updating your Volta directory. This may take a few moments...
success: Setup complete. Open a new terminal to start using Volta!

シェルを再起動すると以下の環境変数が追加されます。

export VOLTA_HOME="$HOME/.volta"
export PATH="$VOLTA_HOME/bin:$PATH"

コマンドも実行できるようになりました。

$ volta --version
2.0.1
$ volta --help
The JavaScript Launcher ⚡

    To install a tool in your toolchain, use `volta install`.
    To pin your project's runtime or package manager, use `volta pin`.

Usage: volta [OPTIONS] [COMMAND]

Commands:
  fetch        Fetches a tool to the local machine
  install      Installs a tool in your toolchain
  uninstall    Uninstalls a tool from your toolchain
  pin          Pins your project's runtime or package manager
  list         Displays the current toolchain
  completions  Generates Volta completions
  which        Locates the actual binary that will be called by Volta
  setup        Enables Volta for the current user / shell
  run          Run a command with custom Node, npm, pnpm, and/or Yarn versions
  help         Print this message or the help of the given subcommand(s)

Options:
      --verbose
          Enables verbose diagnostics

      --very-verbose
          Enables trace-level diagnostics

      --quiet
          Prevents unnecessary output

  -v, --version
          Prints the current version of Volta

  -h, --help
          Print help (see a summary with '-h')

次にバージョンを確認してみます。

コマンドについて

コマンドについてnodenv環境との併用を踏まえた確認をします。

nodenvでインストールしたnodeのバージョン

$ node -v
v22.8.0

voltaでインストールした後のnodeのバージョン

$ volta install node
success: installed and set node@20.17.0 (with npm@10.8.2) as default
# 変更された。
$ node -v
v20.17.0

これはnodeおよび、npmのパスがvolta-shimシンボリックリンクであり、volta-shimバイナリが要求されたコマンドに応じて実行されているためです。
なので、nodenvのパスがvoltaよりも後に追加される場合はコマンドの挙動も変わるため注意が必要という認識です。

一方でnodenvのコマンドはシェルスクリプトで記述されており、依存関係もvoltaとは異なるため競合はしないという理解です。
補足としてnodenvで同様にサポートするnpm,npxについても同様にシェルスクリプトで記述されています。

$ file $HOME/.nodenv/bin/../libexec/nodenv
/home/[username]/.nodenv/bin/../libexec/nodenv: Bourne-Again shell script, ASCII text executable

$PATHの確認

$ echo $PATH
/home/[username]/.volta/bin:/home/[username]/.local/bin:/home/[username]/.volta/bin:/home/[username]/.cargo/bin:/home/[username]/.nodenv/shims:/home/[username]/.nodenv/bin:

コマンドのフルパス

$ which node
/home/[username]/.volta/bin/node
$ which npm
/home/[username]/.volta/bin/npm

$VOLTA_HOME/binの確認

$ ls -l $VOLTA_HOME/bin
node -> /home/[username]/.volta/bin/volta-shim
npm -> /home/[username]/.volta/bin/volta-shim
npx -> /home/[username]/.volta/bin/volta-shim
pnpm -> /home/[username]/.volta/bin/volta-shim
volta
volta-migrate
volta-shim
yarn -> /home/[username]/.volta/bin/volta-shim
yarnpkg -> /home/[username]/.volta/bin/volta-shim

バイナリ実行ファイルの確認

$ file $VOLTA_HOME/bin/volta
/home/[username]/.volta/bin/volta: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=eac7f1dee35e2c47a85ac156c4c767a23c6d6982, with debug_info, not stripped

$ file $VOLTA_HOME/bin/volta
/home/[username]/.volta/bin/volta: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=eac7f1dee35e2c47a85ac156c4c767a23c6d6982, with debug_info, not stripped

$ file $VOLTA_HOME/bin/volta-migrate
/home/[username]/.volta/bin/volta-migrate: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=b98371e4a4976765b8be5a6356e1618fc443732b, with debug_info, not stripped

使用例

以下では個人プロジェクトを例にコマンドの使用例を示します。

github.com

volta install node@x.x.xでnodeをインストールします。 デフォルトをv22.8.0とします。

$ volta list all
⚡️ User toolchain:

    Node runtimes:
        v20.16.0
        v20.17.0
        v22.8.0 (default)

    Package managers:
        Yarn:
            v4.4.1-git.20240825.hash-b2f315f6 (default)

    Packages:

次に現在のnodenvの情報を記載します。

# global設定
$ nodenv versions
  system
  22.6.0
* 22.7.0 (set by /home/[username]/dev/twitter-video-dl-node/.node-version)
  22.8.0

# local設定
$ nodenv versions
  system
* 22.6.0 (set by /home/[username]/.nodenv/version)
  22.7.0
  22.8.0

プロジェクト構成を示します。

$ tree -a -L 1
.
├── .git
├── .gitignore
├── .node-version
├── README.md
├── package-lock.json
├── package.json
├── src
├── test
└── twitter-video-dl-node.js

3 directories, 6 files

この状態でnpm installを実行すると22.8.0でインストール動作します。 これはvoltaで追加したnodedefaultです。

$ npm install --verbose
# 省略
Run `npm audit` for details.
npm verbose cwd /home/[usertname]/dev/twitter-video-dl-node
npm verbose os Linux 5.15.153.1-microsoft-standard-WSL2
npm verbose node v22.8.0
npm verbose npm  v10.8.2
npm verbose exit 0
npm info ok

次に実際のプロジェクト以下でバージョンを指定します。 するとpackage.jsonvoltaセクションが追加されます。

$ volta pin node@20.16.0
success: pinned node@20.16.0 (with npm@10.8.1) in package.json
  "volta": {
    "node": "20.16.0"
  }
$ volta list all
⚡️ User toolchain:

    Node runtimes:
        v20.16.0 (current @ /home/[username]/dev/twitter-video-dl-node/package.json)
        v20.17.0
        v22.8.0 (default)

    Package managers:
        Yarn:
            v4.4.1-git.20240825.hash-b2f315f6 (default)

    Packages:

npm installを実行します。
すると、voltaでlocal指定(pin)した20.16.0が追加されました。

$ npm install --verbose
# 省略
Run `npm audit` for details.
npm verbose cwd /home/[usertname]/dev/twitter-video-dl-node
npm verbose os Linux 5.15.153.1-microsoft-standard-WSL2
npm verbose node v20.16.0
npm verbose npm  v10.8.1
npm verbose exit 0

次にvoltaで追加したnodeを削除した場合を確認します。

$ rm -rf ~/.volta/tools/image/node/*

$ volta list all
⚡️ No Node runtimes installed!

    You can install a runtime by running `volta install node`. See `volta help install` for
    details and more options.

package.jsonvoltaセクションが記載されている場合はnodeを追加してインストール処理を実行されました。

$ rm -rf node_modules
$ npm install --verbose
npm verbose cli /home/[usertname]/.volta/tools/image/node/20.16.0/bin/node /home/[usertname]/.volta/tools/image/node/20.16.0/bin/npm
npm info using npm@10.8.1
npm info using node@v20.16.0
npm verbose title npm install
npm verbose argv "install" "--loglevel" "verbose"
# 省略
npm verbose cwd /home/[usertname]/dev/twitter-video-dl-node
npm verbose os Linux 5.15.153.1-microsoft-standard-WSL2
npm verbose node v20.16.0
npm verbose npm  v10.8.1
npm verbose exit 0
npm info ok

$ volta list all
⚡️ User toolchain:

    Node runtimes:
        v20.16.0 (current @ /home/[usertname]/dev/twitter-video-dl-node/package.json)

    Package managers:
        Yarn:
            v4.4.1-git.20240825.hash-b2f315f6 (default)

    Packages:

一方でpackage.jsonvoltaセクションが記載を削除してもdefaultのバージョンを追加してインストール動作しました。
これはデフォルトの情報をplatform.jsonで管理しているためです。

$ cat ~/.volta/tools/user/platform.json
{
  "node": {
    "runtime": "22.8.0",
    "npm": null
  },
  "pnpm": null,
  "yarn": "4.4.1-git.20240825.hash-b2f315f6"
}

platform.jsonを削除した場合は、nodenvのバージョン(下記ではshimによるカレントディレクトリのバージョン)で追加されました。

$ npm install --verbose
npm verbose cli /home/[usertname]/.nodenv/versions/22.7.0/bin/node /home/[usertname]/.nodenv/versions/22.7.0/bin/npm
npm info using npm@10.8.2
npm info using node@v22.7.0
npm verbose title npm install
npm verbose argv "install" "--loglevel" "verbose"
# 省略
Run `npm audit` for details.
npm verbose cwd /home/[usertname]/dev/twitter-video-dl-node
npm verbose os Linux 5.15.153.1-microsoft-standard-WSL2
npm verbose node v22.7.0
npm verbose npm  v10.8.2
npm verbose exit 0
npm info ok

これらの仕様はmain/crates/volta-core/src/run/mod.rsから確認することができます。

以上の確認から、nodenvの場合はnodenv local x.x.x.node-versionで追加されますが、両方存在していてもパスの指定により競合することはないことがわかりました。

補足:VoltaのNode runtime(default)を変更する方法

voltaにはnodenvにおけるnodenv global <version>のようなコマンドはありません。

Voltaではvolta install node@<version>のように実行すれば設定されます。

<変更前>VoltaのNode runtime(default)

$ volta list all
⚡️ User toolchain:

    Node runtimes:
        v20.17.0
        v22.7.0 (default)
        v22.8.0

    Package managers:
        Yarn:
            v4.4.1-git.20240825.hash-b2f315f6 (default)

    Packages:

volta install node@<version>を実行する

$ volta install node@22.8.0
success: installed and set node@22.8.0 (with npm@10.8.2) as default

<変更後>VoltaのNode runtime(default)

$ cat ~/.volta/tools/user/platform.json
{
  "node": {
    "runtime": "22.7.0",
    "npm": null
  },
  "pnpm": null,
  "yarn": "4.4.1-git.20240825.hash-b2f315f6"
$ cat ~/.volta/tools/user/platform.json
{
  "node": {
    "runtime": "22.8.0",
    "npm": null
  },
  "pnpm": null,
  "yarn": "4.4.1-git.20240825.hash-b2f315f6"

まとめ

Node.js向けのパッケージツールであるVoltaのインストール方法について紹介しました。

また、実際のプロジェクトとnodenvを用いた使用例の確認から以下の点がわかりました。

  • nodenvvoltaはパスやデフォルトのバージョン情報を削除しなければ競合しない
  • voltaでは、プロジェクトに対してローカル指定する場合はpackage.jsonにvoltaフィールドを追加する(pinコマンドを実行する)。
  • voltaでは、nodenvのように.node-version管理ではなく、package.jsonplatform.jsonで管理され、nodenpm等は、シェルスクリプト形式ではなく、実行バイナリファイル形式で要求されたコマンドに応じて実行される。

最後に、ここ数年でRust製のプロジェクトは増えており、Pythonなど他の言語でもツールとして公開されることが増えてきました。利用しやすい(特に速度面)反面、環境依存など考慮すべき点など注意が必要ですが、使いやすさがあり、速くてバグが少ないのであれば利用したいという思いです。その点、Voltaは移行も使い勝手も問題ない印象のため、今後利用していきたいと感じました。また、気になる点があれば追記をしたいと思います。

以上です。