有没有比process.cwd()
更好的方法来确定运行中的node.js进程的根目录?类似于Rails.root
的东西,但对于Node.js来说。我正在寻找一种尽可能可预测和可靠的方法。
有几种方法来处理这个问题,每一种都有各自的优点和缺点。
来自http://nodejs.org/api/modules.html。
当一个文件直接从Node运行时,
require.main
被设置为其module
。这意味着你可以通过测试require.main === module
来确定一个文件是否被直接运行。因为
module
提供了一个filename
属性(通常相当于__filename
),通过检查require.main.filename
可以获得当前应用程序的入口点。
因此,如果你想要你的应用程序的基本目录,你可以这样做。
var path = require('path');
var appDir = path.dirname(require.main.filename);
这在大多数情况下都很好用,但如果你用pm2这样的启动器运行你的应用程序,或运行mocha测试,这种方法就会失败。
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');
运作稳定,但你必须依赖一个全局变量,这意味着你不能轻易重复使用组件/等。
这将返回当前的工作目录。 这一点也不可靠,因为它完全取决于进程是从哪个目录发起的***。
$ 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');
app-root-path模块使用几种不同的技术来确定应用程序的根路径,同时考虑到全局安装的模块(例如,如果你的应用程序运行在/var/www/
,但模块却安装在~/.nvm/v0.x.x/lib/node/
)。 这并不是100%的工作,但在大多数情况下是可行的。
在大多数情况下无需配置即可工作。 还提供了一些不错的附加便利方法(见项目页)。 最大的缺点是,在以下情况下,它不会工作。
node_modules
目录中(例如,如果你全局安装了它)你可以通过设置APP_ROOT_PATH'环境变量,或者对模块调用
.setPath()'来解决这个问题,但在这种情况下,你最好使用`global'方法。
如果你正在寻找一种方法来确定当前应用程序的根路径,上述解决方案之一可能对你最有效。 另一方面,如果你想解决可靠地加载应用程序模块的问题,我强烈建议你研究NODE_PATH
环境变量。
Node的模块系统会在不同的位置寻找模块。 其中一个位置是process.env.NODE_PATH
指向的地方。如果你设置了这个环境变量,那么你就可以用标准的模块加载器来 "要求 "模块,而不需要做任何其他改变。
例如,如果你把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-name-path模块结合起来,它可以防止在没有设置NODE_PATH
的情况下意外加载应用程序。要想对环境变量进行更多的控制,请参见checkenv。
有一个问题: NODE_PATH
必须在节点应用程序的之外设置。 你不能做类似于process.env.NODE_PATH = path.resolve(__dirname)
的事情,因为模块加载器会在你的应用程序运行前缓存它要搜索的目录列表。
[4/6/16添加]另一个试图解决这个问题的真正有前途的模块是wavy。
__dirname
不是全局的;它是当前模块的局部,所以每个文件都有自己的局部,不同的值。
如果你想要运行进程的根目录,你可能确实想使用process.cwd()
。
如果你想要可预测性和可靠性,那么你可能需要把设置某个环境变量作为你的应用程序的要求。你的应用程序寻找MY_APP_HOME
(或其他什么),如果它在那里,并且应用程序存在于该目录中,那么一切都很好。如果它是未定义的,或者该目录不包含你的应用程序,那么它应该退出并提示用户创建该变量。它可以作为安装过程的一部分来设置。
你可以在节点中用process.env.MY_ENV_VARIABLE
这样的方式来读取环境变量。
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;
这样一来,你的所有项目目录都将与这个文件相对应;)