有很多方法可以解决这个问题,每种方法都有自己的优缺点:
require.main.filename
来自http://nodejs.org/api/modules.html:
当一个文件直接从 Node 运行时,require.main 被设置为它的module。也就是说你可以通过测试require.main === module来判断一个文件是否直接运行过
因为module提供了一个filename属性(一般相当于__filename),所以可以通过检查require.main.filename获得当前应用的入口点。
因此,如果您想要应用程序的基本目录,您可以这样做:
const { dirname } = require('path');
const appDir = dirname(require.main.filename);
优点和缺点
这在大多数情况下都很好用,但如果您使用 pm2 之类的启动器运行应用程序或运行 mocha 测试,则此方法将失败。
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
应用程序根路径
为了解决这个问题,我创建了一个名为 app-root-path 的节点模块。用法很简单:
const appRoot = require('app-root-path');
const myModule = require(`${ appRoot }/lib/my-module.js`);
app-root-path 模块使用多种技术来确定应用程序的根路径,同时考虑到全局安装的模块(例如,如果您的应用程序在 /var/www/ 中运行,但模块是安装在~/.nvm/v0.x.x/lib/node/)。它不会在 100% 的时间里工作,但它会在最常见的情况下工作。
优点和缺点
在大多数情况下无需配置即可工作。还提供了一些不错的附加便利方法(参见项目页面)。最大的缺点是它在以下情况下不起作用:
- 您正在使用启动器,例如 pm2
-
并且,该模块未安装在您应用的
node_modules 目录中(例如,如果您将其安装在全局范围内)
您可以通过设置APP_ROOT_PATH 环境变量或在模块上调用.setPath() 来解决此问题,但在这种情况下,您最好使用global 方法。
NODE_PATH 环境变量
如果您正在寻找一种方法来确定当前应用的根路径,那么上述解决方案之一可能最适合您。另一方面,如果您试图解决可靠地加载应用程序模块的问题,我强烈建议您查看 NODE_PATH 环境变量。
Node 的Modules system 在多个位置寻找模块。 One of these locations is wherever process.env.NODE_PATH points。如果你设置了这个环境变量,那么你可以使用标准模块加载器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 启动您的应用程序,您就可以了。我将它与我的enforce-node-path 模块结合使用,它可以防止在未设置NODE_PATH 的情况下意外加载应用程序。有关强制执行环境变量的更多控制,请参阅checkenv。
一个问题: NODE_PATH 必须设置在节点应用的外部。你不能做像process.env.NODE_PATH = path.resolve(__dirname) 这样的事情,因为模块加载器会在你的应用程序运行之前缓存它会搜索的目录列表。
[2016 年 4 月 6 日添加] 另一个非常有希望尝试解决此问题的模块是 wavy。