◆ n-install でインストールしないと管理者権限必要で使いづらい
  ◆ dnf で入れた Node.js 使うと一般ユーザに権限のない場所に node_modules ができる
◆ 使いやすいけど切り替えで指定バージョンのファイル全部コピーしてるみたいで遅い
  ◆ シンボリックリンクでいいのに

nodebrew の必要性なかった?

新しい環境に Node.js を入れようといたのですがこれまで使ってた nodebrew って perl が必要なんですよね
昔 Node.js のバージョン管理ツールを比較して nodebrew をオススメしてるところがあって以来 nodebrew を使っています
はっきり覚えてないのですが そのおすすめの理由がたしか 「デフォルトで入ってる perl があれば動く」 というものだったと思います
適当にググって時期と内容からするとこのブログ
ここの人は Mac みたいですね
Linux なら入ってそう と思ってましたが fedora ではデフォルトで入ってませんでした
CentOS の minimal でもなかった気がします

そうなると nodebrew である必要ない気がしてきたので 他のに移るか考えてみました
ここ 5 年ほどは nodebrew で特別他のを調べたりはしてなかったのですが 新しいバージョン管理ツールが出たというの話はこれと言って耳にしていません
たまに目にするのは昔からある nvm と n くらいです
昔からあるのと言えばあとは nave ですが 全然名前が聞かなくなってもう使われてないのでしょうか

他の候補

掘り出し物でもないかなーといろいろ調べてみましたが ピンとくるものは特になさそうです
表でまとめてくれていたサイトがありました

名前だけ取り出すと

  • nvm
  • n
  • nvm-windows
  • nave
  • nodist
  • nvmw
  • avn
  • nodenv
  • ndenv
  • nenv

ここには nodebrew が載っていなくて 後自分で見つけた nvs というのも入れて 12 個の候補です
Windows 環境は nodist 使っていて今回探してるのは Linux 用なので Windows 用の物を除いて

  • nvm
  • n
  • nave
  • avn
  • nodenv
  • ndenv
  • nenv
  • nodebrew
  • nvs

9 個です

上の nodebrew を紹介していたブログで比較対象にあったのは

  • nvm
  • nave
  • n
  • nodeenv

この 4 つは古くからあるだけあってスターやコミット数は多めです
nave は最近聞かないだけあってこの中だとコミット数少なめで最近はほとんど更新ないみたいです
バージョン管理ツールですし 根本的な使い方を変えるでもないと更新するところない気もします
比較的新しいのだと avn と nvs です

env 系はいっぱいあってもうどれでもいいやって気分になってきます
軽く見た感じだと名前が長いのほど古くてちゃんとメンテナンスされてそうです
他はもう放置されてそうな感じがします

選ばれたのは

nvm は Node.js というかプログラミング言語の実行環境のバージョン管理ツールで最初に使ったものです
最初だからこそよくわかってなかった分もありますが 特別良かった思い出もなく nodebrew にして使いやすくなったという覚えがあるので別にいいかなー ということで×

nave はなんかもう古そう という理由で×

avn は README 見てあんまり情報ないしわかりづらそうでわざわざ苦労してまで使ってみたいものでもないし ということで×

env 系はなんか個人的に良いイメージがない (本当にイメージだけで別に何か苦労させられたことはなかった気がする) ので他に候補があるなら×

最後に nvs ですがこれはすごく迷いました
Github リポジトリを直接見つけたもので 他のみたいにあちことで紹介されてるものでもないですし Windows 対応してるらしいのに Windows の一覧載せていたブログにも載ってないほどです
興味あるものでまともに動くのなら マイナーで新しいのでも困らないと言うかそっちのほうが好みです
Windows でも動くと言うだけでなく PowerShell にも対応してるらしいですし VS Code のサポートまであります
また やろうとしたことないから知らないだけで他にもあるのかもしれませんが ダウンロード先のリモートの URL を変えたり 全体のバージョン切り替えでなくその場でバージョンを指定して実行できたりと機能が多そうです
Windows も同じにツールに揃えられると便利そうですし これはありかなと思ったのですが 考えてみたら バージョン管理ツールにそんなにいろいろ求めてない気がしました

複数のバージョンをインストールできて 切り替えさえできればその他の機能は別になくても困りません
それにそういった最低限な基本の使い方はどれもたいして変わらないです
新しくて情報が少ないなら エラーになったときに自分でソース見てどうにかしないといけないケースもありますし そのときに必要以上の高機能だと面倒なことになる予感しかしません
ちょっと使ってみる程度のものならそれでもいいのですけど 今回はメインで使うもので nodebrew の代わりにするものがあるのかを探してるのでちょっと優先度下げめにします

ということで残ったのが n です
名前的に 「ググるの辛い」 その一言だけで避けていたものです
見てみるとリポジトリの中身はすごくシンプルです
README や package.json などの設定ファイル除けば n という ShellScript ファイル 1 つだけです
その中身も 1000 行ありません

その割に README を見ると 十分にサブコマンドがあります
バージョン指定するだけで そのバージョンがなければインストールしてくれたり 一覧から上下キーで interactive に選べたり (←これ重要) コマンドラインに n と一文字打つだけで良かったり と良い部分が多そうです
そういうわけで n を使ってみることにしました

