💡 Node.jsのバージョン管理ツールを改めて選定する【2021年】

開発者「すみません、なんか`npm i`とか`npx`コマンドがうまくいかなくて…」

ワイ「でたー、`cb.apply is not a function`って書いてません？」

開発者「書いてます」

ワイ「ちょっと見てみますね」

https://qiita.com/heppokofrontend/items/0d224c8a77f517a6c9a0

ワイ「……これは`npm`入れなおしたほうが早そうですね…」

ｶﾀｶﾀ…

ワイ（うーん…なぜ未だにnodistで消耗しているのか…😨）

## TL;DR

- nodistはもうやめよう
- 選定するときは、まず選定基準を決めよう
- 関連技術の特徴を洗い出そう
- それらが自分たちの環境にどれくらいマッチするかで比較しよう
- Windowsなら**fnm**がオススメ[^0]！

[^0]: macOSでは「[**n**](https://github.com/tj/n)」を使っています👀

※ バージョン管理ツールがなんだかわからない方は「[Node.jsのバージョン管理ツールとは](https://qiita.com/heppokofrontend/items/1746c73a34d59b124013)」からお読みください。

## うわっ…私の現場、nodist使いすぎ…？

Node.jsの利用が本格化してきたころ、私の周りでは圧倒的に[nodist](https://github.com/nullivex/nodist)が流行していました。
流行ったきっかけは覚えていないですが、業界内でもわりと主流だったように思います。

現在では、メンテナンスされていない[^1]上に不具合が発生する[^2]ケースが様々あるようで、**nodistを実務で使っていくのは難しい**でしょう😢
一刻も早く、別のバージョン管理ツールへの乗り換えを検討しなければなりません。

[^1]: 最終リリースが2019年3月

[^2]: 冒頭のように`cb.apply is not a function`という例外が発生する。`npx`コマンドの導入が手動。npmのバージョンが自動で切り替わらないなどなど。

**アンインストール方法はこちら：**
※ 環境変数パス（`%HOGEHOGE%`）は`Windows + r`に入力することで開くことができます。

1. nodistのアンインストール（コントロールパネル、またはインストールしたときに対応する方法で）
2. `%HOMEPATH%/.npmrc`からnodistに関する記述を削除する
3. `%PROGRAMFILES%`と`%PROGRAMFILES(X86)%`からnodistインストール先フォルダの削除
4. `%APPDATA%`から`npm-cache`フォルダを削除

https://zenn.dev/ymasaoka/articles/note-uninstall-nodish-windows

## どうやって選定するのか？

まずは選定するにあたって、いくつか方針を固めます。
ここでは次の3点に注目することにしました。

- 作業環境のOSに対応しているか（互換性）
- 自動切換えに対応しているか（生産性）
- メンテナンスされているか（信頼性）

それを踏まえて、現行のNode.jsバージョン管理ツールを比べてみましょう。

### 現行のバージョン管理ツールを比較してみる

※ 以下の情報は記事執筆時点のものです。

| Name | Windows | macOS | Support automatically | GitHub Stars | Version/Year |
| :-- | :-: | :-: | :-- | --: | --: |
| ~~[nodist](https://github.com/nullivex/nodist)~~ | ✅ | - | `.node-version`<br>`package.json(engine.node)` | 1.3k | v0.9.1 / 2019 |
| [asdf](https://github.com/asdf-vm/asdf) | - | ✅ | `.node-version`<br>`.nvmrc`<br>※ Node.js以外の環境もこれ1本[^9] | 12.9k | v0.9.0 / 2021 |
| [fnm](https://github.com/Schniz/fnm) | ✅ | ✅ | `.node-version`<br>`.nvmrc` | 5.4k | v1.28.1 / 2021 |
| [n](https://github.com/tj/n) | - | ✅ | `.n-node-version`<br>`.node-version`<br>`.nvmrc`<br>`package.json(engine.node)` | 15.4k | v8.0.0 / 2021 |
| [nave](https://github.com/isaacs/nave) | ✅ | ✅ | `.naverc` | 1.5k | v3.2.2 / 2020 |
| [nodebrew](https://github.com/hokaccha/nodebrew) | - | ✅ | \- | 0.9k | v1.1.0 / 2021 |
| [nodenv](https://github.com/nodenv/nodenv) | - | ✅| `.node-version` | 1.7k | v1.4.0 / 2020 |
| [nvm](https://github.com/nvm-sh/nvm) | - | ✅ | `.nvmrc` | 53.3k | v0.39.0 / 2021 |
| [nvm-windows](https://github.com/coreybutler/nvm-windows) | ✅ | - | - | 18.2k | v1.1.8 / 2021 |
| [nvs](https://github.com/jasongin/nvs) | ✅ | ✅ | `.node-version`<br>`nvmrc` | 1.6k | v1.6.0 / 2020 |
| [volta](https://github.com/volta-cli/volta) | ✅ | ✅ | `package.json(volta.node)` | 4.5k | v1.0.5 / 2021 |

[^9]: @Inadati さんコメントありがとうございました！

乗り換え元のnodistを含めてある程度調べてみました。
最も著名な**nvm**のスター数はずば抜けて多いですね。

ここから、先ほど決めた方針に合わせて絞り込んでいきます。

### 作業環境のOSに対応しているか（互換性）

まず、Windowsに対応しているものに限定してみていきます。
nodistからの乗り換えなので今回はWindowsの話をしていきますが、他のOSでも考え方は同じです。

- fnm
- nave
- nvm-windows
- nvs
- volta

### 自動切換えに対応しているか（生産性）

nodistを使っていた現場にとって、自動切り替えは必須としたいポイントです。
`.npmrc`などを利用していないプロジェクトでも、これがあればバージョン違いのまま開発してしまう可能性を下げられます。

先ほどの候補から、`.node-version`などの設定ファイルに反応して自動的にバージョンを切り替えてくれるもののみに候補を絞ると次の４つが残ることになりました。

- fnm
- nave
- nvs
- volta

#### 導入作業コストも考える

ツールの乗り換えは、往々にして導入（移行）コストがかかるものです。
使い方を覚えるのもそうですが、既存ツールのアンインストール作業や、新ツールの適応作業などがあったりします。

作業者が多ければ多いほど、乗り換えにかかるコストも増えていくので、
なるべくコンパクトに移行を終えられて、既存の環境を生かせるものや近いものを選んでいきたいところです。

そうした視点で考えてみると、nodistがサポートしている`.node-version`に対応しておらず、独自の方法で自動切換えを実現しているnaveとvoltaは候補から外したほうがよさそうです。

- fnm
- nvs

#### 具体的に、どういうところがコストになるの？

もしvoltaを採用するとなると、膨大な数の既存の案件リポジトリにコミットされている`package.json`に、voltaの設定を記載しないといけなくなります。
naveの場合も同様に、`.naverc`を設置してコミットするのは面倒です。

思い切って`.node-version`を捨てて別の手段に乗り換える道もあるかもしれませんが、
外部のスタッフと連携する際も相手がnaveやvoltaの環境を積んでいないと、業務に支障が生まれるかもしれません。

小規模な単発の現場であれば、それらと`.node-version`と共存させるのも手です（`.nvmrc`とかも）。
しかし多くのバージョン管理ツール用の設定ファイルが共存してしまうと、バージョンを上げたときにそれぞれの設定ファイルを書き換えるのも面倒ですし、特定のツールの設定ファイルだけ更新漏れしてしまうようなリスクもあります。

以上の理由から、**多くの開発者が関わる**ものや、**長期間運用される**ような現場では、
少なくとも広く使われている`.node-version`をサポートしたものを選択したほうがよいと判断しました。

`.node-version`ファイルってなんなの…？という方はこちらのページをご参照ください。

https://github.com/shadowspawn/node-version-usage

### メンテナンスされているか（信頼性）

一時は、Node.jsバージョン管理の代名詞となっていたnodistも、現代では使い続けるのが難しい状況になっています。
長期間にわたって使い続けるには、やはり開発陣による定期的なメンテナンスが必要不可欠です。

残った2つの候補のうち、2021年内にリリースされていたのは**fnm**のみでした。
スター数も最も多いです。

## 結論

🏆 **「fnm」選手、優勝です！**

https://github.com/Schniz/fnm

技術選定をするときは、

- 様々なツールの特徴を洗い出す
- ざっくり選定基準を立てる（互換性[^3]、生産性[^4]、信頼性[^5]、安全性[^6]、金額面[^7]などなど）
- 自分たちの環境との相性を吟味する

[^3]: 互換性 - プロジェクトとの相性。乗り換えの場合は、既存の仕組みからどれだけ手を加えずに移行できるか。乗り換えたときに発生する不都合の規模などを考える。
[^4]: 生産性 - その技術を利用する場合としない場合で、ある同じ作業がどれほど無駄なくストレスなく行えるかを考える。
[^5]: 信頼性 - その技術に万が一脆弱性が見つかったとき、しかるべき対処が早急に実施される可能性がどれくらいありそうか。または、採用実績、将来性、ドキュメントの精度、更新頻度などから、その技術によって万が一トラブルが発生したとして、それがどの程度の問題になるか考える。
[^6]: 安全性 - その技術によってスタッフの作業ミスがどれほど防げるかを考える。
[^7]: 金額面 - その技術を採用する場合としない場合、工数・人件費などの視点でどれくらいのメリットがあるかを考える。

の3ステップを行うだけです。
絞り込めなくなったら新しく選定基準を増やして、候補がなくなるまで繰り返しましょう。

1度使用することを決めたツールでも、時間とともに衰えたり、新しいものが主流になっていたりします。
定期的に、採用技術の見直しをしてみるのも大切ですね🥒

## おまけ：`fnm`を導入してみたい！という方へ

https://qiita.com/heppokofrontend/items/fe1c3bc41a0ae943c2ca?0