【问题标题】:Node requiring module before it's exposed is causing undefined在暴露之前需要模块的节点导致未定义
【发布时间】:2014-08-23 21:49:36
【问题描述】:

我最终试图在我的foo-dao.js 文件中要求var server = require('../../index.js');,这样我就可以访问 hapi 服务器插件,而无需通过 hapi request 对象从控制器传递到 dao。

在我的 foo-dao.js 方法的 cmets 中尝试在文件顶部需要 index.js 时可以看到问题。

我认为问题是因为在我的 index.js 中,它需要 ./modules 文件夹,该文件夹需要 ./modules/foo/foo-routes.js 需要 ./modules/foo/foo-ctrl.js这需要 ./modules/foo/foo-dao.js。

这是需求的简化视图

./modules/index.js -> ./modules/foo/foo-routes.js -> ./modules/foo/foo-ctrl.js -> ./modules/foo/foo-dao.js - > ./modules/index.js

/hapi/index.js

/**
 * Hapi.js server.
 *
 * @type {exports}
 */
var Hapi = require('hapi');
var modules = require('./modules');

// Instantiate the server
var server = new Hapi.Server('0.0.0.0', 4445, {cors: true, debug: {request: ['error']}});

...

/**
 * Add all the modules within the modules folder
 */
for(var route in modules) {
  server.route(modules[route]);
}

/**
 * Expose the server's methods when used as a require statement
 *
 * @type {exports.server}
 */
module.exports = server;

/hapi/modules/foo/foo-routes.js

var Joi = require('Joi');
var fooController = require('./foo-ctrl');

module.exports = function() {
  return [
    {
      method: 'GET',
      path: '/api/foo',
      config: {
        handler: fooController.foo//,
      }
    }
  ]
}();

/hapi/modules/foo/foo-ctrl.js

var fooDao = require('./foo-dao');

module.exports = function() {

  return {

    foo: function foo(req, reply) {

      fooDao.findFoo(function(err, data) {

        if (err) {
          return reply(Boom.badImplementation(err));
        }

        reply(data);
      });
    }
  }
}();

/hapi/modules/foo/foo-dao.js

var server = require('../../index.js');  //  WHEN I REQUIRE THE FILE HERE, IT'S UNDEFINED, PROBABLY BECAUSE THE server OBJECT HAS NOT BEEN EXPOSED YET

console.log('server = ');
console.log(server);

module.exports = function() {

  return {

    findFoo: function findFoo(callback) {
      var server = require('../../index.js');  //  WHEN I REQUIRE THE FILE HERE, IT'S ACTUALLY DEFINED, PROBABLY BECAUSE THE server OBJECT HAS BEEN EXPOSED BY THIS POINT. I DON'T WANT TO HAVE TO REQUIRE INDEX.JS IN EVERY SINGLE FUNCTION THOUGH. HOW CAN I CIRCUMVENT THIS PROBLEM?
      ... get data and return it in the callback
    }
  }
}();

【问题讨论】:

  • 好的,让它变成非圆形的。
  • @minitech 天才!为什么我没有想到呢?哦,等等,我确实发现了问题,我正在寻求帮助以不使其循环。
  • 好吧,要么一个组件的每个部分都需要另一个组件的每个部分才能运行,这是不可能的,要么你可以将它分解成更多的模块,或者如果你需要比索引更具体的模块已经完成了第一步。
  • 我不太明白..

标签: javascript node.js hapijs


【解决方案1】:

我最终试图要求 var server = require('../../index.js');在我的 foo-dao.js 文件中,这样我就可以访问 hapi 服务器插件,而无需通过 hapi 请求对象从控制器传递到 dao。

这非常清楚地表明 CommonJS 系统试图将您从糟糕的设计中拯救出来。不要采用子模块并使其了解更高相关的父模型。它使子模块不可重用,并将其与包含应用程序强耦合,这与您想要的相反。深度的、可重用的模块应该通过选项和请求对象获得它们需要的东西,而不是通过要求更高级别的应用抽象。

这是您想要在foo-dao.js 中执行的操作,至少是解决您的循环需求问题的第一步。但除此之外,我认为您需要对代码结构进行更广泛的更改以使其干净。

module.exports = function makeDao(server) {

  return {
    findFoo: function findFoo(callback) {
      //now via closure you have permanent access to the server,
      //without being coupled so tightly to it's exact filesystem location
    }
  }
};

要加载它,您需要从顶部向下传递服务器实例,在您的情况下是 modules

var server = new Hapi.Server('0.0.0.0', 4445, {cors: true, debug: {request: ['error']}});
var modules = require('./modules')(server);

这将使您的模块代码更易于测试(依赖注入)和重用。

我在express_code_structure 存储库中详细说明了我的整体方法。特别注意appinstance 是如何传递给路由的。其工作原理的细节随着 express4 的变化而变化,我确信 hapi.js 有所不同,但总体思路可能仍然适用。

【讨论】:

  • 我不知道您可以将变量传递给像这样的require 语句。我将如何以不同的方式构造我的代码以使其更干净?在我需要在我的 dao 方法中访问服务器之前,它非常干净,我需要它的唯一原因是访问 hapijs 插件(我最终甚至可能不会将它作为插件留下,因为它会造成如此多的痛苦和重组)
  • 我不是。仔细看。该模块导出一个函数。外部代码需要模块(它是一个函数),使用一些配置调用该函数,然后使用应用程序中返回的值。这种模式很常见,几乎所有 express 中间件(类似于 hapi 插件)都使用这种模式。例如,如果你想限制上传大小,你可以这样做 var limitMiddleware = require('limiter')({size: 100});
  • 对于您的特定问题,我很难就 FS 布局和代码组织为您提供具体建议,但尽管 require('../ 有合法用途,但通常是代码味道表明您没有得到你的关注点分离了。
  • 有趣。好吧,我对 Hapi 插件架构很好奇。我知道如何在不使用 Hapi 插件的情况下做到这一点,并且它不会创建循环依赖,但我只是尝试使用插件架构,这可能是没有意义的情况。
  • 我想我不同意你的看法,require('../通常是一种代码味道。这一切都取决于你想做什么。例如,我的项目根目录中有一个常量文件。我需要使用../ 来引用该文件。我还创建了一个库,位于我的 root/lib 文件夹中。如果我在root/controllers/module/someFile.js 工作,我还必须使用../../lib
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-16
  • 2016-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多