回答
npm install -g tplink-smarthome-api でインストールが出来ております。
npm install --global
(npm i -g
)はCLIからパッケージを利用したい場合のインストール方法で、通常require()
で読み込むことはできません。
原因
require()
は./
、/
、../
または#
で始まらない文字列を受け取った時、現在のディレクトリ(__dirname
)を階層ごとに分割したリストにnode_modules
を連結して、その中にディレクトリ名が一致するパッケージが無いか総当たり方式で検索します。
例えば、現在のディレクトリが/Users/foo/bar/baz
で、/Users/foo/node_modules/hoge-module
にrequire()
したいモジュールがあるとします。
console
1$ tree /
2.
3└── Users
4 └── foo
5 ├── bar
6 │ └── baz # この中にいる
7 └── node_modules
8 └── hoge-module # これをrequire()したい
この状態で、/Users/foo/bar/baz/index.js
の中でrequire('hoge-module')
を実行すると、Nodeは次のディレクトリの中から順番にhoge-module
と名付けられた子ディレクトリが存在しないか調べます:
/Users/foo/bar/baz/node_modules
/Users/foo/bar/node_modules
/Users/foo/node_modules
/Users/node_modules
/node_modules
このケースでは/Users/foo/node_modules
に目的のモジュールがあるため、リストの__3.__で検索が終了します。
--global
フラグ付きでインストールした場合にここで発生する問題が、npm-install
がこれらのディレクトリのいずれの場所にもパッケージを配置してくれないことです。
npm install --global
は{prefix}/lib/node_modules
(macOS/Linux/BSD/その他*nixの場合)または{prefix}/node_modules
(Windowsの場合)の中にパッケージをインストールします。
ご自身の環境の{prefix}
は次のコマンドを打つことで確認できます:
console
1$ npm config get prefix
2/usr/local # 一例(macOSの場合)
試しにjest
パッケージを--global
フラグ付きでインストールし、type
とrealpath
を使い、実態がどこにあるか調べてみましょう:
console
1$ npm i -g jest
2added 528 packages, and audited 529 packages in 13s
3found 0 vulnerabilities
4
5$ realpath $(type -p jest)
6/usr/local/lib/node_modules/jest/bin/jest.js # 一例(macOSの場合)
ディレクトリ/usr/local/lib/node_modules
の中にjest
パッケージがインストールされていますね。上記したNodeのパッケージ解決方法を参照すると、/usr/local/lib
の子孫ディレクトリ以外からrequire()
することができないことに気がつくと思います。これが質問で発生しているCannot find module ...
エラー('MODULE_NOT_FOUND'
エラー)の直接的な原因です。
解決方法
これを解決するにはNodeにより検索対象となっているnode_modules
にパッケージのフォルダを用意する必要がありますが、これには大きく3種類のアプローチがあります。
ローカルにインストールし、CLIではnpxコマンドを利用する(方法1)
console
1$ npm i tplink-smarthome-api # 1. ローカルにインストール
2$ npx tplink-smarthome-api # 2. CLIで実行
バージョン7.0.0以降のNodeにはnpx
と呼ばれる明示的にパッケージをインストールすることなくCLIスクリプトを実行できるコマンドが追加されています。このコマンドはローカルにパッケージがインストールされている場合ローカルのパッケージを、ローカルにパッケージがインストールされていない場合は自動的にNPMからキャッシュフォルダ(~/.npm
または%AppData%/npm-cache
)にダウンロードしたパッケージを実行します。環境を起因とした問題が発生する可能性が低く、消費する容量も抑えられるため、私はこれを推奨します。
ローカルとグローバルの両方にインストールする(方法2)
console
1$ npm i tplink-smarthome-api # 1. ローカルにインストール
2$ npm i -g tplink-smarthome-api # 2. グローバルにインストール
3$ tplink-smarthome-api # 3. CLIで実行
特筆性は存在しませんが、一番シンプルな方法です。2回同じパッケージをインストールするため、消費する容量が2倍になります。
グローバルにインストールし、ローカルにリンクさせる(方法3)
console
1$ npm i -g tplink-smarthome-api # 1. グローバルにインストール
2$ npm link tplink-smarthome-api # 2. ローカルにリンク
3$ tplink-smarthome-api # 3. CLIで実行
npm-link
はローカルのnode_modules
内に--global
でインストールしたパッケージのシンボリックリンクを作成します。両方にインストールする方法と比べると容量の節約にはなりますが、package.json
の依存関係にパッケージを追加してくれず、結果的に管理が複雑になってしまうため非推奨です。加えて使用するパッケージによってはシンボリックリンクを追跡してくれないため、原因不明のエラーが発生することもあります。データ容量の節約をしたい場合は自動的にハードリンクを張ってくれるpnpmや、上記したNodeのモジュール解決方法を容量削減に活用したYarn 2といった他のパッケージマネージャーを使用することをおすすめします。
方法のまとめ
簡単なテーブルとして次のように表すことができます:
方法 | 容量 | 管理 |
---|
ローカル+npx(方法1) | ⭕️ | ⭕️ |
ローカル+グローバル(方法2) | ❌ | ⭕️ |
グローバル+リンク(方法3) | ⭕️ | ❌ |
ご不明な点などありましたらお気軽にご質問ください。