从正在运行的 node.js 应用程序确定项目根目录

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10265798/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 15:34:35  来源:igfitidea点击:

Determine project root from a running node.js application

node.js

提问by MrEvil

Is there a better way than process.cwd()to determine the root directory of a running node.js process? Something like the equivalent of Rails.root, but for Node.js. I'm looking for something that is as predictable and reliable as possible.

有没有比process.cwd()确定正在运行的 node.js 进程的根目录更好的方法?类似于Rails.root, 但对于 Node.js。我正在寻找尽可能可预测和可靠的东西。

回答by inxilpro

There are several ways to approach this, each with their own pros and cons:

有几种方法可以解决这个问题,每种方法都有自己的优点和缺点:

require.main.filename

要求.main.filename

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

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

When a file is run directly from Node, require.mainis set to its module. That means that you can determine whether a file has been run directly by testing require.main === module

Because moduleprovides a filenameproperty (normally equivalent to __filename), the entry point of the current application can be obtained by checking require.main.filename.

当文件直接从 Node 运行时,require.main设置为它的module. 这意味着你可以通过测试直接判断一个文件是否已经运行require.main === module

因为module提供了一个filename属性(通常相当于__filename),可以通过检查 获得当前应用程序的入口点require.main.filename

So if you want the base directory for your app, you can do:

因此,如果您想要应用程序的基本目录,您可以执行以下操作:

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

Pros & Cons

优点缺点

This will work great most of the time, but if you're running your app with a launcher like pm2or running mochatests, this method will fail.

大多数情况下这会很好用,但是如果您使用pm2 之类的启动器运行应用程序或运行mocha测试,则此方法将失败。

global.X

全局.X

Node has a a global namespace object called global— anything that you attach to this object will be available everywhere in your app. So, in your index.js(or app.jsor whatever your main app file is named), you can just define a global variable:

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');

Pros & Cons

优点缺点

Works consistently but you have to rely on a global variable, which means that you can't easily reuse components/etc.

始终如一地工作,但您必须依赖全局变量,这意味着您无法轻松重用组件/等。

process.cwd()

进程.cwd()

This returns the current working directory. Not reliable at all, as it's entirely dependent on what directory the process was launched from:

这将返回当前工作目录。根本不可靠,因为它完全取决于进程哪个目录启动:

$ 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

应用程序根路径

To address this issue, I've created a node module called app-root-path. Usage is simple:

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

var appRoot = require('app-root-path');
var myModule = require(appRoot + '/lib/my-module.js');

The app-root-pathmodule uses several different techniques to determine the root path of the app, taking into account globally installed modules (for example, if your app is running in /var/www/but the module is installed in ~/.nvm/v0.x.x/lib/node/). It won't work 100% of the time, but it's going to work in most common scenarios.

应用程序根路径模块使用多种不同的技术来确定该应用程序的根路径,考虑到全球范围内安装的模块(例如,如果应用程序在运行/var/www/,但模块安装在~/.nvm/v0.x.x/lib/node/)。它不会在 100% 的情况下工作,但它会在最常见的情况下工作。

Pros & Cons

优点缺点

Works without configuration in most circumstances. Also provides some nice additional convenience methods (see project page). The biggest con is that it won't work if:

大多数情况下无需配置即可工作。还提供了一些不错的附加便利方法(参见项目页面)。最大的缺点是,如果:

  • You're using a launcher, like pm2
  • AND, the module isn't installed inside your app's node_modulesdirectory (for example, if you installed it globally)
  • 您正在使用启动器,例如 pm2
  • AND,该模块未安装在您的应用程序node_modules目录中(例如,如果您全局安装了它)

You can get around this by either setting a APP_ROOT_PATHenvironmental variable, or by calling .setPath()on the module, but in that case, you're probably better off using the globalmethod.

您可以通过设置APP_ROOT_PATH环境变量或调用.setPath()模块来解决此问题,但在这种情况下,您最好使用该global方法。

NODE_PATH environmental variable

NODE_PATH 环境变量

If you're looking for a way to determinethe root path of the current app, one of the above solutions is likely to work best for you. If, on the other hand, you're trying to solve the problem of loading app modules reliably, I highly recommend looking into the NODE_PATHenvironmental variable.

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

Node's Modules systemlooks for modules in a variety of locations. One of these locations is wherever process.env.NODE_PATHpoints. If you set this environmental variable, then you can requiremodules with the standard module loader without any other changes.

Node 的Modules 系统在不同的位置寻找模块。 这些位置之一是 whereprocess.env.NODE_PATH。如果您设置了这个环境变量,那么您可以require使用标准模块加载器进行模块,而无需进行任何其他更改。

For example, if you set NODE_PATHto /var/www/lib, the the following would work just fine:

例如,如果您设置NODE_PATH/var/www/lib,则以下内容可以正常工作:

require('module2/component.js');
// ^ looks for /var/www/lib/module2/component.js

A great way to do this is using npm:

一个很好的方法是使用npm

"scripts": {
    "start": "NODE_PATH=. node app.js"
}

Now you can start your app with npm startand you're golden. I combine this with my enforce-node-pathmodule, which prevents accidentally loading the app without NODE_PATHset. For even more control over enforcing environmental variables, see checkenv.

现在你可以开始你的应用程序,npm start你是金。我将其与我的执行节点路径模块结合使用,以防止在未NODE_PATH设置的情况下意外加载应用程序。有关强制执行环境变量的更多控制,请参阅checkenv

One gotcha:NODE_PATHmustbe set outsideof the node app. You cannot do something like process.env.NODE_PATH = path.resolve(__dirname)because the module loader caches the list of directories it will search before your app runs.

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

[added 4/6/16]Another really promising module that attempts to solve this problem is wavy.

