Node.js

Node.js グローバルインストールでハマった

簡単にいうとNode.js グローバルインストールにハマりました。いわゆるパスを通すのに苦労した話です。


tl:dr

Node.jsでグローバルインストールしたモジュールが実行環境によって参照できない時の調査ポイント


  • npm root -g で、モジュールのパスを確認

  • NODE_PATH にモジュールのパスを追加

  • VSCode の場合は.vscode/launch.json に NODE_PATH を追加


問題 グローバルインストールしたモジュールが読み込めない

グローバルインストール


shell

npm i -g 3rd_party_module


呼び出しするも失敗


index.js

const a = require('3rd_party_module')

// 読み込みに失敗する
// 🚨Error: Cannot find module '3rd_party_module'


解決方法

$NODE_PATHにグローバルインストールされたモジュールのパスを通せば良い。

グローバルインストールのパスがNode.jsのrequire()メソッドから参照されるためには、そのパスがglobal.module.pathsに入っている必要がある。まずはそれを確認する。


shell

$ node

> global.module.paths
[ '/opt/jarvis/repl/node_modules',
'/opt/jarvis/node_modules',
'/opt/node_modules',
'/node_modules',
'/root/.node_modules',
'/root/.node_libraries',
'/usr/lib/node' ]
> .exit # node を終了

次にグローバルインストールされたモジュールのパスを確認する。

# モジュールがグローバルインストールされているパス確認

$ npm root -g
/usr/local/lib/node_modules

global.module.pathsに入っていないので、追加する。そうするには$NODE_PATHという環境変数に追加する。


shell

$ NODE_PATH="npm root -g"

# 確認
$ node
> global.module.paths
[ '/usr/lib/node_modules/repl/node_modules',
'/usr/lib/node_modules', 🌟追加されている
'/usr/node_modules',
# ・・・以下略

Dockerを使う場合は、このパスをDockerfileに定義する。

ENV NODE_PATH /usr/lib/node_modules


Mac でパスが通らない

Docker はうまくいったものの Mac でグローバルインストールしたモジュールが参照できない。


.bash_profile

NODE_PATH="npm root -g"

export NODE_PATH

❌ NODE_PATH = npm root -g となってしまうためNG. ダブルクォーテーションだとダメ。


.bash_profile

NODE_PATH=`npm root -g`

export NODE_PATH

NODE_PATH = /usr/local/... (npm root -gの結果が代入される) が入るようになった。以下のコマンドで環境変数を反映。


shell

source ~/.bash_profile

echo $NODE_PATH
/usr/local/... # O.K.

コンソールから、Node.jsを実行してみたらちゃんとグローバルインストールされたモジュールが読み込まれていた。


VSCode でパスが通らない

しかし、VS Codeから実行すると、グローバルインストールしたモジュールが読み込まれない...。色々調べたら、launch.json に 環境変数追加してやればいいみたい。


.vscode/launch.json

 ~~~~~ 中略 ~~~~~

{
"type": "node",
"request": "launch",
"name": "VSCodeでのデバッグ",
"program": "${workspaceFolder}/nodejsproject/index_from_vscode.js",
"env": {
"NODE_PATH": "/usr/local/lib/node_modules" 🌟 ここ!
}
}
~~~~~ 中略 ~~~~~

いくつか変数っぽいのは使えるのかな〜と思って、"${npm root -g}" を設定してみたけど"npm root -g"がNODE_PATHとして設定されるだけだったので仕方なく直打ちです。


余談

そもそもグローバルインストールするのは良くないとか議論があるのだけど、たくさんのNode.jsプロジェクトがあって共通ライブラリ的に使用したいときは使うよね?でも、package.jsonに依存関係残らないから、困る。Dockerfileに記述するだろうから大丈夫だとは思うけどみんなどうしてるだろう。気になる。