在Node应用中避免“Dot Hell”

转载自:http://blog.leapoahead.com/2015/09/03/prevent-node-require-dot-hell/

在Node应用中,我们使用require来加载模块。在目录层次相对复杂的应用中,总是会出现类似require(‘../../../../../module‘)的调用,我把它称之为Dot Hell。我用了一些时间研究现有的解决方案,并介绍我个人认为最好的方法。

在Node中的全局对象是global,它就像浏览器的window对象一样。global对象下面的方法都可以直接调用。


1

2


global.a = 1

require(‘assert‘).equal(1, a)

因此最简单的方法,也是我认为最好的方式就是在global下创建一个appRequire方法作为require方法的包装,appRequire方法专门用于调用应用内的包。


1

2

3

4


var path = require(‘path‘)

global.appRequire = function(path) {

return require(path.resolve(__dirname, path))

}

假设我们的项目目录结构如下


1

2

3

4

5

6

7

8


├── app

│   ├── controller

│   │   └── AppController.js

│   ├── model

│   │   └── User.js

│   └── view

│   └── AppView.js

└── app.js

其中app.js是应用的入口。那么我们只需要在app.js中应用上面的代码,那么在整个应用程序中就都可以使用了。

例如,现在在app/controller/AppController.js中,我们可以用下面的语句调用app/model/User.js


1

var User = appRequire(‘app/model/User‘)

Oh Yeah! 一切都很优雅,很顺利。

但是一个应用中一定还会有测试代码。以单元测试为例,我们如果用mocha之类的Task Runner去运行测试的话,就得在每个测试前面都加上这一段代码,这样做很容易出错,而且很麻烦。

所以,我们可以把上述的封装代码单独封装成一个文件global-bootstrap.js,在运行mocha的时候,用mocha的require参数来指定每次运行测试之前要加载global-bootstrap.js


1

2

3


# 用Mocha运行tests文件夹下面的所有测试

# 在运行的时候加载should库,以及我们封装的含有appRequire函数的文件

mocha --require should --require global-bootstrap.js --recursive tests

其他方案

对于解决这个问题,还有两种方案:NODE_ENV方案(及其变种)Symlink方案,你可以在这里看到。

我认为应该避免使用这两种方案。虽然这两种方案都可行,但是它们都会可能导致应用自身的目录名和node模块名冲突。例如,在下面的结构中,使用require(‘request‘)就很容易产生二义性。


1

2

3

4

5


.

├── node_modules

│   └── request

└── request

└── index.js

总结

我一直认为Node的模块引用方式的设计是有问题的,Dot Hell就很能说明这点。而Python相对而言就优雅很多,你可以直接通过路径的形式来导入包(在正确配置的情况下)。本文的解决方案允许我们用类似Python的方式去加载模块,你可以在我的项目webcraft中看到其应用。

在Node应用中避免“Dot Hell”

时间: 2025-01-02 18:06:44

在Node应用中避免“Dot Hell”的相关文章

在Node.js中使用RabbitMQ系列二 任务队列

在上一篇文章在Node.js中使用RabbitMQ系列一 Hello world我有使用一个任务队列,不过当时的场景是将消息发送给一个消费者,本篇文章我将讨论有多个消费者的场景. 其实,任务队列最核心解决的问题是避免立即处理那些耗时的任务,也就是避免请求-响应的这种同步模式.取而代之的是我们通过调度算法,让这些耗时的任务之后再执行,也就是采用异步的模式.我们需要将一条消息封装成一个任务,并且将它添加到任务队列里面.后台会运行多个工作进程(worker process),通过调度算法,将队列里的任

Node.js权威指南 (10) - Node.js中的错误处理与断言处理

10.1 使用domain模块处理错误 / 272 10.1.1 domain模块概述 / 272 10.1.2 创建并使用Domain对象 / 274 10.1.3 隐式绑定与显式绑定 / 276 10.1.4 绑定回调函数与拦截回调函数 / 279 10.1.5 domain堆栈的弹出与推入 / 280 10.1.6 Domain对象的销毁 / 28610.2 Node.js中的断言处理 / 286 10.2.1 equal方法与notEqual方法 / 287 10.2.2 strictE

node.js中的交互式运行环境-REPL

<Node.js权威指南>第2章Node.js中的交互式运行环境--REPL 开发者可以在该环境中很方便地输入各种JavaScript表达式并观察表达式的运行结果. 在学习Node.js框架的过程中,通过该运行环境的使用,我们可以很方便地了解Node.js中定义的各种对象所拥有的各种属性及方法.本节为大家介绍在REPL运行环境中操作变量 2.2 在REPL运行环境中操作变量 在REPL运行环境中,可以使用var关键字来定义一个变量并为其赋值,但是在输入了对其赋值进行的表达式后,该表达式的执行结

node.js中的exports和module.exports

不同的编程语言都有各自的代码组织和复用的方式,如.net.php中的命名空间,python中的import,ruby中的module等,来避免命名空间污染.一直都没搞清楚node中的exports和module.exports的区别,借此搞清楚node的代码模块复用方式. 首先怎么创建node中的modules. 可以直接创建一个文件作为module,如下module.js function writeLine(){ console.log("module.js"); } export

在node.js中使用COOKIE

node.js中如何向客户端发送COOKIE呢?有如下两个方案: 一.使用response.writeHead,代码示例: //设置过期时间为一分钟 1 var today = new Date(); 2 var time = today.getTime() + 60*1000; 3 var time2 = new Date(time); 4 var timeObj = time2.toGMTString(); 5 response.writeHead({ 6 'Set-Cookie':'myC

setTimeout函数在浏览器中和Node.js中的区别

setTimeout函数delay时间之后执行一次func. setTimeout函数原型: var timeoutID = window.setTimeout(func, [delay, param1, param2, ...]); var timeoutID = window.setTimeout(code, [delay]);//not recommended for the same reasons as using eval() //param1, param2, and so for

log4js-Node.js中的日志管理模块使用与封装

开发过程中,日志记录是必不可少的事情,尤其是生产系统中经常无法调试,因此日志就成了重要的调试信息来源. Node.js,已经有现成的开源日志模块,就是log4js,源码地址:点击打开链接 项目引用方法: npm install log4js 1.配置说明(仅以常用的dateFile日志类型举例,更多说明参考log4js-wiki): { "appenders": [ // 下面一行应该是用于跟express配合输出web请求url日志的 {"type": "

笔记-Node.js中的核心API之HTTP

最近正在学习Node,在图书馆借了基本关于Node的书,同时在网上查阅资料,颇有收获,但是整体感觉对Node的理解还是停留在一个很模棱两可的状态.比如Node中的模块,平时练习就接触到那么几个,其他的一些模块暂时只会在学习的时候接触到,不常用便就荒废了.正所谓好记心不如烂笔头,多做笔记还是更有利于理解和记忆.自己做的总结也方便回头复习,所以决定踏上漫长的修炼之旅-- Node提供了许多API,其中一些比较重要.这些核心的API是所有Node应用的支柱,你会不停的用到他们. HTTP服务器 Nod

NodeJs&gt;-------&gt;&gt;第二章:Node.js中交互式运行环境--------REL

第二章:Node.js中交互式运行环境--------REL 一:REPL运行环境概述 1 C:\Users\junliu>node 2 > foo = 'bar' ; 3 'bar' 4 > 二:在REPL运行环境中操作变量 1 C:\Users\junliu>node 2 > foo='bar' 3 'bar' 4 > var foo='bar' 5 undefined 6 > 1 console.log("foo='bar'"); //控