从运行的node.js应用程序确定项目根目录 [英] Determine project root from a running node.js application
问题描述
是否有比process.cwd()
更好的方法来确定正在运行的node.js进程的根目录?类似Rails.root
的东西,但适用于Node.js.我正在寻找一种尽可能可预测和可靠的东西.
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.
推荐答案
有几种解决方法,每种方法各有利弊:
There are several ways to approach this, each with their own pros and cons:
来自 http://nodejs.org/api/modules.html :
直接从Node运行文件时,
require.main
设置为其module
.这意味着您可以通过测试require.main === module
When a file is run directly from Node,
require.main
is set to itsmodule
. That means that you can determine whether a file has been run directly by testingrequire.main === module
由于module
提供了filename
属性(通常等效于__filename
),因此可以通过选中require.main.filename
来获取当前应用程序的入口点.
Because module
provides a filename
property (normally equivalent to __filename
), the entry point of the current application can be obtained by checking 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);
优点&缺点
这在大多数情况下都非常有效,但是如果您使用 pm2 之类的启动器运行应用程序或运行 mocha 测试,则此方法将失败.
Pros & Cons
This will work great most of the time, but if you're running your app with a launcher like pm2 or running mocha tests, this method will fail.
Node有一个名为global
的全局命名空间对象-您附加到此对象的任何内容都将在您的应用程序中随处可见.因此,在您的index.js
(或app.js
或您的主应用程序文件中的任何名称)中,您只需定义一个全局变量即可:
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.js
or whatever your main app file is named), you can just define a global variable:
// 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.
这将返回当前工作目录.根本不可靠,因为它完全取决于进程从哪个目录从启动:
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
为解决此问题,我创建了一个名为 app-的节点模块根路径 .用法很简单:
app-root-path
To address this issue, I've created a node module called app-root-path. Usage is simple:
var appRoot = require('app-root-path');
var myModule = require(appRoot + '/lib/my-module.js');
app-root-path 模块考虑到全局安装的模块,使用了几种不同的技术来确定应用程序的根路径(例如,如果您的应用程序在/var/www/
中运行,但该模块在~/.nvm/v0.x.x/lib/node/
中安装).它不会100%地起作用,但是可以在大多数常见情况下起作用.
The app-root-path module 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.
在大多数情况下无需配置即可工作.还提供了一些不错的附加便利方法(请参阅项目页面).最大的缺点是,如果满足以下条件,它将无法正常工作:
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:
- 您正在使用启动器,例如pm2
- AND ,该模块未安装在应用程序的
node_modules
目录中(例如,如果您是全局安装的)
- You're using a launcher, like pm2
- AND, the module isn't installed inside your app's
node_modules
directory (for example, if you installed it globally)
您可以通过设置APP_ROOT_PATH
环境变量或在模块上调用.setPath()
来解决此问题,但在这种情况下,最好使用global
方法.
You can get around this by either setting a APP_ROOT_PATH
environmental variable, or by calling .setPath()
on the module, but in that case, you're probably better off using the global
method.
如果您正在寻找确定当前应用程序根路径的方法,则上述解决方案之一可能最适合您.另一方面,如果您要解决可靠加载应用程序模块的问题,则强烈建议您查看NODE_PATH
环境变量.
If you're looking for a way to determine the 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_PATH
environmental variable.
Node的模块系统查找各种位置的模块. 其中一个位置是process.env.NODE_PATH
指向的任何地方.如果设置了此环境变量,则可以使用标准模块加载器require
模块,而无需进行其他任何更改.
Node's Modules system looks for modules in a variety of locations. One of these locations is wherever process.env.NODE_PATH
points. If you set this environmental variable, then you can require
modules with the standard module loader without any other changes.
例如,如果将NODE_PATH
设置为/var/www/lib
,则以下内容将正常工作:
For example, if you set NODE_PATH
to /var/www/lib
, the the following would work just fine:
require('module2/component.js');
// ^ looks for /var/www/lib/module2/component.js
执行此操作的一种好方法是使用npm
:
A great way to do this is using npm
:
"scripts": {
"start": "NODE_PATH=. node app.js"
}
现在,您可以使用npm start
启动您的应用程序,您就很成功了.我将其与我的 enforce-node-path 模块结合使用,可以防止意外加载应用程序而无需NODE_PATH
设置.有关对执行环境变量的更多控制,请参见 checkenv .
Now you can start your app with npm start
and you're golden. I combine this with my enforce-node-path module, which prevents accidentally loading the app without NODE_PATH
set. For even more control over enforcing environmental variables, see checkenv.
一个陷阱: NODE_PATH
必须设置为节点应用的外部.您无法执行process.env.NODE_PATH = path.resolve(__dirname)
之类的操作,因为模块加载程序会在应用运行之前缓存将搜索的目录列表.
One gotcha: NODE_PATH
must be set outside of 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.
[16年4月6日添加] 另一个试图解决此问题的非常有前途的模块是
[added 4/6/16] Another really promising module that attempts to solve this problem is wavy.
这篇关于从运行的node.js应用程序确定项目根目录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!