Cixar

XML/RSS

Categories:

/ (117)
  art/ (4)
    tale/ (1)
  bookmark/ (2)
  langlubber/ (4)
  movies/ (2)
  music/ (1)
    garageband/ (2)
  photo/ (1)
  politics/ (1)
  program/ (28)
    cli/ (1)
    javascript/ (13)
      chiron/ (5)
    python/ (6)
    swil/ (2)
    tale/ (22)
  reading/ (4)
  tale/ (24)
  writing/ (2)

Archives:

2008-Oct
2008-Sep
2008-Aug
2008-May
2008-Apr
2008-Mar
2008-Feb
2008-Jan
2007-Jun
2007-May
2007-Apr
2007-Mar
2007-Feb
2007-Jan
2006-Oct
2006-Sep
2006-Aug
2006-Jun
2006-May
2006-Apr
2006-Mar
2006-Feb
2006-Jan
2005-Dec
2005-Nov
2005-Oct
2005-Sep
2005-Aug
2005-Jul
2005-Jun
2005-May
2005-Apr
2005-Mar


The Sourcerer

by Kris Kowal.

Wed, 14 Mar 2007

Javascript Module Loader

I had an epiphany when writing a module loader. The trouble is that I didn't want modules to have access or ability to mess with the module loader's local variables. Since I was just calling eval with the text of the module, it had all of this access for reading and writing. Since I don't trust even myself, this was not acceptable. The problem was finding a way to sweep all the names under the carpet.

Here's the trivial solution:

(function () {
	/* module loader */
	this.require = function (url) {
		var require = function (url) {
			/* this require is for the module */
		};
		var text = http.requestText(url);
		eval(text);
	}
})();

Here's a less naive solution:

var evalModule = function (text, require) {
	eval(text);
};
(function () {
	this.require = function (url) {
		var text = http.requestText(url);
		var require = function (url) {};
		evalModule(text, require);
	};
})()

That solution still leaves evalModule as a variable that the module could potentially supplant. I needed to isolate evalModule. My solution uses a member variable of a jail object which eventually gets populated with the evalModule function without giving the closure access to either jail or itself..

(function () {
	var jail = {};
	this.require = function (url) {
		var text = http.requestText(url);
		var require = function (url) {};
		evalModule(text, require);
	};
	return jail;
})().evalModule = function (text, require) {
	eval(text);
}

Of course, it's not enough to isolate the module in a closure. I also give it a Module object as its context object.

(function () {
	var jail = {};
	this.require = function (url) {
		var text = http.requestText(url);
		var require = function (url) {};
		var module = new Module(url);
		evalModule.call(module, text, require);
	};
	return jail;
})().evalModule = function (text, require) {
	eval(text);
}

So, modules look like this:

var module = this;
assert(this != window);
with (require('module.js')) {
	/* go do stuff without fear of name collisions */
}
this entry was posted on Wed, 14 Mar 2007 at 21:48 in