Tuesday, April 25, 2006

Python-esque Imports in JavaScript

programming :: javascript :: web



Caveat 1: It has been several years since I've been forced to work with
JavaScript. Caveat 2: This has either been done before and considered
stupid or done before and done better. If so, I'm sure I'll hear about
it :-)

And before I get started, I've been meaning to blog about
MochiKit. I've got all sorts of good
things to say about it, but I'm so busy using it that I'm not sure I'll
ever get around to it. Among the many reasons that people rave about
MochiKit, let me say that the first and foremost should be what the
MochiKit team has done most for JavaScript: coding convention. Even
though there are lots of stylistic inconsistencies in the various
MochiKit libraries, compared to JavaScript in the wild, it is a
completely unified whole. Wild JavaScript is generally pure shite.

Back to the topic: the project I am working on right now has multiple
"screens" that are loaded depending on user interaction. Pretty common
fare. But I really didn't want to load all the DOM manipulation stuff
in a series of *.js files on page load. There are WAY to many files for
this. So I wrote importLibrary().

My first attempt at writing this function was to append script tags to
HEAD with the proper source information in it. Which works...
eventually -- the js source just isn't available immediately. So here's
what I did:


req = getXMLHttpRequest();
req.open('GET', file, false);
req.send('');
js = req.responseText;
eval(js);


Now, as far as I know, there is no reason to object to the "eval()"
call here, since this is just the same thing (again, as far as I know)
as when your browser downloads the file by itself. This filename is not
parsed from a URL or derived from any human input.

In addition, I wrote a little function for parsing the import
parameters so that


importLibrary('MyProject.ThisSection.ThisScreen')

maps to a file available at an arbitrary (pre-determined per-project)
location off of docroot on the web server.




The import itself has to be done synchronously to ensure that JS code
is available to everything after the called to import. Right now, I
have it doing simple checking to see if the js file has already been
imported, and if so, skips it. I would like to add some kind of "use
queue" as well, where most frequently clicked screens are bumped to the
top (or bottom), and those least visited are pushed off the queue and
then not maintained in HEAD.

This has really enabled me to organize the code for the project in a
sane way.



Now playing:
Glenn Gould - The Art of Fugue, BWV 1080: Contrapunctus IX (a 4, alla Duodecima)

2 comments:

Duncan McGreggor said...

Hey Paul,

I have looked at Dojo before, but it was much more than I needed. It really is time that I looked again, though... since I'm doing a lot more than I was before -- thanks! I've just spend about 30 minutes reviewing the docs for some of their really cool stuff like the AO connect() stuff and then some widgetry I might be able to use.

Do you know if they have an analog to JS code "imports"?

Duncan McGreggor said...

So, I've checked out the entire dojo project from svn and am digging through their source code. My first impression is that, like MochiKit, these guys are giving JS some much-needed support in the coding standards arena. As far as approach, though, I find that MochiKit's is more aethetically pleasing to me. I perceive he manner in which it is formatted as more explicit (and cleaner)... but that's really just personal preference. Regardless, dojo has done an awesome job.

As for the imports... they've got a require() function that changes depending on the hosted environment. (Since I just care about browsers for now, the browser env is the one I'm looking at.)

dojo.hostenv.loadModdule() is what is called when dojo.require() is called... yes, it looks like they are doing something very similar (path parsing, etc.)... then loadPath() is called, and that calls getText() which in turn calls getXmlhttpObject().

Bingo!

Thanks, Paul!

So, in fact, Dojo Toolkit is using this exact method! (Much more robust, of course.)