n のインストール

このコマンドでインストールできるみたいです

$ npm -g i n

ってあれ? npm がいるの??
npm (と Node.js) をいれるために n を使うことにしたのに n を使うために npm がいるなんて……
phpbrew を思い出します

dnf でパッケージインストール必要ならもう perl 入れても良い気がする……
そう思ってたら別の方法もあるみたいです

$ curl -L https://git.io/n-install | bash

さっそくやってみると
$ curl -L https://git.io/n-install | bash
n-install: ERROR:
`git` not found, which is required for operation. GNU Make not found, which is required for operation.
On FreeBSD and PC-BSD, for instance, you can download it with `sudo pkg install gmake`.

git が必要みたいです
git くらい入れても良い気はするのですが dnf で何も入れずに Node.js のバージョン管理はできないものなんですかね

どうせなにか入れるなら公式で ということで npm を dnf から入れる方法にしました

管理者権限必要

dnf からインストールしたら node_modules が /usr/lib/node_modules という場所にあるようです
ここは一般ユーザに書き込み権限がないので

$ npm -g i n

を一般ユーザですると

npm WARN checkPermissions Missing write access to /usr/lib/node_modules

と警告が出て書き込みエラーで失敗します
管理者権限で

# npm -g i n

を実行してインストールが終わっても

user@localhost ~> ll /usr/bin
(略)
n -> ../lib/node_modules/n/bin/n
(略)
user@localhost ~> ll /usr/lib/node_modules/
合計 4.0K
drwx------ 4 root root 103 5月 6 17:58 n/
drwxr-xr-x 9 root root 4.0K 5月 6 17:58 npm/
user@localhost ~> ll /usr/lib/node_modules/n
ls: ディレクトリ '/usr/lib/node_modules/n' を開くことが出来ません: Permission denied

n コマンドは 「/usr/lib/node_modules/n/bin/n」 へのシンボリックリンクです
ここに権限がないのでアクセスできません

記事書くときの確認用に別環境でも試したらこっちだと npm と一緒で権限が 755 だったので中を見れましたが n のコマンドを実行すると

user@localhost ~> n latest
mkdir: ディレクトリ `/usr/local/n' を作成できません: 許可がありません
mkdir: ディレクトリ `/usr/local/n' を作成できません: 許可がありません

