7rikazhexde’s tech log

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

Macでnodenvをインストールする

前書き

Node.jsのバージョン管理ツールとしてnを使用していましたが、
brew doctorを実行したところ以下のwarningが出ました。

% brew doctor
Please note that these warnings are just used to help the Homebrew maintainers
with debugging if you file an issue. If everything you use Homebrew for is
working fine: please don't worry or file an issue; just ignore this. Thanks!

Warning: You have unlinked kegs in your Cellar.
Leaving kegs unlinked can lead to build-trouble and cause formulae that depend on
those kegs to fail to run properly once built. Run `brew link` on these:
  node

nとbrewコマンドでインストールしたnodeの設定に問題があり、
nodeコマンドの実体についてリンクを設定し直せばwarningは解消できそうでしたが、
Pythonのバージョン管理としてpyenvを使用していることもあり、同様に管理可能なNode.js向けに開発されたバージョン管理ツールであるnodenvをインストールすることにしました。
本記事ではインストール時に確認した内容のまとめになります。

nとnode(npm)を削除する

以下の記事を参考にさせていただきました。
手順は同じですが、./zshrcを変えていたので関連する箇所は個別に修正しました。
nパッケージを完全にアンインストールする

brewコマンドでnode,npmがアンインストールされていることを確認します。

% brew node
Error: Unknown command: node
% brew npm
Error: Unknown command: npm

nodenvをインストールする

nodenvのインストールは以下の記事を参考にさせていただきました。
nodenvでNode.jsのバージョンを切り替える

Homebrewでnodenvをインストールします。

# https://github.com/nodenv/nodenv#homebrew-on-macos
# Homebrew on macOS
% brew install nodenv
Running `brew update --auto-update`...
==> Downloading https://ghcr.io/v2/homebrew/core/node-build/manifests/4.9.87
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/node-build/blobs/sha256:4187ec6
==> Downloading from https://pkg-containers.githubusercontent.com/ghcr1/blobs/sh
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/nodenv/manifests/1.4.0
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/nodenv/blobs/sha256:a20f7a9c8ce
==> Downloading from https://pkg-containers.githubusercontent.com/ghcr1/blobs/sh
######################################################################## 100.0%
==> Installing dependencies for nodenv: node-build
==> Installing nodenv dependency: node-build
==> Pouring node-build--4.9.87.all.bottle.tar.gz
🍺  /usr/local/Cellar/node-build/4.9.87: 775 files, 928.6KB
==> Installing nodenv
==> Pouring nodenv--1.4.0.monterey.bottle.tar.gz
🍺  /usr/local/Cellar/nodenv/1.4.0: 34 files, 106.4KB
==> Running `brew cleanup nodenv`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).

zshrcに以下を追加します。

% vi ~/.zshrc
eval "$(nodenv init -)"

nodenv-doctor スクリプトを使用して、nodenv が適切に設定されていることを確認します。

# https://github.com/nodenv/nodenv#homebrew-on-macos
# 4. Verify that nodenv is properly set up using this nodenv-doctor script:
% curl -fsSL https://github.com/nodenv/nodenv-installer/raw/master/bin/nodenv-doctor | bash
Checking for `nodenv' in PATH: /usr/local/bin/nodenv
# nodenvコマンド(エイリアス)のインストール先
Checking for nodenv shims in PATH: OK
Checking `nodenv install' support: /usr/local/bin/nodenv-install (node-build 4.9.87)
# nodenv-installコマンド(エイリアス)のインストール先
Counting installed Node versions: none
  There aren't any Node versions installed under `$HOME/.nodenv/versions'.
  You can install Node versions like so: nodenv install 2.2.4
Auditing installed plugins: OK
<補足> brewコマンドで更新する場合:nodenv,node-buildそれぞれ指定する
# https://github.com/nodenv/nodenv#homebrew-on-macos
# Upgrading with Homebrew
% brew upgrade nodenv node-build
Warning: nodenv 1.4.0 already installed
Warning: node-build 4.9.87 already installed
<補足> nodenvコマンド(実体)の確認
% cd /usr/local/bin/      
% ls -lt nodenv
lrwxr-xr-x  1 [computer_name]  admin  33  8  4 21:04 nodenv -> ../Cellar/nodenv/1.4.0/bin/nodenv

% cd ../Cellar/nodenv/1.4.0/bin/

% pwd
/usr/local/Cellar/nodenv/1.4.0/bin

% ls
nodenv
<補足> nodenv-installコマンド(実体)の確認
% ls -lt nodenv-install
lrwxr-xr-x  1 [computer_name]  admin  46  8  4 21:04 nodenv-install -> ../Cellar/node-build/4.9.87/bin/nodenv-install

