8

Basically, the idea is that "sub" module creates an object, and that object should be part of a utilities library which is the "main" module. However, the "sub" object depends on utilities from "main":

// Main module
define(['sub'], function(sub) {
    var utils = {
        utilityMain: function () {
           // ...
        };
        // ...
    };

    tools.subModule = sub;

    return tools;
});

// Sub module
define(['main'], function(main) {
    return new (function () {

        // Singleton object using functions in main module
        var somestuff = function () {
            main.utilityMain();
            // etc
        };
    })();
});   

How can I achieve this with require.js without creating a black hole that would swallow the whole planet?

Thank you very much.

pilau
  • 6,635
  • 4
  • 56
  • 69

1 Answers1

6

There are a few things suggested in the docs:

b can fetch a later after modules have been defined by using the require() method (be sure to specify require as a dependency so the right context is used to look up a)

e.g.:

// Sub module
define(['require'], function(require) {
    return new (function () {

        // Singleton object using functions in main module
        var somestuff = function () {
            require('main').utilityMain();
            // etc
        };
    })();
});

or

you could instead use exports to create an empty object for the module that is available immediately for reference by other modules

e.g.:

// Main module
define(['sub', 'exports'], function(sub, exports) {
    exports.utilityMain: function () {
       // ...
    };

    exports.subModule = sub.sub;
});
// Sub module
define(['main', 'exports'], function(main, exports) {
    exports.sub = new (function () {

        // Singleton object using functions in main module
        var somestuff = function () {
            main.utilityMain();
            // etc
        };
    })();
});

and

Circular dependencies are rare, and usually a sign that you might want to rethink the design

freejosh
  • 11,263
  • 4
  • 33
  • 47
  • "rethink the design", I totally agree but it's a bit tight for that at the moment. I have already researched and looked into what you're proposing... I've been trying to wrap my head around the `exports` object for the past two days, and now you're telling me it is available *immediately*? I thought that `exports` is returned to `define`/`require` only once the factory function resumes execution? On a second look, it seems you're suggesting that `main` should resume execution only once `sub` resumes? – pilau Jun 17 '13 at 16:21
  • I would really appreciate it if you could really lay out the order in which these things all happen. I think this is where I fail to grasp how this workaround solves my problem. Thanks! – pilau Jun 17 '13 at 16:24
  • 1
    Using `exports` just allows each module to have a reference to some object instead of `undefined` for each module. You can't immediately use the _functions_ of either module, but you can be sure that the references will be set up properly at runtime. Think of both module definitions running in parallel. They both know where to _look_ for the other module, but neither can interact until they're both complete. – freejosh Jun 17 '13 at 16:29
  • I understand, but I don't see how that solves it. Because the `sub` model explicitly depends on some functions in `main`, but `main` only needs to get the return value from `sub`. I think I will just load them both in a parent module and have *that* one combine and return them as a single object. Talk about "rethinking the design"... :) Of course if you feel like elaborating further on your solution I am indeed all ears! – pilau Jun 17 '13 at 18:45
  • What's your definition of solve? The `exports` technique solves the problem where circularly-dependent modules will return `undefined`. The `require` technique solves the problem of having a dependency loop at define-time. – freejosh Jun 17 '13 at 18:54
  • My definition of solve is to implement what I described in my question :) Despite your explanations and everything I have read online so far I am still having trouble with grasping how AMD/CommonJS/RequireJS handles circular dependency. I couldn't find any description on the order of things that happen behind the unicorn magic which is "RequireJS and circular dependency". Put it simply, `exports` for me is still a black box. What happens inside it, and **when** it happens, is a mystery to me. – pilau Jun 19 '13 at 13:36