Patching Dojo

February 4th, 2009 - by sfoster

There are many reasons you might end up needing to patch your Dojo source tree. Maintaining patches can be a pain, and sometimes outside of your control entirely. It could be a bug you’ve found, or something you really wish a Dojo component did/didn’t do, or you are having to work against an older release of Dojo, or there’s a patch in trac that fixes an issue you have, but it has not yet been committed. In this post, we’ll present a neat way to make the change, keep what you did explicit so other developers aren’t confused, and maintain it outside the Dojo source.

Here’s an example: Dojo 1.3 introduces dojo.create into Dojo Base – a new, handy API for creating DOM elements. But, if you’re already developing with a previous version of Dojo, it won’t be available to you until you upgrade to 1.3. You can create a shim to start using it immediately like this:

dojo.provide("yourns.patches.dojo.base");

if(dojo.version.major == 1 && dojo.version.minor < 3) {
        // a copy of dojo.create, from svn trunk’s dojo/_base/html.js
        // lots of useful doc comments snipped for brevity
        dojo.create = function(tag, attrs, refNode, pos) {
                var doc = d.doc;
                if(refNode){           
                        refNode = d.byId(refNode);
                        doc = refNode.ownerDocument;
                }
                if(d.isString(tag)){
                        tag = doc.createElement(tag);
                }
                if(attrs){ d.attr(tag, attrs); }
                if(refNode){ d.place(tag, refNode, pos); }
                return tag; // DomNode
        };
}

Now, to use it:

// if you’ve not already registered your namespace, do so…
dojo.registerModulePath("yourns", "../yourDirectory");

dojo.require("yourns.patches.dojo.base");

dojo.addOnLoad(function() {
  dojo.create("div", {innerHTML:"this worked"}, dojo.body());
});
 

The naming scheme here is:

  • yourns” – placeholder for whatever your namespace is.
  • patches” – a package/directory to contain all such patches. You might use the same directory to also keep static resources like CSS files that tweak/extend a Dojo CSS rule, or image. For this example, you’ll have created a file at ../yourDirectory/patches/dojo/base.js
  • dojo.base” – the name of the dojo module/method this patch impacts. To patch dijit.layout.BorderContainer you might call this “yourns.patches.dijit.layout.BorderContainer“, or, bundle up all your Dijit patches into “yourns.patches.dijit“. Though as a rule it is best to leave optimization to the build process and focus on clarity of intent and scope in your source. The goal here is to avoid “strange magic from a distance” by putting the change directly into the context in which it applies.

You can treat this like any other module in your build profile, just make sure you place it ahead of any code that relies on it being there. When you do upgrade, you can simply remove the patch, and the version check gives you a grace period to do so.

The Dojo Toolkit is just that – tools to help you produce better work, faster. The real world of web application development is a much more complicated place than most tutorials and code samples would like you to believe, and most projects throw you a curve ball at some point. Your toolkit should work with you at times like that, and this is just one technique that allows you to adapt gracefully and move on to the next problem to solve.

Bookmark and Share

Tags: ,

4 Responses to “Patching Dojo”

  1. mwilcox says:

    That’s an excellent idea Sam, I never thought of using Dojo’s versioning to prevent breaking future upgrades.

  2. Mark says:

    I like this too! So, in this example it was adding in a function from 1.3 back into 1.2. I am assuming I could also use this to apply a bug fix that is in 1.3 into the 1.2 version I am using now until 1.3 is officially released? In this case, the patch as described here would override the existing method with the bug in 1.2. (This fix would be in the Theme.js class.)

  3. Sam Foster says:

    @Mark
    Yes that will work. The only times this technique wont work immediately is when the function you are trying to patch is dependant on some environment values provided by a closure, or if the function itself is private and hidden via a closure.

  4. [...] gets the inlined templates, and the templateKey look-up works just as before. We could even monkey-patch this functionality into dijit._Templated and wring yet more goodness from the out-of-the-box Dijit [...]

Leave a Reply