[2016 年 4 月 6 日添加]另一个尝试解决此问题的真正有前途的模块是wavy

回答by izb

__dirnameisn't a global; it's local to the current module so each file has its own local, different value.

__dirname不是全球性的;它是当前模块的本地文件,因此每个文件都有自己的本地不同值。

If you want the root directory of the running process, you probably do want to use process.cwd().

如果你想要运行进程的根目录,你可能想要使用process.cwd().

If you want predictability and reliability, then you probably need to make it a requirement of your application that a certain environment variable is set. Your app looks for MY_APP_HOME(Or whatever) and if it's there, and the application exists in that directory then all is well. If it is undefined or the directory doesn't contain your application then it should exit with an error prompting the user to create the variable. It could be set as a part of an install process.

如果您想要可预测性和可靠性,那么您可能需要让您的应用程序要求设置某个环境变量。您的应用程序会查找MY_APP_HOME(或其他),如果它在那里,并且该应用程序存在于该目录中,那么一切都很好。如果它未定义或目录不包含您的应用程序,那么它应该退出并提示用户创建变量的错误。它可以设置为安装过程的一部分。

You can read environment variables in node with something like process.env.MY_ENV_VARIABLE.

您可以使用类似process.env.MY_ENV_VARIABLE.

回答by Fareed Alnamrouti

1- create a file in the project root call it settings.js

1- 在项目根目录中创建一个文件,将其命名为settings.js

2- inside this file add this code

2- 在此文件中添加此代码

module.exports = {
    POST_MAX_SIZE : 40 , //MB
    UPLOAD_MAX_FILE_SIZE: 40, //MB
    PROJECT_DIR : __dirname
};

3- inside node_modules create a new module name it "settings" and inside the module index.js write this code:

3- 在 node_modules 内部创建一个新的模块,命名为“settings”,并在模块 index.js 中编写以下代码:

module.exports = require("../../settings");

4- and any time you want your project directory just use

4- 任何时候你想要你的项目目录就使用

var settings = require("settings");
settings.PROJECT_DIR; 

in this way you will have all project directories relative to this file ;)

通过这种方式,您将拥有与此文件相关的所有项目目录;)

回答by Alexander Mills

the easiest way to get the global root (assuming you use NPM to run your node.js app 'npm start', etc)

获取全局根的最简单方法(假设您使用 NPM 运行您的 node.js 应用程序“npm start”等

var appRoot = process.env.PWD;

If you want to cross-verify the above

如果你想交叉验证以上

Say you want to cross-check process.env.PWDwith the settings of you node.js application. if you want some runtime tests to check the validity of process.env.PWD, you can cross-check it with this code (that I wrote which seems to work well). You can cross-check the name of the last folder in appRoot with the npm_package_name in your package.json file, for example:

假设您想process.env.PWD与 node.js 应用程序的设置进行交叉检查。如果你想要一些运行时测试来检查 的有效性process.env.PWD,你可以用这个代码(我写的似乎工作得很好)交叉检查它。您可以使用 package.json 文件中的 npm_package_name 交叉检查 appRoot 中最后一个文件夹的名称,例如:

    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.');
    }

you can also use this NPM module: require('app-root-path')which works very well for this purpose

你也可以使用这个 NPM 模块:require('app-root-path')它非常适合这个目的

回答by Patrick

I've found this works consistently for me, even when the application is invoked from a sub-folder, as it can be with some test frameworks, like Mocha:

我发现这对我来说一直有效,即使从子文件夹调用应用程序,因为它可以用于某些测试框架,例如 Mocha:

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

Why it works:

为什么有效:

At runtime node creates a registry of the full paths of all loaded files. The modules are loaded first, and thus at the top of this registry. By selecting the first element of the registry and returning the path before the 'node_modules' directory we are able to determine the root of the application.

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

It's just one line of code, but for simplicity's sake (my sake), I black boxed it into an NPM module:

这只是一行代码,但为了简单起见(我的缘故),我将其黑箱化到 NPM 模块中:

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

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

Enjoy!

享受!

回答by Konstantin Isaev

All these "root dirs" mostly need to resolve some virtual path to a real pile path, so may be you should look at path.resolve?

所有这些“根目录”大多需要将一些虚拟路径解析为真实的堆路径,所以您可能应该看看path.resolve

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

回答by didxga

As simple as add this line to your module in root, usually it is app.js

就像将这一行添加到 root 中的模块一样简单,通常它是 app.js

global.__basedir = __dirname;

Then _basedir will be accessiable to all your modules.

然后 _basedir 将可以访问您的所有模块。

回答by kvz

Maybe you can try traversing upwards from __filenameuntil you find a package.json, and decide that's the main directory your current file belongs to.

也许您可以尝试向上遍历,__filename直到找到 a package.json,然后确定这是您当前文件所属的主目录。

回答by Avi Tshuva

Actually, i find the perhaps trivial solution also to most robust: you simply place the following file at the root directory of your project: root-path.js which has the following code:

实际上,我发现对于最强大的可能也是微不足道的解决方案:您只需将以下文件放在项目的根目录中:root-path.js,其中包含以下代码:

import * as path from 'path'
const projectRootPath = path.resolve(__dirname)
export const rootPath = projectRootPath

回答by Pankaj Shinde

Add this somewhere towards the start of your main app file (e.g. app.js):

将此添加到主应用程序文件(例如 app.js)的开头:

global.__basedir = __dirname;

This sets a global variable that will always be equivalent to your app's base dir. Use it just like any other variable:

这将设置一个全局变量,该变量将始终等同于您的应用程序的基本目录。像任何其他变量一样使用它:

const yourModule = require(__basedir + '/path/to/module.js');

Simple...

简单的...