【2019年4月版】node-gyp と grpc のインストールに詰まったら。@macOS + node.js

# node-gyp と grpc のインストールは正直やっかい

かなり広範囲のライブラリで採用されていながら環境依存が激しいこの`node-gyp`と`grpc`。macOSでは**最新版**の`node.js`では動かないのがやっかいなところ。つまり、**昔は最新版で問題なかった**のです。(私がタイトルに〇〇年×月とつけているのはそのためです。)

`node-gyp`や`grpc`は数多くのライブラリ、フレームワークで採用されているため、前提として`npm install -g`されているよね？という暗黙の前提があったりします。
おかげでとあるフレームワークのインストールで手順通りに

```console
$ npm i s xxxxxx
```
とやると、`node-gyp rebuild`でエラーや`Tried to download(403): https://storage.googleapis.com/grpc-precompiled-binaries/node/grpc/v1.10.1/node-v64-darwin-x64-unknown.tar.gz`からの長大なエラーメッセージに高確率で遭遇してしまいます。

## 対象環境

OS: macOS High Sierra 10.13.6

インストールが成功した動作確認環境は上記です。もしかしたら、macのバージョンが違えば成功する`node`のバージョンも違うかもしれません。
またUbuntuなどのlinuxでも問題解決のヒントになるかもです。

# 保険のためには nvm 必須
OSのバージョンと`node`のバージョンの組み合わせに激しく依存するため自分の環境でうまくいくようにアレコレするためには`nvm`が必須です。
まず、トライ＆エラーをする保険として `nvm` のインストールをしておきましょう。
その前に、`brew install`してある`node`は全て削除、です。

```console
$ brew uninstall --force node
```
以下のコマンドで**nvmの最新版**をインストールします。

```
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
```
インストールが終わったら、ターミナルを再起動するか、`~/.bashrc`を`source`します。


```console
$ . ~/.bashrc
```

# `node-gyp` の解決

まず、`brew install node`で入ってくる`node`は`11系`です。
`brew install node`で`node`を入れた後、`node-gyp` をインストールする
もしくは、`node-gyp` を依存性に含むライブラリをインストールすると`rebuild`に失敗したという長大なエラーメッセージが吐き出されるかもしれません。

そんな時は、以下のissueをご覧ください。ちょっと古いissueですがここでの議論は今でも現役です。

