Interning Strings Everywhere in your Dojo Build

Dojo has a build system that does a lot of neat stuff. Let’s investigate.

The Dojo Book explains it well:

A Dojo custom build speeds performance by doing the following:

  1. First, it groups together modules into layers. A layer, which is one big .js file, loads faster than the individual .js modules that comprise it
  2. Second, it interns external non-JavaScript files. This is most important for Dijit templates, which are kept in a separate HTML file. Interning pulls the entire file in and assigns it to a string.
  3. Third, it smooshes the layer down with ShrinkSafe. ShrinkSafe removes unneeded whitepsace and comments, and compacts variable names down to smaller ones. This file downloads and parses faster than the original.

You’ll see in the second point that the Dojo build system can “intern” external files. This is great when writing widgets, but you might start wishing that you could do the same sort of thing elsewhere in your code. I’ll quickly go over one of the main patterns that the build system uses to do this interning and, once we know how it works, we can write a quick function that will allow us to use external strings throughout our code in ways that ensure interning happens once we build and deploy our code.

One of the best forms of declaring an external resource is the same one that you use to specify where a template lives in a Dijit widget. It looks like this:

templatePath: dojo.moduleUrl("yourmodule.strings", "hello.html")

What happens to Dijit widgets that use this syntax? Without using a build, if you open up your debugger of choice and watch the server requests your page makes, you’ll see these template files being loaded from the server. But after you use a build, these requests go away. What happened?

Before the build, the templatePath attribute was just a pointer to the hello.html file in the strings directory of your module. When creating a build, the build tool looks for this combination of attribute name and dojo.moduleUrl call, replacing it with this:

templateString: "The actual text text from hello.html"

Knowing this, we can write a utility function that will automatically handle these two forms transparently. In our code, we’ll be able to use it like this:

var string = intern({templatePath: dojo.moduleUrl("yourmodule.strings", "hello.html")});

After the build system runs, it will look through your code, find this pattern, and replace the code in the same way we noted above. When the build system has finished running, your original code will now look like this:

var string = intern({templateString: "The actual text from hello.html"});

It should be obvious that what this function will have to do. It will have to load our file synchronously if it finds a templatePath (before the build) or return the string if it finds a templateString (after the build). Let’s write it!

function intern(obj){
  if(obj.templatePath){
    var string;
    dojo.xhrGet({
      url: obj.templatePath,
      sync: true,
      load: function(data){
        string = data;
      }
    });
    return string;
  }else{
    return obj.templateString;
  }
}

Hopefully you’ll figure out some places in your own code where this will speed things up. Have fun with it!

Tags: ,