% cd ../Cellar/node-build/4.9.87/bin/

% pwd
/usr/local/Cellar/node-build/4.9.87/bin

% ls
node-build      nodenv-install      nodenv-uninstall
# nodenv-install以外も追加されている

nodenv-package-rehashプラグインを追加する

nodenv-package-rehashプラグインはグローバルパッケージをインストールまたはアンインストールするたびに、nodenv rehash を自動的に実行されるようになります。

nodenv init - --no-rehashによる設定について

https://github.com/nodenv/nodenv-package-rehash
Configuration (optional)
With this plugin, rehashing will happen on-demand (when global npm modules are installed/uninstalled). You can take advantage of this and remove nodenv's automatic hashing upon shell initialization. In your shell startup file (.bash_profile, .bashrc, or .zshrc), add the --no-rehash flag to the nodenv init - invocation: eval "$(nodenv init - --no-rehash)" This will speed up your shell initialization since nodenv will no longer need to rehash on every startup.

シェルの起動ファイル (.bash_profile, .bashrc, .zshrc) で、
nodenv init - invocation に --no-rehashフラグを追加することにより、オンデマンドでリハッシュが行われます。
(グローバルなnpmモジュールがインストール/アンインストールされたとき)
これを利用して、シェル初期化時のnodenvの自動ハッシュ化を解除することができます。
nodenvが起動のたびにリハッシュする必要がなくなるので、シェルの初期化が高速化されます。

# install via git (recommended)
% git clone https://github.com/nodenv/nodenv-package-rehash.git "$(nodenv root)"/plugins/nodenv-package-rehash
Cloning into '$HOME/.nodenv/plugins/nodenv-package-rehash'...
remote: Enumerating objects: 820, done.
remote: Total 820 (delta 0), reused 0 (delta 0), pack-reused 820
Receiving objects: 100% (820/820), 111.61 KiB | 4.65 MiB/s, done.
Resolving deltas: 100% (374/374), done.

zshrcを以下に変更

% vi ~/.zshrc
- eval "$(nodenv init -)"
+ eval "$(nodenv init - --no-rehash)"

その後設定を反映させるために以下を実行します。

nodenv package-hooks install --all

nodenv updateプラグインを追加する

nodenvおよびインストールされているすべてのnodenvプラグインを更新するnodenvプラグインです。
インストール方法は上記リンクの通りです。

% git clone https://github.com/nodenv/nodenv-update.git "$(nodenv root)"/plugins/nodenv-update
Cloning into '$HOME/.nodenv/plugins/nodenv-update'...
remote: Enumerating objects: 406, done.
remote: Total 406 (delta 0), reused 0 (delta 0), pack-reused 406
Receiving objects: 100% (406/406), 58.10 KiB | 1.04 MiB/s, done.
Resolving deltas: 100% (131/131), done.

% nodenv update
Updating nodenv
Updating node-build
Updating nodenv-package-rehash
Updating nodenv-update

nodenvコマンドの使い方

指定バージョンのインストール方法

% nodenv install -l

0.1.14
# 省略
18.4.0
18.5.0
18.6.0
18.7.0
chakracore-dev
chakracore-nightly
chakracore-8.1.2
# 省略
iojs-3.3.1
nightly
node-dev
rc
v8-canary

% nodenv install 17.9.1
Downloading node-v17.9.1-darwin-x64.tar.gz...
-> https://nodejs.org/dist/v17.9.1/node-v17.9.1-darwin-x64.tar.gz

WARNING: node-v17.9.1-darwin-x64 is past its end of life and is now unsupported.
It no longer receives bug fixes or security updates.

Installing node-v17.9.1-darwin-x64...
Installed node-v17.9.1-darwin-x64 to $HOME/.nodenv/versions/17.9.1

Installed postinstall/postuninstall package hooks for 17.9.1

% nodenv install 18.6.0
Downloading node-v18.6.0-darwin-x64.tar.gz...
-> https://nodejs.org/dist/v18.6.0/node-v18.6.0-darwin-x64.tar.gz
Installing node-v18.6.0-darwin-x64...
Installed node-v18.6.0-darwin-x64 to $HOME/.nodenv/versions/18.6.0

Installed postinstall/postuninstall package hooks for 18.6.0

% nodenv install 18.7.0 
Downloading node-v18.7.0-darwin-x64.tar.gz...
-> https://nodejs.org/dist/v18.7.0/node-v18.7.0-darwin-x64.tar.gz
Installing node-v18.7.0-darwin-x64...
Installed node-v18.7.0-darwin-x64 to $HOME/.nodenv/versions/18.7.0

