Monday, February 1, 2010

CommonJS - Why Server Side Only?

There is one single thing I don't like about CommonJS Idea, the fact nobody is thinking about the client side!!!

CommonJS Why

Since everybody would like to use JavaScript as Server Side Programing Language, where right now I can count there about 50 implementations, somebody decided that at least basic stuff such IO operations, streams or sockets, and much more, should have a common behavior, namespace, API, across all different implementations.
In few words, these guys are trying to create their own WSW Consortium, and this is absolutely OK.
So what am I complaining about?

Client CommonJS

If we, as developers and libraries authors, would have adopted a similar strategy ages ago, rather than fight with each other about natives prototypes pollutions, web development would be probably even easier for everybody.
We failed, while those server side guys started correctly.
The problem, for both language usage and its environment, is that JavaScript on server has different problems than a bloody "attachEvent VS addEventListener" but while common practices are in any case appreciated and widely adopted world wide, CommonJS is not friendly at all with Client Side JavaScript.
The basic example?

require

This function aim is to retrieve from a namespace, where it is basically represented via dot notation, translated into folders paths, a generic variable, object, function, whatever.
The power a dedicated build could have over ouw miserable secured/sandboxed version of browser JavaScript engines is endless.
As example, the only way I could think about to implement a client side require, is this one:

if (typeof require === "undefined") {
// (C) WebReflection - Mit Style License
var require = (function (context, root, Function) {
function require(namespace) {
if (!hasOwnProperty.call(cache, namespace)) {
var xhr = new XMLHttpRequest;
xhr.open("GET", (root + "." + namespace.replace(/(^.*)(?:\.[0-9A-Za-z$_]+)$/, "$1")).replace(/\./g, "/") + ".js", false);
xhr.send(null);
cache[namespace] = Function(xhr.responseText + ";return function(){return eval(arguments[0])};").call(context);
}
return /(?:^.*\.|^)([0-9A-Za-z$_]+)$/.test(namespace) && cache[namespace](RegExp.$1);
};
var XMLHttpRequest = this.XMLHttpRequest || function () {
return new ActiveXObject("Microsoft.XMLHTTP");
};
var cache = {};
var hasOwnProperty = cache.hasOwnProperty;
return require;
})(this, "", this.Function);
}


How It Works

Let's say we have a file called mylib.js and let's say this file contains our libraries variables.
To obtain the base object, we could simply do something like this:

<script src="require.js"></script>
<script>
var base = require("mylib.base");
base.alert("hello");

var $alert = require("mylib.base").alert;
$alert("world");
</script>

Where mylib.js file is nothing different from:

var base = (function () {
var self = this;
return {
alert:function (msg) {
self.alert(msg);
}
};
}).call(this);

Easy? In few words if a file contains proper variable declarations, rather than global myvar = {} without var prefix, we can imagine we could have all our libraries automatically "sandboxed", at least the global namespace won't be polluted that much and via my implementation of require, each file will be loaded simply once and never again, and we can retrieve step after step just what we need.

P.S. please note that my implementation is just an imperfect proof of concept since require in CommonJS accepts syntax like require("mylib").base; but untile we won't have runtime cross browser resolved get/set, this is not possible to implement synchronously :(

No comments:

Post a Comment