A Simplified Universal Module Definition

There are several UMD ways to define a module with zero dependencies but I believe that's quite an overhead so here an alternative:

// please read next example too
// which seems to be better for AMD tools
(this.define || Object)(
this.exportName = exportValue
);
Update with a nice hint by @kentaromiura where the other side of define could be just a function and not a new function as initially proposed.
Another update suggested by @unscriptable that should not break AMD tools, neither CommonJS, neither global Rhino or window, still leaking a couple of properties that should be reserved for module stuff anyhow.

var
define = define || Object,
exports = this.exports || this // *
;
define(
exports.module = {}
);
Nice one, and if you are wondering why this.exports is needed, is because RingoJS apparently does not follow a de-facto standard as this as module exports is for other CommonJS implementations.

Even Better

If you don't want to pollute the scope at all:

(this.define || Object)(
(this.exports || this).module = {}
);
now all patterns in one for easy portability, cool?

What Is `this`

In node, this is always the exports object, if the module has been loaded through require, so this.name = value is not different from exports.name = value.
Outside node.js world, this will be the global object or any augmented environment or namespace if the file is loaded as text and evaluated a part.
This makes automatically the module mock ready.

Less Fairytales, Please

This trend to double check that define function has a truthy amd is hilarious. The whole purpose of going modules is to avoid global object pollution so, if you have in your code any script that create an insignificant define variable, function, or property, in the global scope, drop that jurassic script or rename that function in that script instead of check that property all over.
Also, please consider that a property could be part of any object so that check gives us nothing ... right? (but I wouldn't name a propety `amd` ... sure, as well as I wouldn't name a global function define ...)

A Basic Example


// what.js
(this.define || function(){})(
this.what = {
ever: function () {
console.log("Hello");
}
});

// node.js
var what = require('./what.js').what;
what.ever(); // Hello

// browser
<script src="what.js"></script>
<script>
what.ever(); // Hello
</script>

// AMD
require('what.js', function (what) {
what.ever(); // Hello
});
All this works with closures too, if necessary, so you don't pollute the global scope in non node environment.

(this.define || function(){})(
this.what = function(){
var Hello = "Hello";
return {
ever: function () {
console.log(Hello);
}
};
}(/* **INSTANTLY INVOKED** */));
As summary, if you want to create a tiny library, utility, module, and you don't have/want dependencies, this approach has a minimum overhead of 39 bytes without compression vs 158. Now multiply this per each file you have there and also try to remember my suggested approach, I bet you have it already ... now tell me the other with if/elses :P

But ... Global Scope Polluted With Define ?

I believe this is another fairytale. If you understand how AMD works you realize the moment you execute code in the closure the module is loaded correctly and passed as argument which means, basically, who cares what that argument outside that scope.
Said that, when it comes for globals name clashes possibilities are really low. The classic $ function or the _ one are two example but again, if you use AMD you receive the right argument while if you don't use AMD and you just inject script you do want that property in the global scope and again, if you don't use a module loader, it's your problem if you have both underscore and lodash in your global scope. Just drop one of them ... and enjoy this simplified UMD :)

Comments

Popular posts from this blog

8 Things you should not be afraid of as a Developer

News

Why REST is so important