【fnm】 Node.jsのバージョンをスマートに切り替えたい

## 背景

メインで作業しているプロジェクトではwebpackをv14系のNode.jsを使用しており、最新の18系に上げるとスクリプトが動かない不具合[^1]があるので長らく14系を使用していました。
しかし、Viteを使う別プロジェクトを作成したところコンパイルが通らないので調べると、Vite3以降はNode.jsのバージョンが16以上でないといけないようなので[^2]、fnmを使って複数バージョンを切り替えられるようにしました。

fnmは最初のセットアップが大変ですが、それを終えた後にはきっと優雅なfnmライフが待っていることでしょう。

※自環境がWindowsのため、Mac等での導入方法は解説してません。

## ツールの選定

初めはNodistを使おうとしましたが、Node.jsのバージョンを切り替えるにはいちいちコマンドを打つ必要があり、スマートじゃない。

そこで、fnmはディレクトリ内の.node-versionファイルを参照してバージョンを自動的に切り替えてくれるらしく、そちらに変えました。

## インストール

### バイナリファイルの入手

公式のリポジトリからそれぞれの環境にあったzipをダウンロード

https://github.com/Schniz/fnm/releases

windowsであれば、「fnm-windows.zip」
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328727/94e56e00-3599-8ce5-27b8-8766a321345e.png)
これを解凍して、PATHを通します。

私は以下の場所に置きました。
`C:\Users\<user-name>\fnm`

これだけで`fnm`コマンドが使えるようになります。
```bash
fnm --version
# > 1.33.1
```

とっても簡単ですね。(この後がめんどくさいです)

### シェルセットアップ

fnmを使い始めるには、環境変数の設定が必要です。

#### PowershellのProfile作成($Profileが無い場合)

```bash
path-test $Profile
```

上のコマンドをPowerShellで実行して`False`が出れば、まだprofileファイルが無いので、以下のコマンドで作成

```bash
	new-item -path $profile -type file -force
```

#### $Profileに追記

```bash
$profile
```

で表示されるプロファイルファイルに以下を追記

```bash
fnm env --use-on-cd | Out-String | Invoke-Expression
```

これでPowerShellが起動する際にこのスクリプトが実行されてfnm用の環境変数が用意されます。

(まだ終わりじゃない)

### スクリプトの実行を許可

PowerShellを再起動すると、このようなエラーが出ると思います。
上で作成したプロファイルファイルの実行に失敗しています。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328727/fd709e8e-e90e-a768-b69e-6beabc85930f.png)

Set-ExecutionPolicyコマンドでポリシーにUnrestrictedを設定すればいいのですが、それでは常時スクリプトの実行が許可されてしまいセキュリティ的にも不安なので、起動コマンドに`-ExecutionPolicy Unrestricted`を追加。

この場合、ScoepeオプションはProcessになるので、PowerShellを閉じればDefaultに戻るので安心です。
![Untitled (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328727/ab3dae65-9016-2548-c90c-89e31fef9c34.png)

これで、スタートメニューから起動した際に、エラーが出ずにプロファイルファイルが実行されます。

### VSCodeからPowerShellを使う場合

VSCodeのTerminalで起動するPowerShellは別途setting.jsonにポリシーを記述する必要があります。
`terminal.integrated.profiles.windows` のPowerShellの部分を以下の通りに変更

```json
"PowerShell": {
    "source": "PowerShell",
    "icon": "terminal-powershell",
    "args": [
        "-ExecutionPolicy",
        "Unrestricted"
    ]
},
```

## fnmの操作

### Node.jsのインストール

既にNode.jsがインストールされている場合は、そのバージョンがデフォルトのバージョンになります。
バージョンをインストールするには

```bash
fnm install 18
# v18系がインストールされる
```

### インストール済みのバージョンの確認

```bash
fnm list
```

### Node.jsのバージョン切り替え

```bash
fnm use 18
```

インストールされていないバージョンを指定すると、インストールするかどうか聞かれます。

### 使用しているバージョンの確認

```bash
fnm current
```

## ディレクトリ毎にバージョンを設定

ディレクトリ内にバージョンファイル(`.node-version` もしくは`.nvmrc`)を作成しバージョンを記述することで、それより下層のディレクトリでのバージョンを指定することができます。
![Untitled (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328727/8b8b975a-e41c-c767-0ad0-1f0ff8af3040.png)
これで、ディレクトリを移動するだけでバージョンが切り替わるようになりました！

## .gitignoreに設定

git管理されているディレクトリでは、このバージョンファイルを無視して欲しいので、グローバルな`.gitignore`に登録します。

```bash
git config --global core.excludesFile
```
このコマンドで出力されるパスに`.gitignore`があるので、そこに.node-versionを追記。


### ディレクトリ移動でバージョン切り替え
以下のようにディレクトリaaaとディレクトリbbbを用意し、
aaaには`14.21.3`を指定した.node-versionを
bbbには`18.15.0`を指定した.node-versionを用意します。
```bash
 aaa
├ .node-verion # 14.21.3
└ bbb
  └ .node-verion # 18.15.0
```
bbbからaaaに移動するだけで、以下のようにバージョンが切り替わりました！
![image (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328727/172553d6-e7f2-7009-3cf7-32e70afa8208.png)


おしまい

## 参考記事

[https://github.com/Schniz/fnm/blob/master/README.md](https://github.com/Schniz/fnm/blob/master/README.md)
[https://umi-uyura.hatenablog.com/entry/2021/09/30/083419](https://umi-uyura.hatenablog.com/entry/2021/09/30/083419)
[https://www.curict.com/item/d1/d1c4a3e.html](https://www.curict.com/item/d1/d1c4a3e.html)

[^1]: [https://qiita.com/kamada_math/items/4df6f153bb2d0159a4ff](https://qiita.com/kamada_math/items/4df6f153bb2d0159a4ff)

[^2]: [https://www.flying-h.co.jp/media/2022/09/30/error_node_path/](https://www.flying-h.co.jp/media/2022/09/30/error_node_path/)