Ilya Tsuryev
Ilya Tsuryev

Reputation: 2846

How to properly resolve circular dependency in require.js

I have following module configuration: Global -> Collections -> Favorites (global requires collections, collections require favorites).

At the same time Favorites also need Global module (for its' other properties).

Sample code:

define("global", ["collections"], function(Collections) {
    console.log("Defining global");

    var Global = {
        env: "home",
        collections: Collections
    };

    return Global;
});
define("collections", ["favorites"], function(Favorites) {
    console.log("Defining collections");

    var collections = {
        likes: function() {},
        favorites: Favorites
    };

    return collections;
});
define("favorites", ["global"], function(Global) {
    console.log("Defining favorites");

    var Favorites = function(name) {
        console.log(Global.env)
        this.name = name;
    };
    return Favorites;
});

require(["global"], function(Global) {
    console.log("global", Global);
    console.log("collections", Global.collections);
    console.log("favorites", Global.collections.favorites);

    var Favorites = Global.collections.favorites;
    Favorites();
});

I've also created jsfiddle for this case: http://jsfiddle.net/NBSzC/

As you can see this codes produces error as we are trying to read value (env) from undefined.

Here on StackOverflow there is other helpful ticket on the same case: How to handle circular dependencies with RequireJS/AMD?

Using it I was able to make it "work", please check following fiddle: http://jsfiddle.net/NBSzC/1/

And the issue here is in the fact that I had to use

console.log(Global.Global.env)

as original Global now points to exports object and there we've set up link to Global as Global.

We could also do following in the Global module but I believe this is another hack:

_.extend( exports, Global );

In the corresponding link there was no such problem at all, not sure what I am doing wrong.

Upvotes: 2

Views: 902

Answers (1)

Nikos Paraskevopoulos
Nikos Paraskevopoulos

Reputation: 40318

I have the feeling that circular dependencies are a "smell" that the code organization suffers.

In your case I would argue that you do not need the collections field in globals. If something depends on collections, why not ask for the collections module directly?

In this case the dependencies will be: Collections → Favorites → Globals (but Globals does not point back to Favorites, thus the circle is broken).

Then, if you really need to load everything from the beginning, you could modify the require() call:

require(["global","collections"], function(Global,Collections) { ...

Or define a bootstrap module that requires everything and require that:

define("bootstrap",["global","collections","favorites"], function(...) { ...
require("bootstrap", ...)

Of course I do not have all the details of your project, so the solution may be different. But still the main point is that circular dependencies are a smell.

Upvotes: 1

Related Questions