-
Notifications
You must be signed in to change notification settings - Fork 7
Circular dependency handling for dynamic execution #102
Comments
instantiateResult = {
deps: [],
exports: ['export'],
execute: function() {
return {
export: 'value'
};
}
}
Module({
get export() {
EnsureEvaluated(this);
return getEvaluationOutput(this)['export'];
}
})
Update - I'm mixing this up with ideas of deferred execution, apologies. This is unnecessary for CommonJS, we simply need to use an empty shell module that can be extended later on. Having |
I'm not understanding the problem yet. In the presence of cycles, an AMD or Node/Browserify shim should implement the |
NodeJS handles cycles by relying on the fact that require statements execute the modules at that point in the code (http://nodejs.org/api/modules.html#modules_cycles): If I write a.js: exports.export = 'export';
var b = require('b');
console.log(b.export == 'export'); b.js: var a = require('a');
console.log(a.export == 'export');
exports.export = 'export'; I would get two The AMD handles cycles by returning an undefined object when hitting a cycle. The AMD CommonJS form works similarly to NodeJS though I believe (http://requirejs.org/docs/api.html#circular). The above that I described doesn't cater to these cases at all unfortunately, I'm still trying to work out exactly what would be required here. Ultimately I think there are three levels of support one could provide:
{
deps: ['some', 'deps'],
exports: ['these', 'are', 'the', 'exports'],
execute: function(exports, normalizedNames) {
// we now support amending the exports object
exports.these = 'hello';
var circular = System.get(normalizedNames[0]);
exports.are = 'another';
// we build up the module sequentially, just like NodeJS does
// execute doesn't return the Module object, as the shell already exists.
} This would provide the full NodeJS compatibility. Note that the last option would also need to support deferred execution of dynamic modules, so they aren't executed during linking, only during |
i don't think that's quite the full story. for AMD, to support circular dependencies, you can request what @dherman describes sounds like a feasible option - the compatibility shim becomes responsible for generating the |
as a point of reference for using |
@dherman I'm trying to understand your suggestion. My assumption is that the dependencies are loaded in the execute function by a If we assume this is handled by the user code in the execute function, how would it know if a given dependency is a dynamic or declarative module though? Or even how would it know if we are in a circular scenario? For example, it can be useful to support allowing a CommonJS module to have The suggestion (3) I've made above would fully cover the circular execution scenario identical to NodeJS with the loader handling the creation of a module shell. |
It seems I have misinterpreted the instantiate function form here somewhat. I'm closing this, attempting the currently suggested method, and if necessary will post feedback elsewhere. |
I still don't see how this could possibly work. Can somebody explain how returning an execute function and a list of dependency names could handle circular dependencies? Thanks. |
John you are exactly right - it can't, and this was my confusion as well. The solution is for AMD and CommonJS module compatibility layers would handle their own module side table to allow circular registries. I'm adapting SystemJS at the moment to use this process, which will support circular references. I'll copy you in on the code when it's working if you're interested. |
Thanks, @guybedford. I was totally not expecting that we'd have to circumvent the ES6 loader! It seems unfortunate that we have to waste memory and cpu time to manage an ES5 side-loader, but I can see now that a few other issues we encountered will go away when we aren't trying to make the ES6 loader handle ES5-ish things. |
It is common for NodeJS modules to be created with circular dependencies.
I believe the assumption is that the first module will execute with a binding to the second before it has been populated. It has a lot of edge cases, but many modules are designed to work this way. See http://nodejs.org/api/modules.html#modules_cycles
The dynamic instantiation still hasn't been fleshed out from what I can see. If it is possible, this code should do the following:
For example, Browserify already caters for circular dependencies. So we have module authors creating node modules for the browser based on these principles.
It would be great to catch this for maximum compatibility.
The text was updated successfully, but these errors were encountered: