除了process.cwd()之外,是否有其他方法来获取当前项目根目录的路径名。Node是否实现了ruby的属性Rails.root之类的东西。我要找的是稳定可靠的东西。


当前回答

在app.js中创建一个函数

/*函数获取应用程序根文件夹*/

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。

我发现这对我来说是一致的,即使应用程序是从子文件夹中调用的,因为它可以与一些测试框架,如Mocha:

process.mainModule.paths[0].split('node_modules')[0].slice(0, -1);

为什么有效:

在运行时,节点创建所有加载文件的完整路径的注册表。模块首先加载,因此位于注册表的顶部。通过选择注册表的第一个元素并返回'node_modules'目录之前的路径,我们可以确定应用程序的根目录。

它只有一行代码,但为了简单起见(我的),我把它黑盒到一个NPM模块:

https://www.npmjs.com/package/node-root.pddivine

享受吧!

编辑:

的过程。mainModule从v14.0.0开始已弃用

使用要求。主要:

require.main.paths [0] .split(“node_modules”)[0]。片(0,1);

所有这些“根dirs”大多需要解析一些虚拟路径到一个真实的堆路径,所以可能你应该看看path.resolve?

var path= require('path');
var filePath = path.resolve('our/virtual/path.ext');

__dirname会给你根目录,只要你在根目录下的文件中。

// ProjectDirectory.js (this file is in the project's root directory because you are putting it there).
module.exports = {

    root() {
        return __dirname;
    }
}

在其他文件中:

const ProjectDirectory = require('path/to/ProjectDirectory');
console.log(`Project root directory is ${ProjectDirectory.root}`);

解决这个问题有很多种方法,每种方法都有其优缺点:

require.main.filename

从http://nodejs.org/api/modules.html:

当一个文件直接从Node运行时,require。Main被设置为它的模块。这意味着您可以通过测试require来确定文件是否已经直接运行。Main ===模块 因为module提供了一个filename属性(通常等价于__filename),当前应用程序的入口点可以通过检查require.main.filename来获得。

如果你想要应用的基目录,你可以这样做:

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

优点与缺点

这种方法在大多数情况下都很有效,但如果你使用pm2之类的启动器或运行mocha测试,这种方法就会失败。这在使用Node.js ES模块时也不起作用。Main不可用。

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
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

为了解决这个问题,我创建了一个名为app-root-path的节点模块。用法很简单:

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

app-root-path模块使用了几种技术来确定应用程序的根路径,考虑到全局安装的模块(例如,如果你的应用程序运行在/var/www/,但模块安装在~/.nvm/ v2 .x.x/lib/node/)。它不会在100%的情况下工作,但在大多数常见的情况下都会工作。

优点与缺点

在大多数情况下不需要配置即可工作。还提供了一些很好的额外方便的方法(参见项目页面)。最大的骗局是,如果出现以下情况,它就不会起作用:

你用的是启动器,比如pm2 并且,该模块没有安装在你的应用程序的node_modules目录中(例如,如果你全局安装它)

您可以通过设置APP_ROOT_PATH环境变量或在模块上调用. setpath()来解决这个问题,但在这种情况下,您可能最好使用全局方法。

NODE_PATH环境变量

如果你正在寻找一种方法来确定当前应用程序的根路径,上述解决方案之一可能最适合你。另一方面,如果您试图解决可靠地加载应用程序模块的问题,我强烈建议查看NODE_PATH环境变量。

Node的Modules系统在不同的位置寻找模块。其中一个位置是process.env. exe。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启动你的应用程序,你就成功了。我将其与我的强制节点路径模块结合起来,这可以防止在没有设置NODE_PATH的情况下意外加载应用程序。更多关于环境变量的控制,请参见checkenv。

有一个问题:NODE_PATH必须在节点应用程序之外设置。你不能做process.env之类的事情。NODE_PATH = path.resolve(__dirname),因为模块加载器在应用程序运行之前缓存了它要搜索的目录列表。

[增加4/6/16]另一个非常有前途的模块,试图解决这个问题是波浪。