実行中のNode.jsアプリケーションからプロジェクトルートを決定する 質問する

実行中のNode.jsアプリケーションからプロジェクトルートを決定する 質問する

process.cwd()現在のプロジェクトのルート ディレクトリのパス名を取得するには、 以外の方法がありますか。Nodeは Ruby のプロパティ のようなものを実装していますかRails.root。一定で信頼できるものを探しています。

ベストアンサー1

これにはさまざまなアプローチがあり、それぞれに長所と短所があります。

require.main.filename

からモジュール:

ファイルがNodeから直接実行されると、require.mainが設定されますmodule。つまり、ファイルが直接実行されたかどうかは、テストすることで判断できます。require.main === module

はプロパティ (通常は と同等)moduleを提供するため、 をチェックすることで現在のアプリケーションのエントリ ポイントを取得できます。filename__filenamerequire.main.filename

したがって、アプリのベース ディレクトリが必要な場合は、次のようにします。

const { dirname } = require('path');
const appDir = dirname(require.main.filename);

長所短所

これはほとんどの場合うまく機能しますが、pm2などのランチャーを使用してアプリを実行している場合や、mocharequire.mainテストを実行している場合は、この方法は失敗します。また、が利用できないNode.js ES モジュールを使用する場合も、この方法は機能しません。

module.paths

Node はすべてのモジュール検索パスを に公開しますmodule.paths。これらを走査して、解決する最初のパスを選択できます。

async function getAppPath() {
  const { dirname } = require('path');
  const { constants, promises: { access } } = require('fs');
  
  for (let path of module.paths) {
    try {
      await access(path, constants.F_OK);
      return dirname(path);
    } catch (e) {
      // Just move on to next path
    }
  }
}

長所短所

これは機能する場合もありますが、アプリケーションがインストールされているディレクトリではなく、パッケージがインストールされているディレクトリを返す可能性があるため、パッケージ内で使用する場合は信頼できません。

グローバル変数の使用

Node には というグローバル名前空間オブジェクトがありますglobal。このオブジェクトにアタッチしたものはすべて、アプリのどこでも利用できるようになります。そのため、index.js(またはapp.jsメインのアプリ ファイルの名前が何であれ) で、グローバル変数を定義するだけで済みます。

// index.js
var path = require('path');
global.appRoot = path.resolve(__dirname);

// lib/moduleA/component1.js
require(appRoot + '/lib/moduleB/component2.js');

長所短所

一貫して動作しますが、グローバル変数に依存する必要があるため、コンポーネントなどを簡単に再利用することはできません。

process.cwd()

これは現在の作業ディレクトリを返します。これはプロセスがどのディレクトリから起動されたかに完全に依存するため、まったく信頼できません。

$ cd /home/demo/
$ mkdir subdir
$ echo "console.log(process.cwd());" > subdir/demo.js
$ node subdir/demo.js
/home/demo
$ cd subdir
$ node demo.js
/home/demo/subdir

アプリのルートパス

この問題に対処するために、私はノードモジュールを作成しました。アプリのルートパス使い方は簡単です:

const appRoot = require('app-root-path');
const myModule = require(`${ appRoot }/lib/my-module.js`);

アプリのルートパス/var/www/module は、グローバルにインストールされたモジュール (たとえば、アプリが で実行されているが、モジュールが にインストールされている場合) を考慮して、いくつかの手法を使用してアプリのルート パス~/.nvm/v0.x.x/lib/node/を決定します。これは 100% の確率で機能するわけではありませんが、ほとんどの一般的なシナリオでは機能します。

長所短所

ほとんどの状況で設定なしで動作します。また、便利な追加メソッドもいくつか提供しています (プロジェクト ページを参照)。最大の欠点は、次の場合には動作しないことです。

  • pm2のようなランチャーを使用しています
  • かつ、モジュールがアプリのnode_modulesディレクトリ内にインストールされていない(たとえば、グローバルにインストールした場合)

APP_ROOT_PATH環境変数を設定するか、モジュールを呼び出すことでこれを回避できます.setPath()が、その場合は、メソッドを使用する方がよいでしょうglobal

NODE_PATH環境変数

現在のアプリのルート パスを特定する方法を探している場合は、上記の解決策のいずれかが最適である可能性があります。一方、アプリ モジュールを確実に読み込むという問題を解決しようとしている場合は、NODE_PATH環境変数を調べることを強くお勧めします。

ノードのモジュールシステムさまざまな場所でモジュールを検索します。これらの場所の1つは、process.env.NODE_PATHポイントがこの環境変数を設定すると、require他の変更を加えずに標準モジュール ローダーでモジュールを実行できます。

たとえば、NODE_PATHに設定すると/var/www/lib、次のコードは正常に動作します。

require('module2/component.js');
// ^ looks for /var/www/lib/module2/component.js

これを行うには、以下を使用するのが最適ですnpm

{
  "scripts": {
    "start": "NODE_PATH=. node app.js"
  }
}

これでアプリを起動してnpm start完了です。私はこれをノードパスの強制モジュールは、設定せずに誤ってアプリをロードすることを防ぎますNODE_PATH。環境変数の適用をさらに制御するには、チェックenv

注意点が 1 つあります。 ノード アプリの外部で設定するNODE_PATH 必要があります。モジュール ローダーはアプリの実行前に検索するディレクトリのリストをキャッシュするため、このようなことはできません。process.env.NODE_PATH = path.resolve(__dirname)

[2016年4月6日追加]この問題を解決しようとするもう一つの非常に有望なモジュールは波状の

おすすめ記事