从正在运行的node.js应用程序中确定项目根目录
有没有比process.cwd()
更好的方法来确定正在运行的node.js进程的根目录? 就像Rails.root
的等价物,但对于Node.js. 我正在寻找尽可能可预测和可靠的事情。
有几种方法可以解决这个问题,每个方法都有自己的优点和缺点:
require.main.filename
从http://nodejs.org/api/modules.html :
当一个文件直接从Node运行时,
require.main
被设置为它的module
。 这意味着您可以通过testingrequire.main === module
来确定文件是否已经直接运行由于
module
提供了一个filename
属性(通常相当于__filename
),因此可以通过检查require.main.filename
来获取当前应用程序的入口点。
所以,如果你想要你的应用程序的基础目录,你可以这样做:
var path = require('path'); var appDir = path.dirname(require.main.filename);
优点缺点
这在大多数情况下都能很好地工作,但是如果你使用像pm2这样的启动器运行你的应用程序,或者运行摩卡testing,这个方法将会失败。
global.X
Node有一个名为global
全局名称空间对象 – 任何附加到这个对象的东西在你的应用程序的任何地方都是可用的。 所以,在你的index.js
(或app.js
或任何你的主要应用程序文件被命名),你可以定义一个全局variables:
// index.js var path = require('path'); global.appRoot = path.resolve(__dirname); // lib/moduleA/component1.js require(appRoot + '/lib/moduleB/component2.js');
优点缺点
一致的工作,但你必须依赖一个全局variables,这意味着你不能轻松地重用组件/等。
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
应用根path
为了解决这个问题,我创build了一个名为app-root-path的节点模块。 用法很简单:
var appRoot = require('app-root-path'); var myModule = require(appRoot + '/lib/my-module.js');
应用程序根path模块使用几种不同的技术来确定应用程序的根path,同时考虑到全局安装的模块(例如,如果您的应用程序在/var/www/
运行,但模块安装在~/.nvm/v0.xx/lib/node/
)。 它不会100%的时间,但它会在大多数常见的情况下工作。
优点缺点
在大多数情况下不需要configuration。 还提供了一些不错的附加便利方法(请参阅项目页面)。 最大的缺点是,如果:
- 您正在使用启动器,如pm2
- 并且 ,该模块不安装在应用程序的
node_modules
目录中(例如,如果您全局安装它)
你可以通过设置一个APP_ROOT_PATH
环境variables或者在模块上调用.setPath()
解决这个问题,但是在这种情况下,你最好使用global
方法。
NODE_PATH环境variables
如果您正在寻找一种方法来确定当前应用程序的根path,上述解决scheme之一可能对您最有效。 另一方面,如果您试图解决可靠加载应用程序模块的问题,我强烈build议查看NODE_PATH
环境variables。
节点的模块系统在各种位置查找模块。 其中一个位置是process.env.NODE_PATH
指向的地方 。 如果您设置了这个环境variables,那么您可以使用标准模块加载程序而不需要任何其他更改。
例如,如果您将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
来启动你的应用程序,而且你是金手指。 我将它和我的enforce-node-path模块结合起来,这样可以防止在没有设置NODE_PATH
情况下意外加载应用程序。 要进一步控制执行环境variables,请参阅checkenv 。
一个问题: NODE_PATH
必须设置在节点应用程序之外。 你不能做类似于process.env.NODE_PATH = path.resolve(__dirname)
因为模块加载器会在运行应用程序之前caching它将要search的目录列表。
[另外4/6/16]另一个很有前途的模块试图解决这个问题是波浪式的 。
1-在项目根目录下创build一个文件,将其称为settings.js
在这个文件里面添加这个代码
module.exports = { POST_MAX_SIZE : 40 , //MB UPLOAD_MAX_FILE_SIZE: 40, //MB PROJECT_DIR : __dirname };
3-里面的node_modules创build一个新的模块名称“settings”,在模块里面index.js写下这段代码:
module.exports = require("../../settings");
4-和任何时候你想要你的项目目录只是使用
var settings = require("settings"); settings.PROJECT_DIR;
通过这种方式,您将拥有与此文件相关的所有项目目录;)
__dirname
不是全局的; 它是当前模块的本地,因此每个文件都有其自己的本地不同的值。
如果你想要正在运行的进程的根目录,你可能想使用process.cwd()
。
如果您需要可预测性和可靠性,那么您可能需要将其设置为应用程序的某个特定环境variables。 您的应用程序查找MY_APP_HOME
(或其他),如果它在那里,并且该应用程序存在于该目录中,则一切正常。 如果它是未定义的或者该目录不包含你的应用程序,那么它应该退出,并提示用户创buildvariables的错误。 它可以被设置为安装过程的一部分。
您可以使用类似于process.env.MY_ENV_VARIABLE
东西读取节点中的环境variables。
获取全局根的最简单的方法( 假设你使用NPM来运行你的node.js应用程序“npm start”等 )
var appRoot = process.env.PWD;
如果你想交叉validation上述
假设您想用node.js应用程序的设置来交叉检查process.env.PWD
。 如果你想要一些运行时testing来检查process.env.PWD
的有效性,你可以用这个代码(我写的看起来工作的很好)进行交叉检查。 您可以使用package.json文件中的npm_package_name来交叉检查appRoot中最后一个文件夹的名称,例如:
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')
,这对于这个目的非常有效
也许你可以尝试从__filename
向上遍历,直到find一个package.json
,并决定这是你当前文件所属的主目录。
所有这些“根目录”大多需要解决一些虚拟path到一个真正的path,所以可能你应该看看path.resolve
?
var path= require('path'); var filePath = path.resolve('our/virtual/path.ext");
即使从子文件夹中调用应用程序,我仍然发现这一切对我来说都是一致的,因为它可以使用一些testing框架,如Mocha:
process.mainModule.paths[0].split('node_modules')[0].slice(0, -1);
为什么它的作品:
运行时节点创build所有加载文件的完整path的registry。 模块首先被加载,因此在这个registry的顶部。 通过selectregistry的第一个元素并返回“node_modules”目录之前的path,我们可以确定应用程序的根目录。
这只是一行代码,但为了简单起见(我的意思),我把黑盒子装进了一个NPM模块:
https://www.npmjs.com/package/node-root.pddivine
请享用!
实际上,我发现也许最简单的解决scheme也是最强大的:只需将以下文件放在项目的根目录下:root-path.js,它具有以下代码:
import * as path from 'path' const projectRootPath = path.resolve(__dirname) export const rootPath = projectRootPath
我发现在使用express时有用的技术是在设置任何其他路由之前将以下内容添加到app.js中
// set rootPath app.use(function(req, res, next) { req.rootPath = __dirname; next(); }); app.use('/myroute', myRoute);
不需要使用全局variables,并且将根目录的path作为请求对象的属性。
如果你的app.js在你的项目的根目录下,默认情况下是这样的。
我用这个
对于我的模块名为mymodule
var BASE_DIR = __dirname.replace(/^(.*\/mymodule)(.*)$/, '$1')
在app.js中创build一个函数
/*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'));
在主文件的顶部添加:
mainDir = __dirname;
然后在你需要的任何文件中使用它:
console.log('mainDir ' + mainDir);
-
mainDir
是全局定义的,如果您只需要在当前文件中使用它,请改用__dirname
。 - 主文件通常位于项目的根文件夹中,并被命名为
main.js
,index.js
,gulpfile.js
。
获取当前文件的path名称:
在该文件中定义:
var get_stack = function(){ var orig = Error.prepareStackTrace; Error.prepareStackTrace = function(_,stack){ 返回堆栈; }; var err = new Error; Error.captureStackTrace(err,arguments.callee); var stack = err.stack; Error.prepareStackTrace = orig; 返回堆栈; };
该文件中的用法:
的console.log(get_stack()[0] .getFileName());
API:
堆栈跟踪
尝试path._makeLong('some_filename_on_root.js');
例:
cons path = require('path'); console.log(path._makeLong('some_filename_on_root.js');
这将返回从你的节点应用程序的根目录(package.json的相同位置)