複数バージョンのNode.jsをPowershellスクリプトでインストール&切り替え

#はじめに
Node.jsではモジュールをインストールすると小さなファイルがたくさんできるので、HDDだと動作が重く感じることがある。そこでNode.jsごとSSDにインストールし直したところ大分快適になった。

今回の再設定では、複数バージョンのNode.jsをPower Shellのスクリプトを使ってインストール(というよりダウンロード)した。というのも、複数バージョンのNode.jsのインストール・切り替えを行う便利なツールはあるものの、Windows非対応だったりMinGWが必要だったり、良く分からないExeファイルが必要だったりするため、職場の事情で使わせてもらえないかもしれないためだ。

# Powershellスクリプトを使ったインストール
[nodeswitch](https://github.com/stm32p103/nodeswitch) というスクリプトを作成した。中身はリンク先を見てもらうとわかるようにとても単純で、`Invoke-Webrequest`を使ってNode.jsのディストリビューションをダウンロードしたり、`Add-Item`でシンボリックリンクを作っているだけなので、拡張するのは難しくないと思う。
スクリプト自体はPowershellだが、起動は以下のようにバッチファイルから行う。(Powershellはバッチファイルのように起動できないため)

* install-node \<Version\>: 指定したバージョンのZipファイルをダウンロード・解凍する
* switch-node \<Version\>: 指定したバージョンにパスが通るようにする

例えば、バージョン14.1.0をインストールしたければ `install-node 14.1.0` を実行する。これにより、64bit OSでは以下のように`versions`以下にzipファイルが展開される。

```
[git clone で作られたフォルダ]
|
+- script
|  +- install-node.bat : インストール用のバッチファイル(中で common.ps1 をコール)
|  +- switch-node.bat  : バージョン切り替え用のバッチファイル(中で common.ps1 をコール)
|  +- common.ps1
|
+- common
|  +- node      : ディストリビューションごとのフォルダへのシンボリックリンク。PATH環境変数に追加すること。
|  +- npm_global: (同上) ここに、グローバルインストールしたモジュールが格納される。
|
+- versions
   +- node-v14.1.0-win-x64
   |  +- npm_global
   |
   +- node-v12.16.2-win-x64
      +- npm_global
```

# npmの設定
Node.jsのパッケージマネージャ npm はデフォルト設定のままではうまく動かなかったり、AppDataにモジュールをインストールしたりしてしまうので、使う前にいくつか設定をしておく。

## プロキシの設定
PCがプロキシサーバの内側にある場合は、npmでプロキシサーバの指定をする。職場では大抵この設定があると思うので、npmがうまく動かない場合は「インターネットのオプション」の「プロキシサーバ」の設定を確認し以下のコマンドでプロキシサーバを指定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296170/751d3f18-9076-fc7e-76c2-ee6458500b45.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296170/189b8c56-4f11-29fd-27f8-0578861872a8.png)

```:プロキシの設定
npm config set proxy http://your.proxy.server:8080
npm config set https-proxy http://your.proxy.server:8080
```
## グローバルインストールの設定
npm はデフォルト設定のままではグローバルインストール先がAppDataフォルダになっている。これをSSDに変更すると、Angularのようにファイルが多いモジュールが快適に使えるようになる。この設定はインストール用のスクリプト`install-node`内で実施しているので、追加で実施する必要はない。

```:グローバルインストールの変更
npm config set prefix <グローバルインストール先>
```

## キャッシュの設定
必須ではないが、npmのモジュールのキャッシュをSSDに置くと速くなるかもしれない。(初回は同じくらい)

```:キャッシュの設定
npm config set cache <キャッシュファイルを置く場所>
```

# node-gypの設定
npm のモジュールの中には、`sqlite3`のように`node-gyp`を使ったビルドが必要なものがある。`node-gyp`の動作にはPythonとVisual Studio Build Toolsのインストールと、`npm config`の設定が必要である。Chocolateyであれば自動でやってくれるのだが、ここでは[node-gyp - On Windows](https://github.com/nodejs/node-gyp#on-windows)の手順に従い、手動でインストール・設定する。実はそんなに難しくない。

### Visual Studio Build Toolsのインストールと設定
[node-gyp - On Windows](https://github.com/nodejs/node-gyp#on-windows) 「Option 2」のリンクから、Visual Studio Build Toolsのインストーラをダウンロードする。(この時は[vs_buildtools__1947476439.1586275928.exe](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools)というファイルだった)

インストーラを開いたら「Visual C++ build tools」を選択し、インストール対象のコンポーネントにある「Visual Studio Build Tools 2019」をインストールする。インストール後に再度インストーラを起動すると、「インストール済み」と表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296170/69c6542d-8b2f-f750-4b2e-92370609878a.png)

Visual Studio Build Toolsをインストールしたら、以下のコマンドでnode-gypからどのビルドツールを使うかを指定する。(2019はインストールしたバージョンに読み替える)

```:VisualStudioBuildToolsの指定
npm config set msvs_version 2019
```

### Pythonのインストールと設定
node-gyp はPython 2.7系と3.8系どちらにも対応しているが、ここでは3.8をインストールする。インストールしたら、以下のコマンドでnode-gypからどのPythonを使うかを指定する(パスは適宜読み替える)。

```:Pythonの指定
npm config set Python K:\python\python38\python.exe
```

### ビルドできるか試してみる
これらの設定ができたら、ビルドが必要なモジュール(例えばsqlite3)をインストールできるようになる。

```:ビルドできることの確認
K:\test>npm install sqlite3
> sqlite3@4.1.1 install K:\test\node_modules\sqlite3
> node-pre-gyp install --fallback-to-build

node-pre-gyp WARN Using request for node-pre-gyp https download
node-pre-gyp WARN Tried to download(403): https://mapbox-node-binary.s3.amazonaws.com/sqlite3/v4.1.1/node-v83-win32-x64.tar.gz
node-pre-gyp WARN Pre-built binaries not found for sqlite3@4.1.1 and node@14.0.0 (node-v83 ABI, unknown) (falling back to source compile with node-gyp)
このソリューション内のプロジェクトを一度に 1 つずつビルドします。並行ビルドを有効にするには、"-m" スイッチを追加してください。
  unpack_sqlite_dep
  sqlite3.c
  win_delay_load_hook.cc
  ...以降ビルドの経過が表示される...
+ sqlite3@4.1.1
added 112 packages from 101 contributors and audited 162 packages in 45.258s

1 package is looking for funding
  run `npm fund` for details

found 0 vulnerabilities
```

# おわりに
以上でNode.jsがとりあえず動く+ Sqlite3のようなネイティブのモジュールをインストールできるようになった。環境構築は地味だが、管理しないとバージョンアップで互換性がなくなったり、メンバ間のバージョン違いで不可解なトラブルが起きたりするので、インストーラに頼りすぎず、自前で環境構築用のスクリプトを作っておくのも良いかと思う。