Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

System JS load multiple dependencies in one call

Looking at the docs for systemjs I can not find an example of loading multiple dependencies at the same time. I would expect an api something like...

System.import(['jquery.js','underscore.js']).then(function($, _) {
    // ready to go with both jQuery and Underscore...
});

I would expect it to use promises to load all dependencies in parallel, and execute the callback once all are complete. Is this possible? If not, is there a reason why this functionality is not implemented?

like image 423
Billy Moon Avatar asked Mar 10 '14 02:03

Billy Moon


3 Answers

Possibly the shortest and DRYest way would be applying a [].map() to the System.import and then destructure its results:

Promise.all([
    'jquery',
    'underscore'
].map(url => System.import(url))).then(function ([$, _]) {
    // do stuff with results
});

Keep in mind that Destructuring still needs to be transpiled at the moment of writing this.

If you don't want to transpile you could write your own wrapper and spread script:

function spread(callback) {
    return function (args) {
        return callback.apply(undefined, args);
    }
}
function import(deps) {
    return Promise.all(deps.map(function (url) {return System.import(url);}));
}

and load it like:

import(['jquery', 'underscore']).then(spread(function ($, _) { /*...*/ }));
like image 102
kernel Avatar answered Nov 07 '22 19:11

kernel


This is possible with Promise.all:

Promise.all([
    System.import('jquery'),
    System.import('underscore')
]).then(function(modules) {
    var jquery = modules[0];
    var underscore = modules[1];
});

But it is ugly as you can see. There is talk of considering allowing an array like your example at the spec level, but it would need to be in the module spec since this is a spec loader.

The better alternative really is to only have one entry point for an application, app.js and then have that load dependencies.

like image 26
guybedford Avatar answered Nov 07 '22 19:11

guybedford


This is how i would do it, take it carrefully: it's not tested.

var SystemImport = System.import;
System.import = function (name, options) {
    if (Object.prototype.toString.call(name) !== '[object Array]')
        return SystemImport.apply(this, arguments);
    var self = this,
        imports = Promise.all(name.map(function (name) {
            return SystemImport.call(self, name); // should i pass options ?
        }));
    return {
        then: function (onfulfill, onreject) {
            return imports.then(function (dependencies) {
                return onfulfill.apply(null, dependencies);
            }, onreject);
        }
    };
};

This snippet will replace System.import with a wrapped version of itself allowing to use array of dependencies.

It returns a "thennable" object, this should work fine with any compliant promise implementation.

As the .spread method is not in the Promise A+ spec, this is the most spec compliant way I can think of...

like image 3
Adrien Gibrat Avatar answered Nov 07 '22 19:11

Adrien Gibrat