我想要求我的文件总是通过我的项目的根,而不是相对于当前模块。

例如,如果查看https://github.com/visionmedia/express/blob/2820f2227de0229c5d7f28009aa432f9f3a7b5f9/examples/downloads/app.js第6行,您将看到

express = require('../../')

在我看来,这真的很糟糕。假设我想让我所有的例子都只靠近根结点一层。这是不可能的,因为我必须更新超过30个例子,并且在每个例子中更新很多次。:

express = require('../')

我的解决方案是有一个基于根的特殊情况:如果字符串以$开头,那么它相对于项目的根文件夹。

任何帮助都是感激的,谢谢

更新2

现在我使用require.js,它允许你以一种方式编写,在客户端和服务器上都可以工作。Require.js还允许你创建自定义路径。

更新3

现在我转移到webpack + gulp,我使用enhanced-require来处理服务器端模块。看这里的基本原理:http://hackhat.com/p/110/module-loader-webpack-vs-requirejs-vs-browserify/


当前回答

如果你使用yarn而不是npm,你可以使用工作区。

假设我有一个文件夹服务,我希望更容易地需要:

.
├── app.js
├── node_modules
├── test
├── services
│   ├── foo
│   └── bar
└── package.json

要创建Yarn工作空间,需要创建一个包。services文件夹中的Json文件:

{
  "name": "myservices",
  "version": "1.0.0"
}

在你的主包里。json添加:

"private": true,
"workspaces": ["myservices"]

从项目的根目录运行yarn install。

然后,在代码的任何地方,你可以这样做:

const { myFunc } = require('myservices/foo')

而不是像这样:

const { myFunc } = require('../../../../../../services/foo')

其他回答

我们准备尝试一种新的方法来解决这个问题。

以其他已知项目(如spring和guice)为例,我们将定义一个“context”对象,它将包含所有的“require”语句。

该对象将被传递给所有其他模块使用。

例如

var context = {}

context.module1 = require("./module1")( { "context" : context } )
context.module2 = require("./module2")( { "context" : context } )

这要求我们将每个模块编写为一个接收选项的函数,这对我们来说是一个最佳实践。

module.exports = function(context){ ... }

然后你会引用上下文而不是要求东西。

var module1Ref = context.moduel1;

如果您愿意,可以轻松地编写一个循环来执行require语句

var context = {};
var beans = {"module1" : "./module1","module2" : "./module2" }; 
for ( var i in beans ){
    if ( beans.hasOwnProperty(i)){
         context[i] = require(beans[i])(context);
    }
};

当您想要模拟(测试)时,这将使工作变得更容易,并且在使代码作为包可重用的同时解决了您的问题。

您还可以通过分离bean声明来重用上下文初始化代码。 例如,你的main.js文件可能是这样的

var beans = { ... }; // like before
var context = require("context")(beans); // this example assumes context is a node_module since it is reused.. 

这种方法也适用于外部库,不需要每次我们需要它们时都硬编码它们的名称-但是它需要特殊处理,因为它们的导出不是需要上下文的函数。

稍后,我们还可以将bean定义为函数——这将允许我们根据环境需要不同的模块——但这超出了这个线程的范围。

假设你的项目根目录是当前的工作目录,这应该是有效的:

// require built-in path module
path = require('path');

// require file relative to current working directory
config = require( path.resolve('.','config.js') );

我喜欢做的是利用node从node_module目录加载的方式。

如果有人试图加载“thing”模块,他会做如下的事情

require('thing');

Node将在'node_module'目录中查找'thing'目录。

由于node_module通常位于项目的根,所以我们可以利用这种一致性。(如果node_module不在根节点上,那么您就会遇到其他令人头痛的问题。)

如果我们进入目录,然后从目录中返回,我们可以获得到节点项目根的一致路径。

require('thing/../../');

如果我们想访问/happy目录,我们会这样做。

require('thing/../../happy');

虽然这有点粗糙,但是我觉得如果node_modules加载的功能发生了变化,将会有更大的问题需要处理。这种行为应该保持一致。

为了使事情更清楚,我这样做,因为模块的名称并不重要。

require('root/../../happy');

我最近在angular2中使用了它。我想从根目录加载服务。

import {MyService} from 'root/../../app/services/http/my.service';

手动符号链接(和Windows连接)

examples目录中不能包含一个node_modules,该node_modules带有指向项目根目录的符号链接吗?/因此允许示例使用require('project'),尽管这并没有删除映射,但它允许源代码使用require('project')而不是require('../../')。

我已经对此进行了测试,它确实适用于v0.6.18。

项目目录清单:

$ ls -lR project
project:
drwxr-xr-x 3 user user 4096 2012-06-02 03:51 examples
-rw-r--r-- 1 user user   49 2012-06-02 03:51 index.js

project/examples:
drwxr-xr-x 2 user user 4096 2012-06-02 03:50 node_modules
-rw-r--r-- 1 user user   20 2012-06-02 03:51 test.js

project/examples/node_modules:
lrwxrwxrwx 1 user user 6 2012-06-02 03:50 project -> ../../

index.js的内容将一个值赋给exports对象的一个属性,并调用console.log,并用一条消息声明它是必需的。test.js的内容是require('project')。

自动化的符号链接

手动创建符号链接的问题是,每次你npm ci时,你都会丢失符号链接。如果您使符号链接进程成为依赖项,那么就没有问题。

模块basetag是一个postinstall脚本,它在每次运行npm install或npm ci时创建一个名为$的符号链接(或Windows连接):

npm install --save basetag
node_modules/$ -> ..

这样,您就不需要对代码或require系统进行任何特殊修改。$成为您可以从中进行请求的根。

var foo = require('$/lib/foo.js');

如果你不喜欢使用$,而更喜欢#或其他(除了@,这是npm的一个特殊字符),你可以fork它并进行更改。

注意:虽然Windows符号链接(到文件)需要管理员权限,但Windows连接(到目录)不需要管理员权限。这是一种安全、可靠、跨平台的解决方案。

我在我的项目中使用process.cwd()。例如:

var Foo = require(process.cwd() + '/common/foo.js');

值得注意的是,这将导致需要一个绝对路径,尽管我还没有在这方面遇到问题。