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.
How to handle circular dependencies?
UPDATE: https://stackoverflow.com/a/42264822/14731 contains an updated answer for ES6 modules.
I figured it out: We need to create a "gatekeeper" file that will define functions that depend on the circular dependencies.
- Rename
ObjectPreconditions.js
toAbstractObjectPreconditions.js
. - Create a new
ObjectPreconditions.js
file (our new gatekeeper). - Move any circular dependencies out of
AbstractObjectPreconditions.js
intoObjectPreconditions.js
- User code should
require(ObjectPreconditions)
. Code involved in the circular dependency (e.g. subclasses) shouldrequire(AbstractObjectPreconditions)
.
Here is what the resulting code looks like:
define(["AbstractObjectPreconditions"], function(ObjectPreconditions)
{
console.log("Inside StringPreconditions");
function StringPreconditions() {}
StringPreconditions.prototype = Object.create(ObjectPreconditions.prototype);
StringPreconditions.prototype.constructor = ObjectPreconditions;
return StringPreconditions;
});
define(["require"], function(require)
{
console.log("Inside AbstractObjectPreconditions");
function ObjectPreconditions() {}
return ObjectPreconditions;
});
define(["AbstractObjectPreconditions"], function(ObjectPreconditions)
{
// Gatekeeper for circular dependencies
ObjectPreconditions.prototype.isInstanceOf(type)
{
console.log("ObjectPreconditions.isInstanceOf() invoked");
if (type === String)
return new StringPreconditions();
}
return ObjectPreconditions;
});
define(["ObjectPreconditions", "StringPreconditions"], function(ObjectPreconditions, StringPreconditions)
{
console.log("Inside Preconditions");
var Preconditions = {};
Preconditions.requireThat(parameter) = function()
{
return new ObjectPreconditions(parameter);
};
return Preconditions;
});
define(["Preconditions"], function(Preconditions)
{
console.log("Inside User code");
function User() {}
User.prototype.doSomething = function()
{
var StringPrecondition = Preconditions.requireThat("test").isInstanceOf(String);
}
});
Resolving circular dependencies for requireJS
is there a tool that will read through all my files (the .ts or the .js) and flag the places where I have circular dependencies?
Atom-TypeScript can do circular dependency analysis : https://github.com/TypeStrong/atom-typescript/blob/master/docs/dependency-view.md#circular
Also this looks interesting : https://www.npmjs.org/package/madge
Is there a way to handle this in requireJS
You get undefined initially but then you can require
again : http://requirejs.org/docs/api.html#circular
Is the answer to have the typescript compiler create a single .js file from all the .ts files? And if so, is there any downside to this approach, both when debugging and in production?
Yes --out
. -ves : slower compile times, must use sourcemaps for debugging. inability to lazy load parts of the codebase at production times.
Typescript + requirejs: How to handle circular dependencies?
Specify the type using what you get from import
i.e
import dataModelType = require("Modules/dataModel");
class MyClass {
dataModel: typeof dataModelType;
RequireJS, Circular Dependencies and Exports Magic Method
Edit: I couldn't find more info about the magic exports method. I could, however, mimic its intended behavior with a dummy "Container" module. See it in this fiddle: http://jsfiddle.net/amenadiel/a7thxz98/
console.log("start");
define("Container",function() {
var Container={};
return Container;
});
define("Employee", ["Container"], function(Container) {
var Employee= function(name) {
this.name = name;
this.company = new Container.Company(name + "'s own company");
};
Container.Employee = Employee;
});
define("Company", ["Container"], function(Container) {
var Company=function(name) {
this.name = name;
this.employees = [];
};
Company.prototype.addEmployee = function(name) {
var employee = new Container.Employee(name);
this.employees.push(employee);
employee.company = this;
};
Container.Company = Company;
});
define("main", ["Container","Employee","Company" ], function ( Container) {
var john = new Container.Employee("John");
var bigCorp = new Container.Company("Big Corp");
bigCorp.addEmployee("Mary");
console.log(bigCorp);
});
require(["main"]);
Requirejs and asynchronous & circular dependencies
Louis' answer was interesting but it just moved the problem creating a new module, and even if it placed the dependencies in the right context, I tried to search for some real asynchronous module definition (not just loading).
The best I could finally come up with was to edit the require.js source file to add the behaviour I expected. I registered a new handler (a special dependency behaviour like "require" or "exports" ) called "delay" that provided a callback function for the module definition :
basically, this works this way :
define(["delay"], function ( delay ) {
var Module = ... ;
setTimeout(function(){ //Some asynchronous actions
delay(Module) ; //This does actually returns the Module's value and triggers the "defined" event.
//It's actually transparent so the other modules just "feel" that the network's load time was a bit longer.
},1000);
return Module ; //This does not do anything because delay is active
});
Thanks to this asynchronous definition, I can now scan the directory (an asynchronous request) and then transparently load all the modules.
The modifications represents only about 10 lines so if someone is interested, I post it there :
https://github.com/jrburke/requirejs/pull/1078/files
Apparently it's not the first request for asynchronous exports but it's still in debate so I just use this for personal projects.
Related Topics
How to Replace the Entire HTML Node Using Jquery
Firebase Callable Function + Cors
How to Set Image Source with Base64
Map Isn't Showing on Google Maps JavaScript API V3 When Nested in a Div Tag
How to Get the Containing Form of an Input
When Should I Use a Semicolon After Curly Braces
How to Reverse an Array in JavaScript Without Using Libraries
Why Isn't This Object Being Passed by Reference When Assigning Something Else to It
Using Await Outside of an Async Function
Es6 Modules Implementation, How to Load a JSON File
Jquery Drop Down Menu Closing by Clicking Outside
Rotating Image/Marker Image on Google Map V3
How to Load Image Files with Webpack File-Loader
JavaScript Ie Detection, Why Not Use Simple Conditional Comments
Get Content of a Div Using JavaScript
Firing a Keyboard Event on Chrome
How to Use Blob Url, Mediasource or Other Methods to Play Concatenated Blobs of Media Fragments