RequireJS

The Death of Module

A while back, I looked around at the Javascript module systems, and I didn’t like anything I found. Some used AJAX techniques to download and eval the whole thing, which seemed just a little too dynamic – among other things it messed up source code attribution for error messages and debugging. The other major technique was script tag insertion, but it wasn’t as popular. And of course, I just didn’t like the syntax most of them used. Many wrapped the entire file in a big function, which was more of a drastic intrusion than I wanted.

I worked on my own javascript module system. It used script tag insertion with a definition block, but that block only need to exist at the top of the file. I had a test suite for it that seemed to cover the basic cases, although I never did much browser testing or battle testing. Besides those two glaring issues, my rather imperative approach would have a required a full Javascript parser, if not interpreter, to tease out the dependencies for creating static single-file builds. That’s where I lost interest in the project.

RequireJS

Back when I was looking at existing systems, one of my favorites was RunJS. It used script tag insertion, and had a relatively clean syntax – except for the giant-function feature that appalled me. Still, when Module finally ran out of steam, I turned back to RunJS, and found it had been renamed to RequireJS – a name that I had seen come up once or twice, indicating it had some traction.

DefineJS?

One of the hiccups I ran into implementing RequireJS is that it’s namesake require method doesn’t actually work the way you want it to work. It’s pretty much a fully asynchronous ‘queue up these files to be loaded’. It doesn’t actually guarantee that those files are loaded before the current file is considered done – triggering it’s load function and any files depending on it. To get a full dependency graph, you have to replace require with define The net effect is that in RequireJS, you have defines all over the place, and few if any requires.

Encapsulation

I don’t mind using define so much – I was planning to convert to it over time anyway. The stated purpose of define is to create a proper module, which returns a value and thus may be installed into any local or global variable name, and perhaps instanced multiple times. I’ve started slowly bubbling up this process throughout the code. Some things are difficult – such as the basic Javascript extensions, which had to be broken up into separate files to maintain the module mapping (they were also big abusers of the publish pattern) Some of the more recent code was organized into more focused objects and ‘classes’ and these tend to convert over very easily, so perhaps I really was learning something during the whole process.

Sorry, I’ve Forgotten Your Name

RequireJS includes a static build tool, or I wouldn’t have pursued it. It doesn’t work entirely how I might like – it can build a single file, or process a whole directory. The whole-project things sounds nice, but it’s all or nothing – you get every file: tests, editor project file, documents, all the little javascript files you don’t need anymore, and the kitchen sink for good measure.

The other thing the build process does is minify the file. Among other features, this renames all variables to shorter arbitrary names. Sounds great, until your code breaks. I sometimes used this little pattern to take private symbols and make them part of a public object:

function publish(s) {
  CGD.JS[s] = eval(s);
}

Unfortunately, this gets called with the string name of the variable, so the compiler doesn’t rename it with the rest of the variables, and the eval fails.

Schizophrenia

The underlying project here is continuing the progress on Disk Clock 2. By this point I’ve mapped out the file and plugin dependencies and built configurations for each set. I’ve always been concerned that that the configurability of Disk Clock broke the complexity barrier for a dashboard widget. I now have a crude build system packing up the necessary set of script files with the other files to build out a series of separate widgets. I’ve been running two separate clocks on my own dashboard for some time; I suppose this is an especially heavy handed way to enforce my preferences. A big upside, however is, that without all the control real-esate taken up by the disk selector, there is room for any and all disk-specific configuration options without any dynamic shenanigans.

Posted Sunday, January 30th, 2011 under Devlog.

Comments are closed.