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:
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.
Outside node.js world,
This makes automatically the module mock ready.
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
Said that, when it comes for globals name clashes possibilities are really low. The classic
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.
// please read next example too
// which seems to be better for AMD tools
(this.define || Object)(
this.exportName = exportValue
);
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.
Nice one, and if you are wondering why
var
define = define || Object,
exports = this.exports || this // *
;
define(
exports.module = {}
);
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:now all patterns in one for easy portability, cool?
(this.define || Object)(
(this.exports || this).module = {}
);
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 thatdefine
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
All this works with closures too, if necessary, so you don't pollute the global scope in non node environment.
// 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
});
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
(this.define || function(){})(
this.what = function(){
var Hello = "Hello";
return {
ever: function () {
console.log(Hello);
}
};
}(/* **INSTANTLY INVOKED** */));
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
Post a Comment