Catch-22 recursive Node modules blowing up when using Mocha

久未见 提交于 2020-01-06 15:03:21

问题


I've been working on a project that uses some custom Node.js modules. I've created a 'helpers' module that assists with loading some helper methods:

/helpers/index.js:

var mutability = require('./mutability'),
    cb = require('./cb'),
    build = require('./build'),
    userAgent = require('./userAgent'),
    is = require('./is'),
    query = require('./query'),
    config = require('./config'),
    _ = require('underscore')

module.exports = _.extend({
    cb: cb,
    build: build,
    userAgent: userAgent,
    is: is,
    query: query,
    config: config
}, mutability)

For fun, mutability.js is:

'use strict'

module.exports = {
    setReadOnly: function(obj, key) {
        // whatever
        return obj
    },
    setWritable: function(obj, key) {
        // whatever
        return obj
    }
}

One of my modules, build, requires a class to do some type checking:

/helpers/build.js

'use strict'

var urljoin = require('url-join'),
    config = require('./config'),
    cb = require('./cb'),
    Entity = require('../lib/entity'),
    _ = require('underscore')

module.exports = {
    url: function(options) {
        return urljoin(
            config.baseUrl,
            options.client.orgId,
            options.client.appId,
            options.type, (typeof options.uuidOrName === 'string') ? options.uuidOrName : ""
        )
    },
    GET: function(options) {
        options.type = options.type || args[0] instanceof Entity ? args[0]._type : args[0]
        options.query = options.query || args[0] instanceof Entity ? args[0] : undefined
        return options
    }
}

And Entity then requires helpers:

/lib/entity.js

'use strict'

var helpers = require('../helpers'),
    ok = require('objectkit'),
    _ = require('underscore')

var Entity = function(object) {
    var self = this

    _.extend(self, object)

    helpers.setReadOnly(self, ['uuid'])

    return self
}

module.exports = Entity

For whatever reason, when I run this with Mocha, I get helpers logging out as {} and Mocha throws:

Uncaught TypeError: helpers.setReadOnly is not a function

When I run /lib/entity.js directly with node, it prints the proper module. What gives? Why is Mocha blowing up?


回答1:


You are correct that the issue is your circular dependency between index.js and entity.js.

Your dependency graph looks like this (with normalised paths) where each arrow is a require statement:

/helpers/index.js -> /helpers/build.js -> /lib/entity.js -> /helpers/index.js

When a module is required in Node module.exports is initialised to an empty object.

When you have a circular dependency then it's possible that this default object is returned to another module before your code has run to actually set module.exports = ...; (because JavaScript is synchronous).

This is what is happening in your case: /lib/entity.js is receiving the default exports object from /helpers/index.js before index.js has defined it's module.exports = _.extend(...).

To fix it you need to make sure that you extend the same object that has been returned to /lib/entity.js, instead of replacing it with a new instance:

// Extend `module.exports` instead of replacing it with a new object.
module.exports = _.extend(
    module.exports,
    {
        cb: cb,
        build: build,
        userAgent: userAgent,
        is: is,
        query: query,
        config: config
    },
    mutability
);

However, it's generally best to avoid circular dependencies if possible.



来源:https://stackoverflow.com/questions/34079751/catch-22-recursive-node-modules-blowing-up-when-using-mocha

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!