How to handle circular dependencies with RequireJS/AMD? How to handle circular dependencies with RequireJS/AMD? javascript javascript

How to handle circular dependencies with RequireJS/AMD?


This is indeed a restriction in the AMD format. You could use exports, and that problem goes away. I find exports to be ugly, but it is how regular CommonJS modules solve the problem:

define("Employee", ["exports", "Company"], function(exports, Company) {    function Employee(name) {        this.name = name;        this.company = new Company.Company(name + "'s own company");    };    exports.Employee = Employee;});define("Company", ["exports", "Employee"], function(exports, Employee) {    function Company(name) {        this.name = name;        this.employees = [];    };    Company.prototype.addEmployee = function(name) {        var employee = new Employee.Employee(name);        this.employees.push(employee);        employee.company = this;    };    exports.Company = Company;});

Otherwise, the require("Employee") you mention in your message would work too.

In general with modules you need to be more aware of circular dependencies, AMD or not. Even in plain JavaScript, you have to be sure to use an object like the G object in your example.


I think this is quite a drawback in larger projects where (multi-level) circular dependencies dwell undetected.However, with madge you can print a list of circular dependencies to approach them.

madge --circular --format amd /path/src


If you don't need your dependencies to be loaded at the start (e.g., when you are extending a class), then this is what you can do: (taken from http://requirejs.org/docs/api.html#circular)

In the file a.js:

    define( [ 'B' ], function( B ){        // Just an example        return B.extend({            // ...        })    });

And in the other file b.js:

    define( [ ], function( ){ // Note that A is not listed        var a;        require(['A'], function( A ){            a = new A();        });        return function(){            functionThatDependsOnA: function(){                // Note that 'a' is not used until here                a.doStuff();            }        };    });

In the OP's example, this is how it would change:

    define("Employee", [], function() {        var Company;        require(["Company"], function( C ){            // Delayed loading            Company = C;        });        return function (name) {            this.name = name;            this.company = new Company(name + "'s own company");        };    });    define("Company", ["Employee"], function(Employee) {        function Company(name) {            this.name = name;            this.employees = [];        };        Company.prototype.addEmployee = function(name) {            var employee = new Employee(name);            this.employees.push(employee);            employee.company = this;        };        return Company;    });    define("main", ["Employee", "Company"], function (Employee, Company) {        var john = new Employee("John");        var bigCorp = new Company("Big Corp");        bigCorp.addEmployee("Mary");    });