- [node-gyp rebuild Fails on Mac OS X 10.9.4](https://github.com/nodejs/node-gyp/issues/489)

上記のissueで成功している方のポイントは、
1. グローバルに入れておいた方がいい。
2. 単独でインストールした方がいい。
3. 管理権限でインストールした方がいいかも。
4. node `8` 系ならバッチリ？
です。
要点を念頭に入れつつ、`8`系はさすがに古いので一旦、`node`のLTSバージョンをインストールしてみます。

```console
$ nvm install --lts
```
上記コマンドで`node`のLTS版(今は`10.15.3`)をインストール＆使用します。
そして以下のコマンドで `node-gyp`をインストールします。

```console
$ npm i g node-gyp
+ node-gyp@3.8.0
+ g@2.0.1
added 1 package from 1 contributor, removed 3 packages, updated 1 package and audited 874057 packages in 32.282s
found 1 high severity vulnerability
  run `npm audit fix` to fix them, or `npm audit` for details
```
あら！？自分の環境ではLTS版ですんなりインストールできました。
（UbuntuではPython2.7入れておかないと必ず失敗します。node-gypはPython3系は未サポートのはずなので。自分のmac環境ではPython3なのでダメかと思っていたんですけど・・・？ ま、まぁ、よしとします。）

# `node-grpc`の解決

毎度の事ですが、`brew install node`で入ってくる`node`は`11系`です。その状態で、`grpc`のインストールをすると・・・

```
$ npm i s grpc
> grpc@1.19.0 install /opt/xxxxx/node_modules/grpc
> node-pre-gyp install --fallback-to-build --library=static_library

node-pre-gyp WARN Using request for node-pre-gyp https download 
[grpc] Success: "/opt/xxxxx/node_modules/grpc/src/node/extension_binary/node-v67-darwin-x64-unknown/grpc_node.node" is installed via remote
```

はい、すんなり入りました。ここで指定しているのは**最新版**、`grpc@1.19.0`です。
つまり`node@11`に`grpc@1.19.0`はOKです。
もし、`grpc@1.19.0`より下のバージョンに依存したライブラリがあった場合・・・？

```console
$ npm i s xxxxx
> grpc@1.10.1 install /opt/xxxxx/node_modules/grpc
> node-pre-gyp install --fallback-to-build --library=static_library

node-pre-gyp ERR! Tried to download(403): https://storage.googleapis.com/grpc-precompiled-binaries/node/grpc/v1.10.1/node-v67-darwin-x64-unknown.tar.gz 
node-pre-gyp ERR! Pre-built binaries not found for grpc@1.10.1 and node@11.10.1 (node-v67 ABI, unknown) (falling back to source compile with node-gyp) 
node-pre-gyp ERR! Pre-built binaries not installable for grpc@1.10.1 and node@11.10.1 (node-v67 ABI, unknown) (falling back to source compile with node-gyp) 
node-pre-gyp ERR! Hit error Connection closed while downloading tarball file 
  CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/surface/init.o
  CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/surface/init.o
rm: ./Release/.deps/Release/obj.target/grpc/deps/grpc/src/core/lib/surface/init.o.d.raw: No such file or directory
make: *** [Release/obj.target/grpc/deps/grpc/src/core/lib/surface/init.o] Error 1
gyp ERR! build error 
```
はい、`node@11`に`grpc@1.10.1`は**NG**なんです！！

そこでこちらの issue が役に立ちます。

- https://github.com/grpc/grpc-node/issues/294

上記のissueで成功している方のポイントは、
1. `unsafe-perm`でインストールした方がいいかも?!
2. node `8` 系ならバッチリ？
という点です。`node-gyp`と同様、`8`系は古いので`LTS`版から行ってみます。

## node `LTS` バージョン

`nvm`から`LTS`バージョンを有効にします。

```
$ nvm use --lts
```
続いて、`grpc`をインストールしてみます。

```console
$ sudo npm install -g --unsafe-perm=true grpc@1.10.1
> grpc@1.10.1 install /Users/yoshinori/.nvm/versions/node/v10.15.3/lib/node_modules/grpc
> node-pre-gyp install --fallback-to-build --library=static_library

node-pre-gyp ERR! Tried to download(403): https://storage.googleapis.com/grpc-precompiled-binaries/node/grpc/v1.10.1/node-v64-darwin-x64-unknown.tar.gz 
node-pre-gyp ERR! Pre-built binaries not found for grpc@1.10.1 and node@10.15.3 (node-v64 ABI, unknown) (falling back to source compile with node-gyp) 
node-pre-gyp ERR! Pre-built binaries not installable for grpc@1.10.1 and node@10.15.3 (node-v64 ABI, unknown) (falling back to source compile with node-gyp) 
node-pre-gyp ERR! Hit error Connection closed while downloading tarball file 
  CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/surface/init.o
  CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/surface/init.o
...
```
やっぱりダメみたいです。。。

## node `8`版で再チャレンジ

不本意ながら`8`系で行ってみます。`nvm`から`8`をインストール、そして`grpc`をインストールしてみましょう。

```console
$ nvm install 8
Downloading and installing node v8.15.1...
Downloading https://nodejs.org/dist/v8.15.1/node-v8.15.1-darwin-x64.tar.xz...
######################################################################### 100.0%
Computing checksum with shasum -a 256
Checksums matched!
Now using node v8.15.1 (npm v6.4.1)
$ sudo npm install -g --unsafe-perm=true grpc@1.10.1
> grpc@1.10.1 install /Users/xxxx/.nvm/versions/node/v8.15.1/lib/node_modules/grpc
> node-pre-gyp install --fallback-to-build --library=static_library

[grpc] Success: "/Users/xxxx/.nvm/versions/node/v8.15.1/lib/node_modules/grpc/src/node/extension_binary/node-v57-darwin-x64-unknown/grpc_node.node" is installed via remote
+ grpc@1.10.1
added 129 packages from 97 contributors in 20.682s
```

よっしー！いけました。

そんなわけで `node-gyp`と`grpc`がどちらも動く環境は・・・`node 8`じゃないとダメなん？

# まとめ

`node-gyp`や`grpc`などのようにビルドがうまくいかないライブラリは割と多いです。
バージョンのホンのちょっとした違いでうまくいく／いかないがあるので、諦めずに**要点を踏まえた上で**トライ＆エラーしてみましょう！ (闇雲にトライ＆エラーはダメです！)