process.cwd()実行中のnode.jsプロセスのルートディレクトリを確認するよりも良い方法はありますか?Rails.rootNode.js用ですが、と同等のものです。私はできる限り予測可能で信頼できるものを探しています。
process.env.PWD...以下の私の答えを参照してください。
process.cwd()実行中のnode.jsプロセスのルートディレクトリを確認するよりも良い方法はありますか?Rails.rootNode.js用ですが、と同等のものです。私はできる限り予測可能で信頼できるものを探しています。
process.env.PWD...以下の私の答えを参照してください。
回答:
これにはいくつかの方法があり、それぞれに長所と短所があります。
http://nodejs.org/api/modules.htmlから:
ファイルをノードから直接実行すると、
require.mainはに設定されますmodule。つまり、テストによってファイルが直接実行されたかどうかを判断できますrequire.main === module
moduleはfilenameプロパティを提供するため(通常はと同等__filename)、現在のアプリケーションのエントリポイントはをチェックすることで取得できますrequire.main.filename。
したがって、アプリのベースディレクトリが必要な場合は、次のようにできます。
var path = require('path');
var appDir = path.dirname(require.main.filename);
これは、ほとんどの時間を偉大な動作しますが、あなたのようなランチャーを使用してアプリケーションを実行している場合PM2または実行中のモカテストを、このメソッドは失敗します。
ノードにはグローバルネームスペースオブジェクトと呼ばれる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');
一貫して動作しますが、グローバル変数に依存する必要があります。つまり、コンポーネントなどを簡単に再利用することはできません。
現在の作業ディレクトリを返します。それはプロセスが開始されたものをディレクトリに完全に依存だとして、すべての信頼できないから:
$ 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
この問題に対処するために、app-root-pathという名前のノードモジュールを作成しました。使い方は簡単です:
var appRoot = require('app-root-path');
var myModule = require(appRoot + '/lib/my-module.js');
アプリ・ルート・パスモジュールは、(あなたのアプリケーションが実行されている場合、例えば、アカウントにグローバルにインストールモジュールを取って、アプリのルートパスを決定するために、いくつかの異なる技術を使用しています/var/www/が、モジュールがインストールされています~/.nvm/v0.x.x/lib/node/)。100%の確率では機能しませんが、ほとんどの一般的なシナリオで機能します。
ほとんどの状況で設定なしで動作します。また、便利なメソッドがいくつか追加されています(プロジェクトページを参照)。最大の欠点は、次の場合に機能しないことです。
node_modulesディレクトリ(たとえば、あなたがグローバルにインストールされている場合)これを回避するには、APP_ROOT_PATH環境変数を設定するか.setPath()、モジュールを呼び出します。ただし、その場合は、globalメソッドを使用した方がよいでしょう。
現在のアプリのルートパスを特定する方法を探している場合は、上記のソリューションのいずれかが最適です。一方、アプリモジュールの読み込みの問題を確実に解決しようとしている場合は、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。これを私のforce-node-pathモジュールと組み合わせて、NODE_PATH設定なしで誤ってアプリをロードするのを防ぎます。環境変数の適用をさらに制御するには、checkenvを参照してください。
1つの落とし穴: ノードアプリの外部で設定するNODE_PATH 必要があります。モジュールローダーは、アプリの実行前に検索するディレクトリのリストをキャッシュするため、このようなことはできません。process.env.NODE_PATH = path.resolve(__dirname)
[追加4/6/16]この問題を解決しようとするもう1つの本当に有望なモジュールは波状です。
require.main.filenameすると、ほとんどの場合機能しますが、常に機能するわけではありません。
require.main.filename動作しているようです。モカについて知らない。
path.parse(process.mainModule.filename).dir
__dirnameグローバルではありません。現在のモジュールに対してローカルであるため、各ファイルには独自のローカルで異なる値があります。
実行中のプロセスのルートディレクトリが必要な場合は、おそらくを使用する必要がありますprocess.cwd()。
予測可能性と信頼性が必要な場合は、特定の環境変数が設定されていることをアプリケーションの要件にする必要があるでしょう。アプリはMY_APP_HOME(または何でも)を検索し、そこにあり、アプリケーションがそのディレクトリに存在する場合、問題はありません。それが未定義であるか、ディレクトリにアプリケーションが含まれていない場合、変数を作成するようユーザーに促すエラーで終了します。インストールプロセスの一部として設定できます。
あなたはのようなものでノードの環境変数を読むことができますprocess.env.MY_ENV_VARIABLE。
bin/server.jsvsを実行すると、異なる結果が得られcd bin && server.jsます。(これらのjsファイルが実行可能としてマークされていると想定)
process.cwd()モカテストを実行しているときでも、使用することは私にとって魅力のように機能しました。ありがとうございました!
1-プロジェクトルートにファイルを作成し、settings.jsと名付けます。
2-このファイル内にこのコードを追加します
module.exports = {
POST_MAX_SIZE : 40 , //MB
UPLOAD_MAX_FILE_SIZE: 40, //MB
PROJECT_DIR : __dirname
};
3- node_modules内で「settings」という新しいモジュール名を作成し、モジュールindex.js内に次のコードを記述します。
module.exports = require("../../settings");
4-プロジェクトディレクトリが必要なときはいつでも
var settings = require("settings");
settings.PROJECT_DIR;
このようにして、このファイルに関連するすべてのプロジェクトディレクトリが作成されます;)
node_modulesは、バージョン管理から除外されることが多いことです。したがって、チームで作業している場合、またはリポジトリのクローンを作成する必要がある場合は、別のソリューションを考え出して、その設定ファイルを同期させる必要があります。
グローバルルートを取得する最も簡単な方法(NPMを使用してnode.jsアプリ 'npm start'などを実行する場合)
var appRoot = process.env.PWD;
上記を相互検証する場合
process.env.PWDnode.jsアプリケーションの設定をクロスチェックしたいとします。ランタイムテストでの有効性をprocess.env.PWDチェックする場合は、このコードとクロスチェックできます(私が書いたもので、うまく機能しているようです)。appRootの最後のフォルダーの名前を、package.jsonファイルのnpm_package_nameとクロスチェックできます。次に例を示します。
var path = require('path');
var globalRoot = __dirname; //(you may have to do some substring processing if the first script you run is not in the project root, since __dirname refers to the directory that the file is in for which __dirname is called in.)
//compare the last directory in the globalRoot path to the name of the project in your package.json file
var folders = globalRoot.split(path.sep);
var packageName = folders[folders.length-1];
var pwd = process.env.PWD;
var npmPackageName = process.env.npm_package_name;
if(packageName !== npmPackageName){
throw new Error('Failed check for runtime string equality between globalRoot-bottommost directory and npm_package_name.');
}
if(globalRoot !== pwd){
throw new Error('Failed check for runtime string equality between globalRoot and process.env.PWD.');
}
このNPMモジュールを使用することもできます。require('app-root-path')これは、この目的に非常によく機能します
PWDは未定義になり、失敗します。
process.cwd()
process.cwd()常にプロジェクトルートと同じになるのですか?
アプリケーションがサブフォルダーから呼び出された場合でも、Mochaなどの一部のテストフレームワークで発生する可能性があるため、これは一貫して機能することがわかりました。
process.mainModule.paths[0].split('node_modules')[0].slice(0, -1);
なぜ機能するのか:
実行時に、ノードはロードされたすべてのファイルの完全パスのレジストリを作成します。モジュールが最初に読み込まれるため、このレジストリの先頭に配置されます。レジストリの最初の要素を選択し、「node_modules」ディレクトリの前のパスを返すことで、アプリケーションのルートを特定できます。
これは1行のコードですが、簡単にするために(私の目的で)、NPMモジュールにブラックボックス化しています。
https://www.npmjs.com/package/node-root.pddivine
楽しい!
これらの「ルートディレクトリ」はすべて、仮想パスを実際のパイルパスに解決する必要がありますpath.resolve。
var path= require('path');
var filePath = path.resolve('our/virtual/path.ext');
Expressを使用するときに便利だと思うテクニックは、他のルートが設定される前にapp.jsに以下を追加することです
// set rootPath
app.use(function(req, res, next) {
req.rootPath = __dirname;
next();
});
app.use('/myroute', myRoute);
グローバルを使用する必要はなく、リクエストオブジェクトのプロパティとしてルートディレクトリのパスがあります。
これは、app.jsがプロジェクトのルートにある場合に機能します。デフォルトでは、プロジェクトのルートにあります。
これはもう手遅れだと知っています。しかし、2つの方法でルートURLを取得できます
第一の方法
var path = require('path');
path.dirname(require.main.filename);
第二の方法
var path = require('path');
path.dirname(process.mainModule.filename);
参照リンク:-https: //gist.github.com/geekiam/e2e3e0325abd9023d3a3
INIT_CWDプロパティがありますprocess.env。これが私のプロジェクトで現在使用しているものです。const {INIT_CWD} = process.env; // process.env.INIT_CWD
const paths = require(`${INIT_CWD}/config/paths`);
幸運を...
INIT_CWDに解決さdirectoryれたからnpm-scriptexectuedました。
メインファイルの先頭に追加:
mainDir = __dirname;
次に、必要なファイルで使用します。
console.log('mainDir ' + mainDir);
mainDir現在のファイルでのみ必要な場合は、グローバルに定義されています- __dirname代わりに使用してください。main.js、index.js、gulpfile.js。const users = require('../../../database/users'); // 👎 what you have
// OR
const users = require('$db/users'); // 👍 no matter how deep you are
const products = require('/database/products'); // 👍 alias or pathing from root directory
npm install sexy-require --saverequire('sexy-require')メインアプリケーションファイルの先頭に1回含めます。
require('sexy-require');
const routers = require('/routers');
const api = require('$api');
...オプションのステップ。パス構成.pathsは、プロジェクトのルートディレクトリのファイルで定義できます。
$db = /server/database
$api-v1 = /server/api/legacy
$api-v2 = /server/api/v2これによりnode_modules、通常はプロジェクトのルートを示すディレクトリが含まれるまで、ディレクトリツリーが下に移動します。
const fs = require('fs')
const path = require('path')
function getProjectRoot(currentDir = __dirname.split(path.sep)) {
if (!currentDir.length) {
throw Error('Could not find project root.')
}
const nodeModulesPath = currentDir.concat(['node_modules']).join(path.sep)
if (fs.existsSync(nodeModulesPath) && !currentDir.includes('node_modules')) {
return currentDir.join(path.sep)
}
return this.getProjectRoot(currentDir.slice(0, -1))
}
またnode_modules、ネストされたパッケージのインストールに含まれているため、返されたパスにがないことも確認します。
app.jsで関数を作成する
/*Function to get the app root folder*/
var appRootFolder = function(dir,level){
var arr = dir.split('\\');
arr.splice(arr.length - level,level);
var rootFolder = arr.join('\\');
return rootFolder;
}
// view engine setup
app.set('views', path.join(appRootFolder(__dirname,1),'views'));
ルートアプリのパスをexpress app変数に追加するだけで、アプリからこのパスを取得できます。このためapp.set('rootDirectory', __dirname);に、index.jsまたはapp.jsファイルに追加します。req.app.get('rootDirectory')コードのルートディレクトリパスを取得するために使用します。
古い質問ですが、使用する質問についての質問はありませんprogress.argv。argv配列には、ノードによって実行されるパラメーターとして使用された完全パス名とファイル名(.js拡張子の有無にかかわらず)が含まれます。これにはフラグを含めることもできるため、これをフィルタリングする必要があります。
これは直接使用できる例ではありません(自分のフレームワークを使用しているため)が、それを行う方法についてはある程度のヒントが得られると思います。また、キャッシュメソッドを使用して、特に拡張子が指定されていない場合(ファイルの存在チェックが必要な場合など)は、この関数を呼び出すとシステムに過度の負荷がかかることを回避できます。次に例を示します。
node myfile
または
node myfile.js
これが私がキャッシュする理由です。以下のコードも参照してください。
function getRootFilePath()
{
if( !isDefined( oData.SU_ROOT_FILE_PATH ) )
{
var sExt = false;
each( process.argv, function( i, v )
{
// Skip invalid and provided command line options
if( !!v && isValidString( v ) && v[0] !== '-' )
{
sExt = getFileExt( v );
if( ( sExt === 'js' ) || ( sExt === '' && fileExists( v+'.js' )) )
{
var a = uniformPath( v ).split("/");
// Chop off last string, filename
a[a.length-1]='';
// Cache it so we don't have to do it again.
oData.SU_ROOT_FILE_PATH=a.join("/");
// Found, skip loop
return true;
}
}
}, true ); // <-- true is: each in reverse order
}
return oData.SU_ROOT_FILE_PATH || '';
}
};
electronアプリのルートパスを見つけるのは難しいかもしれません。ルートパスは、プロダクション、開発、パッケージ化などのさまざまな条件下で、メインプロセスとレンダラーで異なるためです。
electronアプリのルートパスを取得するために、npmパッケージelectron-root-pathを作成しました。
$ npm install electron-root-path
or
$ yarn add electron-root-path
// Import ES6 way
import { rootPath } from 'electron-root-path';
// Import ES2015 way
const rootPath = require('electron-root-path').rootPath;
// e.g:
// read a file in the root
const location = path.join(rootPath, 'package.json');
const pkgInfo = fs.readFileSync(location, { encoding: 'utf8' });
前文
これは非常に古い質問ですが、2012年と同じように2020年にもまだ神経質になっているようです。他のすべての回答を確認しましたが、手法が見つかりませんでした(これには制限がありますが、他のすべてはそうではありません)すべての状況にも適用されます)。
GIT +子プロセス
バージョン管理システムとしてGITを使用している場合、プロジェクトのルートを決定する問題は(プロジェクトの適切なルートと考える-結局のところ、VCSに可能な限り完全な可視性スコープを持たせたい)に減らすことができます。 :
リポジトリのルートパスを取得する
これを行うにはCLIコマンドを実行する必要があるため、子プロセスを生成する必要があります。さらに、プロジェクトルートは実行時に変更される可能性が非常に低いためchild_process、起動時にモジュールAPIの同期バージョンを使用できます。
私spawnSync()はその仕事に最も適していることがわかりました。実際に実行するコマンドについては、git worktree(--porcelain解析を容易にするためのオプションを指定して)絶対ルートパスを取得するために必要なすべてです。
サンプルでは、念のため、複数のワークツリーが存在する可能性があるため(共通パスがある可能性が高い)、パスの配列を返すことを選択しました。CLIコマンドを使用するshell場合、オプションをに設定する必要があることに注意してくださいtrue(信頼できない入力がないため、セキュリティは問題になりません)。
アプローチの比較とフォールバック
VCSにアクセスできなくなる可能性があることを理解し、ドキュメントやその他の回答を分析した後、いくつかのフォールバックを含めました。要約すると、提案されたソリューションは次のように要約されます(サードパーティのモジュールとパッケージ固有を除く):
| ソリューション| アドバンテージ| 主な問題| | ------------------------ | ----------------------- | -------------------------------- | | `__filename` | モジュールファイルを指します。モジュールに対して| | `__dirname` | モジュールdirを指します。`__filename`と同じ| | `node_modules`ツリーウォーク| ほぼ保証されたルート| 入れ子の場合、複雑なツリーウォーキング| | `path.resolve("。 ")` | CWDがルートの場合はルート| `process.cwd()`と同じ| | `process.argv [1]` | `__filename`と同じ| `__filename`と同じ| | `process.env.INIT_CWD` | `npm run` dirを指します| `npm` && CLIの起動が必要です| | `process.env.PWD` | 現在のディレクトリを指す| 起動ディレクトリに関連する(である)| | `process.cwd()` | `env.PWD`と同じ| 実行時の `process.chdir(path)` | | `require.main.filename` | `=== module`の場合のルート| `require`dモジュールで失敗する|
上記の比較表から、最も一般的なのは2つのアプローチです。
require.main.filenamerequire.main === module会った場合、ルートを取得する簡単な方法としてnode_modules最近提案されたツリーウォークは、別の仮定を使用します。モジュールの
node_modulesディレクトリにdirがある場合、それはルートである可能性があります
メインアプリの場合はアプリルートを取得し、モジュールの場合はそのプロジェクトルートを取得します。
フォールバック1.ツリーウォーク
私の実装では、ターゲットディレクトリが見つかったときに停止するという、より緩やかなアプローチを使用しています。指定されたモジュールのルートは、プロジェクトルートです。呼び出しをチェーンするか、拡張して、検索の深さを構成可能にすることができます。
/**
* @summary gets root by walking up node_modules
* @param {import("fs")} fs
* @param {import("path")} pt
*/
const getRootFromNodeModules = (fs, pt) =>
/**
* @param {string} [startPath]
* @returns {string[]}
*/
(startPath = __dirname) => {
//avoid loop if reached root path
if (startPath === pt.parse(startPath).root) {
return [startPath];
}
const isRoot = fs.existsSync(pt.join(startPath, "node_modules"));
if (isRoot) {
return [startPath];
}
return getRootFromNodeModules(fs, pt)(pt.dirname(startPath));
};
フォールバック2.メインモジュール
2番目の実装は簡単です
/**
* @summary gets app entry point if run directly
* @param {import("path")} pt
*/
const getAppEntryPoint = (pt) =>
/**
* @returns {string[]}
*/
() => {
const { main } = require;
const { filename } = main;
return main === module ?
[pt.parse(filename).dir] :
[];
};
実装
ツリーウォーカーは用途が広いため、フォールバックとして使用することをお勧めします。
const { spawnSync } = require("child_process");
const pt = require('path');
const fs = require("fs");
/**
* @summary returns worktree root path(s)
* @param {function : string[] } [fallback]
* @returns {string[]}
*/
const getProjectRoot = (fallback) => {
const { error, stdout } = spawnSync(
`git worktree list --porcelain`,
{
encoding: "utf8",
shell: true
}
);
if (!stdout) {
console.warn(`Could not use GIT to find root:\n\n${error}`);
return fallback ? fallback() : [];
}
return stdout
.split("\n")
.map(line => {
const [key, value] = line.split(/\s+/) || [];
return key === "worktree" ? value : "";
})
.filter(Boolean);
};
短所
最も明白なのは、GITをインストールして初期化することです。これは望ましくない/信じられないかもしれません(ただし、本番サーバーに GITをインストールすることは珍しくなく、安全ではありません)。上記のように、フォールバックによって仲介されます。
ノート
export それをモジュールにする関数参考文献
シンプル: require('path').resolve('./')
ただ使用する:
path.resolve("./") ... output is your project root directory