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


当前回答

就像在根目录中添加这一行到你的模块一样简单,通常是app.js或app.ts。

global.__basedir = __dirname;

然后所有模块都可以访问_basedir。

注意:对于typescript实现,遵循上面的步骤,然后你将能够使用global.__basedir使用根目录路径

其他回答

我发现这对我来说是一致的,即使应用程序是从子文件夹中调用的,因为它可以与一些测试框架,如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);

尝试从__dirname向上遍历,直到找到一个包。Json,并确定这是你当前文件所属的应用主根目录。

根据Node文档

包。json文件通常位于Node.js项目的根目录。

const fs = require('fs')
const path = require('path')

function getAppRootDir () {
  let currentDir = __dirname
  while(!fs.existsSync(path.join(currentDir, 'package.json'))) {
    currentDir = path.join(currentDir, '..')
  }
  return currentDir
}

我知道这已经太迟了。 但我们可以通过两个方法获取根URL

1号方法

var path = require('path');
path.dirname(require.main.filename);

2方法

var path = require('path');
path.dirname(process.mainModule.filename);

参考链接:—https://gist.github.com/geekiam/e2e3e0325abd9023d3a3

序言

这是一个非常古老的问题,但它似乎在2020年和2012年一样触动了人们的神经。 我检查了所有其他的答案,没有找到下面提到的技巧(它有自己的局限性,但其他的也不是适用于所有的情况):

Git +子进程

如果你使用Git作为你的版本控制系统,确定项目根的问题可以简化为(我认为项目的正确根-毕竟,你会希望你的VCS有尽可能充分的可见范围):

检索存储库根路径

由于您必须运行CLI命令来执行此操作,因此我们需要生成一个子进程。此外,由于项目根不太可能在运行时中期更改,我们可以在启动时使用child_process模块的同步版本。

我发现spawnSync()最适合这项工作。至于实际要运行的命令,检索根目录的绝对路径所需要的就是git工作树(带有——porcelain选项,以便于解析)。

在答案后面的示例中,我选择返回一个路径数组,因为可能存在多个工作树(尽管它们可能具有公共路径)。注意,当我们使用CLI命令时,shell选项应该设置为true(安全性不应该成为问题,因为没有不可信的输入)。

方法比较和后备

了解到VCS可能无法访问的情况,在分析了文档和其他答案后,我包含了一些备用方案。建议解决方案可归纳为(不含第三方模块和包):

Solution Advantage Main Problem
__filename points to module file relative to module
__dirname points to module dir same as __filename
node_modules tree walk nearly guaranteed root complex tree walking if nested
path.resolve(".") root if CWD is root same as process.cwd()
process.argv\[1\] same as __filename same as __filename
process.env.INIT_CWD points to npm run dir requires npm && CLI launch
process.env.PWD points to current dir relative to (is the) launch dir
process.cwd() same as env.PWD process.chdir(path) at runtime
require.main.filename root if === module fails on required modules

从上面的对比表来看,以下方法是最普遍的:

require.main.filename作为获取根文件的简单方法。Main ===模块满足 最近提出的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。主模块

第二个实现很简单:

/**
 * @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并不少见,也不是不安全的)。如上所述,可以通过回退来调节。

只使用:

 path.resolve("./") ... output is your project root directory