除了process.cwd()之外,是否有其他方法来获取当前项目根目录的路径名。Node是否实现了ruby的属性Rails.root之类的东西。我要找的是稳定可靠的东西。
当前回答
我用这个。
我的模块名为mymodule
var BASE_DIR = __dirname.replace(/^(.*\/mymodule)(.*)$/, '$1')
其他回答
__dirname不是全局变量;它是当前模块的局部值,因此每个文件都有自己的局部值,不同的值。
如果您想要运行进程的根目录,则可能需要使用process.cwd()。
如果希望获得可预测性和可靠性,那么可能需要将设置某个环境变量作为应用程序的要求。你的应用程序寻找MY_APP_HOME(或任何东西),如果它在那里,应用程序存在于该目录,那么一切都很好。如果它是未定义的,或者目录不包含您的应用程序,那么它应该退出,并提示用户创建变量。可以将其设置为安装过程的一部分。
您可以使用process.env.MY_ENV_VARIABLE来读取节点中的环境变量。
一个非常简单和可靠的解决办法是cd ..递归地搜索包。Json,考虑到这个文件总是在项目根目录。
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
}
序言
这是一个非常古老的问题,但它似乎在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 require d 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并不少见,也不是不安全的)。如上所述,可以通过回退来调节。
你也可以使用 Git rev-parse——show- topllevel 假设您正在使用git存储库
获得全局根的最简单方法(假设你使用NPM来运行你的node.js应用程序' NPM start',等等)
var appRoot = process.env.PWD;
如果你想交叉验证上面的内容
假设你想交叉检查process.env.PWD与node.js应用程序的设置。如果您想要一些运行时测试来检查process.env的有效性。PWD,你可以用这段代码(我写的似乎工作得很好)交叉检查它。你可以用包中的npm_package_name交叉检查apot中最后一个文件夹的名称。Json文件,例如:
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'),它非常适合这个目的
推荐文章
- 在Node.js中读取文件
- DeprecationWarning:当我将脚本移动到另一个服务器时,由于安全性和可用性问题,Buffer()已弃用
- 我如何确定正确的“max-old-space-size”为Node.js?
- npm犯错!代码UNABLE_TO_GET_ISSUER_CERT_LOCALLY
- Access-Control-Allow-Origin不允许Origin < Origin >
- 如何获得所有已注册的快捷路线?
- 你可以为你的组织托管一个私有的存储库来使用npm吗?
- 如何定位父文件夹?
- Gulp命令未找到-安装Gulp后错误
- 在Node.js中写入文件时创建目录
- 如何将自定义脚本添加到包中。Json文件,运行javascript文件?
- 使用child_process。execSync但保持输出在控制台
- SyntaxError:在严格模式下使用const
- 在Node.js中递归复制文件夹
- 如何在node.js中设置默认时区?