Installed postinstall/postuninstall package hooks for 18.7.0

インストールされているNode.jsのバージョン一覧

% nodenv versions      
  17.9.1
  18.6.0
  18.7.0

インストールされているNode.jsをアンインストール方法

% nodenv uninstall 17.9.1
nodenv: remove $HOME/.nodenv/versions/17.9.1? [yN] y
% nodenv versions        
  18.6.0
  18.7.0

バージョン変更

% node -v                
nodenv: node: command not found

The `node' command exists in these Node versions:
  18.6.0
  18.7.0

# グローバル(システム全体)で利用するNode.jsのバージョンを設定する
% nodenv global 18.7.0
% node -v             
v18.7.0

% nodenv versions               
  18.6.0
* 18.7.0 (set by $HOME/.nodenv/version)

# ローカル(カレントディレクトリ配下)で利用するNode.jsのバージョンを設定する
node % mkdir nodenvtest
node % cd nodenvtest 
nodenvtest % nodenv local 18.6.0
nodenvtest % node -v            
v18.6.0

% cat .node-version
# nodenv localコマンドで.node-versionが作成されバージョン情報が書き込まれる 
18.6.0

<参考> latestから5件分のバージョン情報を取得する関数について

nodenv versionsコマンドは全てのバージョンが表示されるので縦長になります。 個人的にバージョンはlatest以前の数バージョンが分かれば十分なので、シェルスクリプトで関数化しました。
引数指定しない場合はlatestから3件分、指定した場合は指定した件数分表示します。

# vi ~/.zshrc
function nodenv_latest {
  n=${1:-3}
  nodenv install --list | grep -E "^ *[0-9]+\.[0-9]+\.[0-9]+$" | sort -V | tail -n ${n}
}

% nodenv_latest
19.8.1
19.9.0
20.0.0

% nodenv_latest 5
19.7.0
19.8.0
19.8.1
19.9.0
20.0.0

補足

バージョンの切り替えについて

nodenvはrbenvからフォークされたプロジェクトです。
https://github.com/nodenv/nodenv/wiki/Why-nodenv%3F

バージョン管理構造はrbenvと同じでshimsコマンドを使用しています。 概念と仕組みについては下記記事でわかりやすく記載されていますので、共有させていただきます。
https://mogulla3.tech/articles/2021-07-10-understanding-rbenv-1/

コマンドの実行ファイル(パス)

% which node
$HOME/.nodenv/shims/node
% which npm 
$HOME/.nodenv/shims/npm

% cd $HOME/.nodenv/shims/
% ls
corepack    node        npm     npx

shims % ls -lt
total 32
-rwxr-xr-x  1 [computer_name]  staff  421  8  4 21:18 npx
-rwxr-xr-x  1 [computer_name]  staff  421  8  4 21:18 npm
-rwxr-xr-x  1 [computer_name]  staff  421  8  4 21:18 node
-rwxr-xr-x  1 [computer_name]  staff  421  8  4 21:18 corepack

バージョン毎のnodeファイル

% ls ~/.nodenv/
plugins     shims       version     versions

% ls ~/.nodenv/versions/   
18.6.0  18.7.0

% ls ~/.nodenv/versions/18.6.0/
CHANGELOG.md    README.md   include     share
LICENSE     bin     lib

シェル固有の Node バージョンを設定する方法

このバージョンはアプリケーション固有のバージョンとグローバルバージョンをオーバーライドする。

% nodenv shell 18.7.0   
% nodenv versions    
  18.6.0
* 18.7.0 (set by NODENV_VERSION environment variable)
% echo $NODENV_VERSION
18.7.0
% env | grep NODENV_VERSION
NODENV_VERSION=18.7.0
# 環境変数としてnodeのバージョンが設定されている

# ただしこのバージョンはshell instanceごとにアクティブなnodeバージョンのためshellを再起動すると削除される。
% env | grep NODENV_VERSION
% nodenv versions          
  18.6.0
* 18.7.0 (set by $HOME/.nodenv/version)

# シェル固有の Node バージョンを未設定にする
% nodenv shell --unset
% nodenv versions          
  18.6.0
* 18.7.0 (set by $HOME/.nodenv/version)
% env | grep NODENV_VERSION

まとめ

参考記事を元にnodenvをインストールしました。特に悩む点はなくインストールできました。
n以外にもnodeのパッケージツールはいくつかありますが、それぞれ設定が必要な場合もあるため少し抵抗がありました。 MacではHomebrewでスクリプトを管理しているため、nodenvも同様に更新を管理できてプロジェクトもフォルダごとにバージョンを区別できるのでより管理がしやすくなるかなと思います。