UMD: JavaScript modules that run anywhere

This is not about RequireJS, and ultimately has very little to do with it at all. I'm not here to discuss whether or not RequireJS is something you should be using for your JavaScript projects...that's really up to you. There are a lot of projects out there that use RequireJS, and there are a lot that don't.

With that disclaimer out of the way, I will say this about RequireJS...I've wrestled with it enough that it has had the positive side-effect of forcing me to figure out how to write my JavaScript modules in such a way that I can develop and test them without RequireJS, while still making them compatible for use in projects that use RequireJS without needing to shim it...and even elsewhere if/when necessary or helpful.

Universally compatible code

In the context of JavaScript, UMD stands for Universal Module Definition. I'm not even going to bother to attempt to write authoritatively on this subject, as others have already done so far more effectively than I could hope to. If you're really interested in understanding the ins-and-outs of UMD, just go read this fantastic article by Addy Osmani: Writing modular JavaScript.

What I will do here is describe how the learning the concept has helped me. Every once in a while in the context of work I end up writing some commonly used functionality multiple times, and it drives me to write a generic version of it that I can reuse again in the future.

Managing dependencies

Very commonly these modules have dependencies that they rely on (things like jQuery or underscore.js most often) that end up being referenced or imported. At first, I always ended up introducing RequireJS to handle importing these dependencies. Unfortunately, too often I ended up running into various hassles with RequireJS not wanting to play nicely with test execution from my build scripts. Ultimately what I always want to be able to do is have all of my spec tests run whenever either the code in the target module is changed, or my spec module is changed. I typically do this with Grunt watch combined with my test framework of choice for the project (whatever it might have been, most often either Mocha or Jasmine). I've had a lot of trouble getting this working, and nearly every time I try to figure out why, nearly everything I find ends up pointing to RequireJS being the problem child in the scenario (this is what I was referring to in my opening disclaimer).

Sigh...

So that's my long-winded explanation for how I got to the point where I decided that I needed to figure out how to write these modules in such a way that I could use them by just adding a global script reference to their dependencies, yet still make them compatible for us as an AMD module. After a bit of Googling, the clear solution seemed to be UMD. That was when I found this REALLY helpful collection of UMD examples on GitHub. That repository, along with Addy's article that I linked to above proved to be exactly what I needed.

Here's an example of how I applied it to one of my side projects.

In this case, I definitely wanted to be able to use this library with a simple script reference in a host page, and I could also definitely see it being used in an AMD environment, and also potentially in a node.js environment (CommonJS) as well, so I needed my UMD setup for this module to support all three of those scenarios. This library depended on both jQuery and underscore.js, so this is what the module wrapper ended up looking like:

(function (root, factory) {
    if (typeof define === "function" && define.amd) {
        define(["jquery", "underscore"], factory);
    } else if (typeof exports === "object") {
        module.exports = factory(require("jquery"), require("underscore"));
    } else {
        root.Requester = factory(root.$, root._);
    }
}(this, function ($, _) {
    // this is where I defined my module implementation

    var Requester = { // ... };

    return Requester;
}));

This module setup allowed me to setup a Mocha spec runner in an HTML file with simple script references for this module and its dependencies that runs without any problems at all both in the browser and from an automated Grunt build script as well. Additionally, it works seamlessly in a RequireJS app as well without any trouble.

Learning how to do this manually and understanding how it works and what it does proved to be a valuable experience for me. However, if you just want to get it done, there are some tools available that can help automate the process to achieve the same result. If that interests you, I recommend checking out uRequire, for which there is also a Grunt plugin as well. If you're using Grunt and prefer that route, there is also Grunt UMD as well.

If you're creating JavaScript modules with the intent of sharing them with the world (OSS, etc) then it would be very kind and generous of you, for the sake of the users of your library/module, to learn how to make your code universally compatible, if you're not already doing so.