Question

I just took a shot at wrapping one of our modules that is meant to be included via a <script> tag in some boilerplate to allow optional AMD loading with requirejs.

It was quite painful and the best I could come up with is:

(function(){
var exports, jQuery;
if (typeof window.define === 'function' && typeof window.requirejs === 'function') {
    exports     = {};
    define(['jquery'], function (jq) {
        jQuery = jq;
        return thisModule();
    });
} else {
    exports     = window;
    jQuery      = window.jQuery;
    thisModule();
}


function thisModule() {
}

})();

Notice that this is

  • A LOT of boilerplate
  • Requires you to declare dependencies in variables (only jQuery in this case thankfully) AND amd
  • Needs yet more code if I want to have CommonJs support.

I am primarily concerned about the second point as that one is going to be a doozy when I get beyond wrapping our core files. I'm sure there's some neat(er) wrapper implementations out there but I can't find any.

Anyone have any tips?

Was it helpful?

Solution

What you are trying to re-create something that already exists, I did exactly the same thing, coming up with a slightly different solution in my StackOverflow question.

To cut a long story short the name you need to know is "Universal Module Definition" and there's a GitHub located at https://github.com/umdjs/umd with a variety of different implementations.

OTHER TIPS

Are you trying to do this for an internal module, or an external module?

If you're not require-ing in additional modules, would it be possible to build your modules assuming AMD, and then just shim out the define() function somewhere else in your code, if it's not there? Of course, you'll have to use named modules, but you'd have to basically do that anyway...

If your modules all return their exports from the define() function, it would be relatively simple, and your shimmed define function could look something like this:

//Whatever additional guards you want could be added, of course...
if (typeof(window.define) === undefined){
  window.define = function(name, deps, callback){
    window.myNamespace[name] = callback();
  };
}

At least that way you wouldn't have to add the boilerplate to every module...

If you've got a larger library with lots of interdependent sub-modules, you're probably just going to have to commit to using Require all the way, or not, and then use your wrapper code around your whole library to handle AMD support, the way Jquery and Knockout JS do it.

After hacking on this I managed to come up with the following which seems significantly better and could even be included as a shim in a regular script tag:

A couple notes and drawbacks.

  • You have to replace any explicit setting on the window object with the exports object
  • It assumes that any dependency exists as a similarly named property on the window object (though it also makes sure to place that property there). This is generally safe enough in my case but you could easily hack in something like the requirejs paths configuration.
  • Actually I'm not convinced that the entire exports concept is particularly necessary, or at least not necessary in all cases.
(function () {
    var define, exports = {};
    if (window.define && window.define.amd) {
        define = window.define;
    } else {
        exports = window;
        define = function (name, dependencies, fn) {
            var deps = [];
            for (var i = 0; i < dependencies.length; i++)
                deps.push(window[dependencies[i]]);
            var module = fn.apply(undefined, deps);
            if (!window[name]) window[name] = module;
        };
    }

    define('mylib.interaction', ['jQuery', 'mylib.core', 'jQuery.UI'], function($, mylib) {
        return /*....blah...*/;
    })
})()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top