install : node-v10.1.0
mkdir : /usr/local/n/versions/node/10.1.0
mkdir: ディレクトリ `/usr/local/n' を作成できません: 許可がありません

Error: sudo required

と管理者権限を要求されます
ここも管理者としてインストールします

> sudo n stable
> sudo n
node/10.0.0

ですが バージョンを確認すると

> sudo node --version
v10.0.0
> node --version
v8.11.0

管理者では切り替わってますが一般ユーザでは切り替わってません
インストールさえされれば パーミッション緩めてパス通せば出来なくはないのですが 手間が多すぎます
この面倒くささなら nodebrew のほうがマシです

n-install

上で書いたもうひとつの git が必要な方法ですが よく見たらサードパーティ製のツールみたいです
https://github.com/mklement0/n-install

ついでなのでこっちも試してみます

git と make をいれて

$ curl -L https://git.io/n-install | bash

を実行するとこんなメッセージがでました

You are ABOUT TO INSTALL n, the Node.js VERSION MANAGER, in:

/home/rzs/n

Afterward, THE FOLLOWING Node.js VERSION(S) WILL BE INSTALLED,
and the first one listed will be made active;
'lts' refers to the LTS (long-term stability) version,
'stable' refers to the latest stable version, and
'latest' to the latest available version.
'-' means that no versions will be installed:

stable

If your shell is Bash, Ksh, or Zsh, the relevant initialization file will be
modified in order to:
- export environment variable $N_PREFIX.
- ensure that $N_PREFIX/bin is in the $PATH
For any other shell you'll have to make these modifications yourself (details
to follow).

For more information, see https://git.io/n-install-repo
===
CONTINUE (y/N)? y
-- Cloning https://github.com/tj/n to '/home/rzs/n/n/.repo'...
-- Running local n installation to '/home/rzs/n/bin'...
n-install: WARNING:
Automatic modification of the initialization file for shell
/bin/fish is not supported.
For n and the Node.js versions managed by it to work correctly,
you must MANUALLY ADD THE EQUIVALENT OF THE FOLLOWING TO YOUR SHELL'S
INITIALIZATION FILE:

export N_PREFIX="$HOME/n"; [[ :$PATH: == *":$N_PREFIX/bin:"* ]] || PATH+=":$N_PREFIX/bin" # Added by n-install (see http://git.io/n-install-repo).
-- Shell initialization file '' updated.
-- Installing helper scripts in '/home/rzs/n/bin'...
-- Installing the requested Node.js version(s)...
1 of 1: stable...

install : node-v10.0.0
mkdir : /home/rzs/n/n/versions/node/10.0.0
fetch : https://nodejs.org/dist/v10.0.0/node-v10.0.0-linux-x64.tar.gz
######################################################################## 100.0%
installed : v10.0.0

=== n successfully installed.
The active Node.js version is: v10.0.0

Run `n -h` for help.
To update n later, run `n-update`.
To uninstall, run `n-uninstall`.

IMPORTANT: Modify your shell initialization file as described above
before using n and Node.js.
===

continue ? と聞かれたので y でつづけると自動で stable のインストールもしてくれました
ただ fish シェルを使っていたので

If your shell is Bash, Ksh, or Zsh, the relevant initialization file will be
modified in order to:
- export environment variable $N_PREFIX.
- ensure that $N_PREFIX/bin is in the $PATH
For any other shell you'll have to make these modifications yourself (details
to follow).

と書いていたとおりで

n-install: WARNING:
Automatic modification of the initialization file for shell
/bin/fish is not supported.
For n and the Node.js versions managed by it to work correctly,
you must MANUALLY ADD THE EQUIVALENT OF THE FOLLOWING TO YOUR SHELL'S
INITIALIZATION FILE:

export N_PREFIX="$HOME/n"; [[ :$PATH: == *":$N_PREFIX/bin:"* ]] || PATH+=":$N_PREFIX/bin" # Added by n-install (see http://git.io/n-install-repo).

fish シェルはサポートしてないので シェル初期化時の環境変数設定は自分でやってと言われました

[[ :$PATH: == *":$N_PREFIX/bin:"* ]] || PATH+=":$N_PREFIX/bin"

とか fish シェルの shell script でどう書くかわからないので単純に

export N_PREFIX="$HOME/n"
export PATH="$PATH:$N_PREFIX/bin"

にしました
すでにあるなら追加しないという処理ですが すでにあるわけがないので気にせず追加するようにしました

こっちのインストーラを使うとユーザフォルダ直下の 「n」 フォルダに n や Node.js がインストールされます
なので nodebrew に近い形で 管理者権限は不要です

フォルダ構造はこうなっていました

rzs@fedora ~> tree n -L 3
n
├── bin
│ ├── n
│ ├── n-uninstall
│ ├── n-update
│ ├── node
│ ├── npm -> ../lib/node_modules/npm/bin/npm-cli.js
│ └── npx -> ../lib/node_modules/npm/bin/npx-cli.js
├── etc
├── include
│ └── node
│ ├── android-ifaddrs.h
│ ├── common.gypi
│ ├── config.gypi
│ ├── libplatform
│ ├── node.h
│ ├── node_api.h
│ ├── node_api_types.h
│ ├── node_buffer.h
│ ├── node_object_wrap.h
│ ├── node_version.h
│ ├── openssl
│ ├── pthread-barrier.h
│ ├── stdint-msvc2008.h
│ ├── tree.h
│ ├── uv-aix.h
│ ├── uv-bsd.h
│ ├── uv-darwin.h
│ ├── uv-errno.h
│ ├── uv-linux.h
│ ├── uv-os390.h
│ ├── uv-posix.h
│ ├── uv-sunos.h
│ ├── uv-threadpool.h
│ ├── uv-unix.h
│ ├── uv-version.h
│ ├── uv-win.h
│ ├── uv.h
│ ├── v8-inspector-protocol.h
│ ├── v8-inspector.h
│ ├── v8-platform.h
│ ├── v8-profiler.h
│ ├── v8-testing.h
│ ├── v8-util.h
│ ├── v8-value-serializer-version.h
│ ├── v8-version-string.h
│ ├── v8-version.h
│ ├── v8.h
│ ├── v8config.h
│ ├── zconf.h
│ └── zlib.h
├── lib
│ └── node_modules
│ └── npm
├── n
│ └── versions
│ ├── io
│ └── node
└── share
├── doc
│ └── node
├── man
│ └── man1
└── systemtap
└── tapset
rzs@fedora ~> tree n/n/versions/node -L 3
n/n/versions/node
└── 10.0.0
├── CHANGELOG.md
├── LICENSE
├── README.md
├── bin
│ ├── node
│ ├── npm -> ../lib/node_modules/npm/bin/npm-cli.js
│ └── npx -> ../lib/node_modules/npm/bin/npx-cli.js
├── include
│ └── node
├── lib
│ └── node_modules
└── share
├── doc
├── man
└── systemtap

n/n/versions/node 以下にインストールした各バージョンが保存されます
使っていてちょっと気になってのは

$ n 8

で 8 系に切り替えると node や npm ファイルはクリアされて新規にコピーされてるようです
シンボリックリンクではありません
-g をつけて 「n/lib/node_modules」 以下へインストールしたものは基本共通で Node.js のバージョンを変えても残りますが npm だけはバージョン切り替えで再作成されるようです
npm を 6 にアップグレードしたのにバージョン変えると 5 に戻っていて Node.js のバージョンを戻しても npm のバージョンは 5 のままでした

node の実行ファイルだけならともかく npm フォルダ全部をコピーする分 切り替えが遅めです
nodebrew だとたしかシンボリックリンクで切り替えは高速だった記憶があります

dnf の npm よりは良くなりましたが git や make を入れるなら perl 入れて nodebrew のほうが良いのかもしれません