Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RequireJS: Dynamic dependencies within nested require of a module

Suppose there is a function that returns an array containing dynamic dependencies. Then within a module B these dependencies are used. Another module A in turn uses module B.

A.js

define([B], function(moduleB){
    moduleB.m();
})

B.js:

define([ dep1, dep2 ], function( dep1, dep2 ) {

    var dyndeps = dep2.getDynDeps();
    var moduleB = {}

    require(dyndeps, function() {
        moduleB.m = function() { ... };
    })

    return moduleB;

});

The problem with this approach is, that the inner require is executed asynchronously, so the method m is not available in time.

like image 573
IARI Avatar asked Jan 10 '23 15:01

IARI


1 Answers

Since B.m is provided by a dynamic dependency, B should provide an interface for waiting on it to become available. There are a number of plugins to allow that, e.g. rq (using Q promises), promise (using jquery, Q, RSVP or ES6 promises), promiseme (self-contained?).

Using one of those, B would not return moduleB, but a promise. The nested require call would resolve the promise with complete moduleB. A would require <PLUGIN>!B. E.g. using promise and jquery:

// A.js
define(["promise!B"], function(moduleB){
    // B is complete now
    moduleB.m();
})

// B.js
define([ "dep1", "dep2", "jquery" ], function( dep1, dep2, $ ) {

    var dyndeps = dep2.getDynDeps();
    var moduleB = {};
    var loaded = new $.Deferred();

    require(dyndeps, function() {
        moduleB.m = function() { ... };
        loaded.resolve(moduleB);
    })

    return loaded.promise();    
});

The only remaining problem with this approach is that the client code (A.js) needs to know to depend on B in a special way. A better solution would be to have B hide its dynamic nature like:

// A.js
define(["B"], function(moduleB){
    moduleB.m();
})

// B.js
define([ "promise!dynamicB" ], function( moduleB ) {
    return moduleB;
});

// still inside B.js define a "private" named module:
define("dynamicB", ["dep1", "dep2", "jquery"], function() {
    var dyndeps = dep2.getDynDeps();
    var loaded = new $.Deferred();
    var moduleB = {};

    require(dyndeps, function() {
        moduleB.m = function() { ... };
        loaded.resolve(moduleB);
    })

    return loaded.promise();    
});

Now B can be used just as any other module.

like image 160
artm Avatar answered Jan 12 '23 08:01

artm