NodeJSにはグローバルモジュール/パッケージが必要


158

私は、グローバルにインストールして使用しようとしているforeverforever-monitor、このように:

npm install -g forever forever-monitor

通常の出力と、ファイルをグローバルパスにコピーする操作も表示されますが、実行しようとするrequire("forever");と、モジュールが見つからなかったというエラーが表示されます。

私はnodeとnpmの両方の最新バージョンを使用しており、npmがグローバルインストールとローカルインストールで行った変更についてはすでに知っていますが、すべてのプロジェクトにローカルをインストールしたくないので、そのようなプラットフォームで作業していますサポートしていlinkないのでnpm link、グローバルインストールを行った後はできません。

私の質問は、なぜグローバルにインストールされたパッケージを要求できないのですか?それは機能ですか、それともバグですか?それとも私は何か間違ったことをしていますか?

PS:明確にするために:ローカルにインストールしたくありません。




それはですので、~/.config/yarn/global糸のために
localhostdotdev

回答:


215

Node.jsでは、requireはグローバルモジュールがインストールされているフォルダーを検索しません。

これを修正するには、NODE_PATH環境変数を設定します。Linuxでは次のようになります。

export NODE_PATH=/usr/lib/node_modules

注:これは、グローバルモジュールが実際にインストールされている場所によって異なります。

参照:グローバルフォルダからのロード


24
私のUbuntu 13.10マシンでは、モジュールのグローバルパスは、ここに示すものとは異なります。export NODE_PATH=/usr/local/lib/node_modules代わりに使用しなければなりませんでした。
Drew Noakes、2014年

11
Windows 7/8を使用していて、Nodeのインストールのデフォルトをオーバーライドしていない場合は、NODE_PATH環境変数をに設定するC:\Users\{USERNAME}\AppData\Roaming\npm\node_modulesと機能する可能性があります。
ウェスジョンソン

5
@WesJohnson Just %AppData%\npm\node_modulesはWindows 10で動作します
theblang 2015年

6
設定NODE_PATHすると、グローバルモジュールとローカルモジュールを同時に使用できますか?
Paulo Oliveira

6
静的パスの代わりに、つまりNVMを使用している場合:NODE_PATH=$(npm root -g)
holmberd

96

パッケージをグローバルにインストールした後、ローカルプロジェクトをグローバルパッケージにリンクする必要があります

npm install express -g
cd ~/mynodeproject/
npm link express  

こちらをご覧ください


2
リンクをサポートしていないプラットフォームで実行しています(私の質問のとおり
alexandernst

1
どのプラットフォームを使用していますか?
user568109 2013年

1
私は本当にリンクを台無しにしたくはありません(シンボリックリンクもまったく)。パッケージをグローバルにインストールし、それらを必要とするだけです。これを避けるためにNPMが再設計されたことは知っていますが、このようなことを達成するのはどれほど難しいでしょうか。
alexandernst 2013年

13
プロジェクトがない場合はどうなりますか?言ってください~/some-stand-alone-random-nodejs-test.js。ホームフォルダをプロジェクトディレクトリにしたくありません。小さな実験ごとに新しいフォルダを作成したくありません。
AnnanFay 14

1
Windows 8.1で完璧に動作しました。ノードのコマンドラインcdからプロジェクトのローカルのnode_modulesフォルダーに移動して実行npm link <module>すると、グローバルノードモジュールを参照するプロジェクトのnode_moduleフォルダーに作成されたショートカット(リンク)が表示されます。
dynamiclynk '25

26

ネクロマンシーについてお詫びしますが、グローバルにインストールされたモジュールへのハードコーディングされたパスを指定できます。

var pg = require("/usr/local/lib/node_modules/pg");

これは完璧ではありませんが、Unity3dがプロジェクトディレクトリに含まれているすべてのJavaScriptを「コンパイル」しようとすることを考えると、パッケージをインストールすることはできません。


4
Unity3DはJavaScriptをサポートしていません。これは、JS-のようなそのブーインタプリタ/コンパイラの構文をサポート(ブーは、Pythonのような.NETの言語です) 一見「JavaScriptの」として販売されています。Unityがサポートする言語のより正確な名前はUnityScriptです。同じ言語に近いものではないため、WebまたはNode.js用に記述されたJSはUnityで動作しません。Unityの公式Wikiの違いに関する詳細:wiki.unity3d.com/index.php/UnityScript_versus_JavaScript
Slipp D. Thompson

19

これは古い質問であることはわかっていますが、semverpreinstallスクリプトでバージョンチェックを実行しようとしたときに、この問題に遭遇しましたpackage.json。インストールされているローカルモジュールに依存できないことがわかっているので、これを使用semverしてグローバルnode_modulesフォルダーから要求します(npm依存しているため、そこにあることがわかっています)。

function requireGlobal(packageName) {
  var childProcess = require('child_process');
  var path = require('path');
  var fs = require('fs');

  var globalNodeModules = childProcess.execSync('npm root -g').toString().trim();
  var packageDir = path.join(globalNodeModules, packageName);
  if (!fs.existsSync(packageDir))
    packageDir = path.join(globalNodeModules, 'npm/node_modules', packageName); //find package required by old npm

  if (!fs.existsSync(packageDir))
    throw new Error('Cannot find global module \'' + packageName + '\'');

  var packageMeta = JSON.parse(fs.readFileSync(path.join(packageDir, 'package.json')).toString());
  var main = path.join(packageDir, packageMeta.main);

  return require(main);
}

使用するために特別なモジュールをインストールする必要がないため、このアプローチが好きです。

プロジェクトでNODE_PATH実行npm installする前に追加の構成/設定を行う必要なしに、これを他の人のマシンで機能させたいので、他の人が提案したような解決策を採用しませんでした。

これがコーディングされている方法では、トップレベルのモジュール(を使用してインストールされたnpm install -g ...)または必要なモジュールnpmdependenciesここにリストされている:https : //github.com/npm/npm/blob/master/package.json)を見つけることが保証されています。新しいバージョンのNPMを使用している場合、node_modulesフォルダーの構造がよりフラットになるため、グローバルにインストールされた他のパッケージの依存関係が見つかる可能性があります。

これが誰かに役立つことを願っています。


19

ドキュメントに従って、Node.jsはデフォルトで次の場所を検索します。

  1. NODE_PATH環境変数で指定されたパス

    注:NODE_PATH環境変数は、コロンで区切られた絶対パスのリストに設定されます。

  2. 現在のnode_modulesフォルダ。(地元)

  3. $HOME/.node_modules (グローバル)

    注:$HOMEはユーザーのホームディレクトリです。

  4. $HOME/.node_libraries (グローバル)
  5. $PREFIX/lib/node (グローバル)

    注:$PREFIXNode.jsの構成済みnode_prefixです。

    の現在の値を確認するには、次のコマンドをnode_prefix実行します。

    node -p process.config.variables.node_prefix

    注:プレフィックスは--prefixビルド中のparamに対応し、を基準にしていprocess.execPathます。npm config get prefixコマンドの値と混同しないでください。ソース

指定されたモジュールが見つからない場合、それは上記の場所のいずれにも存在しないことを意味します。

モジュールがインストールされているグローバルルートフォルダーの場所は、次の方法で出力できますnpm root -g(デフォルトでは、パスはnpmrcfileでオーバーライドされない限り、実行時に計算されます)。

解決

次の回避策を試すことができます。

  • NODE_PATH環境変数でグローバルモジュールの場所を指定します。例えば

    echo 'require("forever")' | NODE_PATH="$(npm root -g):$NODE_PATH" node

    の値をテストして出力するには、次のコマンドをNODE_PATH実行します。

    echo 'console.log(process.env.NODE_PATH); require("forever")' | NODE_PATH="$(npm root -g):$NODE_PATH" node 
  • より永続的な解決策として、$HOME/.node_modules次のコマンドを実行して、グローバルユーザーフォルダーをリンクし、ルートフォルダーを指すようにします。

    ln -vs "$(npm root -g)" "$HOME"/.node_modules

    次に、echo 'require("forever")' | nodeコマンドを使用して再テストします。

  • スクリプトを呼び出す前に、現在のフォルダーを一時的に、拡張機能がグローバルにインストールされている場所に変更します。例えば

    npm install -g forever
    cd "$(npm root -g)"
    echo 'require("forever")' | node
    cd -
  • npmuserconfigファイル(を参照npm help 5 npmrc)またはuserconfigパラメーター(--prefix)でグローバルインストール先を構成します。

    現在の設定を表示するには、次を実行しますnpm config list

    現在の設定を編集するには、次を実行しますnpm config edit

  • を呼び出すときに、ノードモジュールの場所の完全パスを指定しますrequire()。例えば

    require("/path/to/sub/module")
  • パッケージをカスタムの場所にインストールします。

    npm install forever -g --prefix "$HOME"/.node_modules

    ただし、インストールはの下~/.node_modules/lib/node_modules/になるため、場所を追加する必要があります。

    参照:カスタムの場所へのnpmローカルインストールパッケージ

  • グローバルパッケージの場所から現在のフォルダーにシンボリックリンク作成します。例えば

    npm link forever

4.現在のnode_modulesフォルダーのように見えます。(ローカル)3. $よりも優先さPREFIX / libに/ノード(グローバル)
キラリーイシュト

ローカルのnode_modulesフォルダーは常にグローバルフォルダーよりも優先されます!
キラーリイストヴァン

14

requiregこの問題を解決するには、パッケージを使用できます。

var forever = require('requireg')('forever')

トリックを行います。

また、別のモジュールがあります。これはglobal-npm、グローバルを使用することだけに固有npmですが、短いコードを見て、手法がどのように機能するかを確認できます。


興味深いですが、NODE_PATHメソッドはおそらくより標準的です
Alexander Mills

美しさは、NODE_PATHあなたが任意のコードを変更する必要がないこと、もあります。(私のユースケースは、多くの学生プロジェクトをグレーディングしており、プロジェクトnpm installごとに実行したくない、また、node_modulesディレクトリを提供したくない)。
amenthes

いいえ、そもそも必要ないのでうまくいきませんrequireg。これがポイントです。
thisismydesign

6

のような大きなモジュールに依存するCLIユーティリティの場合puppeteer、私はaを生成し、npm root -gそれを使用してグローバルモジュールを要求します。

try {
  const root = require('child_process').execSync('npm root -g').toString().trim()
  var puppeteer = require(root + '/puppeteer')
} catch (err) {
  console.error(`Install puppeteer globally first with: npm install -g puppeteer`)
  process.exit(1)
}

3

あなたはあなたの.profileファイルにこの行を置くことができます:

NODE_PATH = "$(npm config get prefix)/ lib / node_modules"をエクスポートします

これによりnode、グローバルパスが使用されます。


1
いいえ。これはグローバルを取得する一般的な方法ですnode_modules。これは古い答えですが、ドキュメントのどこかから入手したことを覚えています。とにかく、私のコンピューター(2020年)では、グローバルnpm node_modulesディレクトリはusr/lib/node_modulesです。とにかく、npm config get prefixグローバルパッケージがインストールされるたびにnpmによってグローバルに使用されるので、それは正しいはずです。
ルイスパウロ

1
どちらの方法でも(Node.JSの経験が浅かったため、最初の回答ではこれを述べていません)、プログラムでグローバルにインストールされたパッケージを使用することはエッジユースケースであり、プロジェクトで作成されるため、めったに行われるべきではありません特定の依存関係がpackage.jsonファイルまたはyarn.lock/にないため、プロジェクトがVCSにコミットされ、別の環境に複製されるたびに問題が発生しますpackage-lock.json
ルイスパウロ

1
ああ!今、私は分かる。NODE_PATHをPATHと間違えていると思います。PATHは、シェルが実行可能ファイルを探す場所です。NODE_PATHは、ノードがパッケージを探す場所です。node_modulesフォルダーの現在のディレクトリ、次に親、次に親の順に調べnode_modulesます。そのモジュールを含むフォルダーが見つかるまで続きます。ただし、パッケージをグローバルにインストールする場合node_modules、スクリプトの現在のディレクトリより上のフォルダー内にはないため、ノードがパッケージを探すフォールバックとしてNODE_PATHを使用します。
ルイスパウロ

1
ahahahah @Luis Paulo正解です!申し訳ありません!私が試してみて、混乱を防ぐために、私のコメントの一部を削除して、素敵な仕事とあなたに感謝します
ライアン・テイラー

@Ryan Taylor他の誰かが同じものを持っている可能性があるため、解決されたコメントや質問は削除しないでください。今、私はコメントで独り言を持っているように見えます!ahahahah
ルイスパウロ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.