jQuery is a popular JavaScript library for many good reasons. It provides an excellent set of tools in a well-designed, compact file and is easy to learn due to great documentation. However, because of the focus on staying small and simple, jQuery doesn’t provide a significant infrastructure for building large scale applications. Rebecca Murphey‘s recent blog post brought a good amount of attention to the aspects of large scale development that aren’t addressed by jQuery alone. Since then she has continued to describe how Dojo provides the crucial building blocks for large applications. But switching toolkits may be a difficult, expensive endeavor, both for upgrading existing applications and for skill relearning for developers. Consequently, I wanted to look at how you and your team can start using Dojo without abandoning your investment in jQuery.

This post is intended to be a realistic conservative approach to building large applications, by leveraging Dojo infrastructure without throwing away existing code and mindshare based on jQuery. The best developers are the ones that know the right tool for a job, instead of trying to use the same tool for all solutions. jQuery’s sweet spot is in helping developers quickly get started with familiar CSS-esque syntax, while minimizing JavaScript code size. But it is important to recognize when Dojo’s infrastructure, designed for larger client-side applications, becomes a valuable tool.

This post is also intended to help point you towards some minimal effort ways to start leveraging different key components in Dojo to help build your applications. We recognize that learning new tools always has a time/effort cost, and instantly learning about everything in Dojo is unrealistic. Hopefully this post will point you to some tools within Dojo that you can quickly start utilizing and benefiting from. A jQuery application or team certainly does not need to use all of these, you can see which tools will help based on the growing pains of your application.

First…

The first step is including dojo.js in your HTML pages to load Dojo Base. Every subsequent component in the Dojo Toolkit depends on this critical functionality that is at the core of the infrastructure and consistency that Dojo provides. Dojo can easily be included by simply referencing one of the Content Distribution Networks scripts:


Or you can download Dojo and place it in your JavaScript directory structure as a sibling with jQuery and plugin JavaScript libraries. jquery+dojoSome of this functionality is similar to jQuery like DOM querying and manipulation, XHR, language utilities, but there are also additional features like module loading and asynchronous encapsulation that are unique.

Use Modules to Manage Dependencies

You can eliminate manual dependency tracking and begin to use Dojo’s module system. Properly handling different modules and their dependencies requires careful handling of script loads, timing issues, and proper ordering. With more than a handful of modules, handling dependencies by hand can quickly grow very tedious and error-prone. Dependency tracking generally tends to have an order of complexity of the square of the size of your application, since the number of points from which you need to list dependencies grows and the number of dependencies grows. Manually tracking this is very error prone, and as the size of your app grows this opportunity for errors multiples quickly.

Dojo’s module system is very easy to incorporate. You can add dojo.require and dojo.provide or define() calls to modularize your code and handle dependencies. You can even modularize existing scripts that are completely based on jQuery. For example:

dojo.provide("my.module");
dojo.require("load.this.first");
// the rest of your script:

You can also continue loading modules by standard script tags, and once dependencies are declared in modules, you can eliminate unnecessary dependency script tags whenever is convenient. This will also open up the door for intelligent “builds” down the road that can combine and minify files for greatly improved load times.

If you want better module integration with jQuery, you can now write your modules using the proposed CommonJS Asynchronous Module API which is also used by RequireJS. RequireJS has excellent jQuery integration, and is a fantastic module loader. This module API is gaining widespread adoption (also supported by Nodules and Yabble) and Dojo is refactoring its modules to utilize this module format. Since Dojo is utilizing this format in the upcoming 1.6 release (current version is 1.5), you can write modules for jQuery/RequireJS and Dojo without any incompatibility using this approach. RequireJS style modules can run on top of Dojo or RequireJS and Dojo modules itself will actually run on RequireJS as well.

Internationalization

We can begin to use Dojo’s internationalization infrastructure for applying locale-specific strings. To use internationalization, you setup a JSON file that defines a set of messages and then create translations of that file. You can then load the appropriate JSON file based on the current locale of the user:

dojo.requireLocalization("my-app", "messages");
var messages = dojo.i18n.getLocalization("my-app", "messages");

We can then use dojo.string.substitute to do a simple variable replacement in strings. To make this easier to use with jQuery, we can plug it in:

dojo.requireLocalization("my-app", "messages");
jQuery.fn.i18nize = function(){
  var messages = dojo.i18n.getLocalization("my-app", "messages");
  return this.each(function(){
    this.innerHTML = dojo.string.substitute(this.innerHTML, messages);
  });
};

Now we can easily apply internationalization to an HTML element:

$("#target").i18nize();

Where the target element has HTML with variables like:

${greeting}

And these variables can then be replaced with the appropriate locale specific messages defined in the JSON files.

Internalization is also baked into Dojo’s widget system, giving you a single simple infrastructure for internationalization that is already incorporated into all the widgets. Let’s look at widgets now.

Consistent Widgets

Of course there are numerous quality jQuery widgets available. Dojo provides an excellent set of widgets as well, but the big advantage to the Dojo widget system (Dijit) is the cohesive and integrated nature of these widgets. Dojo widgets were not developed in isolation; they were developed to work together consistently. Whereas numerous individual jQuery widgets work great on their own, using multiple ones from different developers can increase the mental load on developers when faced with differing naming conventions, events, look and feel, and data interaction. While jQuery UI does provide a set of more standardized widgets, with Dojo, there is a uniform data API, naming conventions and events, system-wide internationalization, accessibility, a unifying set of themes for consistent look and feel, and integrated layout handling for smart use of screen real estate coordinated between widgets. Having a complete set of unified attractive widgets without needing to worry about internationalization updates, and knowing accessibility standards are already met, greatly simplifies application construction.

Dojo has five themes currently available that style all 100+ Dijit widgets, and those themes are a standard for Dojo development. The Dijit theme tester provides a great look at the beautiful consistency that Dojo widget’s provide:
theme

Widgets are a big part of Dojo, and we can look at a few different aspects of leveraging them:

Apply a Dijit theme

To use Dojo widgets, you need to select a theme first. Including a theme is as simple as including the appropriate CSS file and adding the theme class to your top-level element (usually the <body>). Dojo themes are carefully namespaced, so you shouldn’t encounter any naming conflicts. Of course, you can also use the CSS classes yourself in your HTML, as well as override classes to tweak the look and feel (or completely rewrite a theme for your own look and feel). It is easy to extend and customize the themes for you own application.

Adding Dojo’s Dijits to your jQuery App

Let’s look at using Dojo’s widgets now. To make it easy to use Dojo widgets in a jQuery application, we can create a simple jQuery plugin to instantiate Dojo widgets in jQuery style. We first create the plugin adapter:

function dijitAsPlugin(Constructor){
  return function(args){
    return this.each(function(){
      new Constructor(args, this);
    });
  };
}
// and create a namespace for plugins:
jQuery.fn.dijit = {};

And now we can start registering widgets as plugins. For example, to register a Tree widget as a jQuery plugin:

dojo.require("dijit.Tree");
jQuery.fn.dijit.Tree = dijitAsPlugin(dijit.Tree);

And now we can create a tree with familiar syntax:

$("#tree").dijit.Tree({store: myDataStore});

Or you can learn the Dojo syntax if you prefer.

Using Layout

One common requirement for application-style sites is to control screen layout, intelligently distributing real estate based on the visible screen to maximize the visibility of key controls and information into various panes. Ideally this could be done completely with CSS, but CSS doesn’t provide sufficient capabilities for responsive height and width apportioning of the visible screen needed by many applications.

Dojo’s layout manager goes beyond the capabilities of CSS to properly size panes and handle page resizing. Proper layout often requires a complex combination of browser-specific CSS hacks and JavaScript interaction. The layout tools handle this so you don’t need to know all the hacks. This includes fluid layouts and window resizing enhancements. Dojo provides excellent tools for a wide variety of layout needs. The easiest way to integrate existing jQuery widgets within the layout is to simply use the ContentPane to contain HTML which can consist of any widget. For example, we could register BorderContainer and ContentPane to build a layout:

dojo.require("dijit.layout.BorderContainer");
dojo.require("dijit.layout.ContentPane");
jQuery.fn.dijit.BorderContainer = dijitAsPlugin(dijit.layout.BorderContainer);
jQuery.fn.dijit.ContentPane = dijitAsPlugin(dijit.layout.ContentPane);

And now we can build a layout:

var container = $("#container").dijit.BorderContainer();
container.addChild($("#left").dijit.ContentPane({region:"left"}));
container.addChild($("#center").dijit.ContentPane({region:"center"}));
container.addChild($("#right").dijit.ContentPane({region:"right"}));

Layout can be suboptimal without some level of coordination between components to properly resize in response to different page sizing. If you have jQuery components that can be resized, you may want to wire them to respond layout resizing. This is as simple as connecting to the resize() method and then delegating the new size measurements to the jQuery component:

var centerPane = $("#center").ContentPane({region:"center"})
dojo.connect(centerPane, "resize", function(newSize){
  MyjQueryComponent.setSize(newSize);
});

You’ll notice we used dojo.connect here to register our event handler. This is similar to jQuery’s bind function, but has the added capability of being able to uniformly connect to both DOM events as well as standard JavaScript methods (on any object, widget, etc).

Utilize Dojo Data

One of the common strategies for development of robust applications is using the principles of a model-view-controller (MVC) architecture. This architecture provides separation of concerns between UI and data in a way that allows for modularity and independent evolution of your components without tight coupling. True web application development is much more than manipulating DOM nodes, and Dojo Data lets us separate unrelated DOM nodes and data entities. The Dojo Data API is a resource oriented programming approach that provides a uniform interface for data access. You can start using Dojo Data stores to access your data, and then later easily connect data-powered widgets to these data stores.

The modularity that Dojo Data provides makes it easy to put the pieces of your application together. For example, we could use Dojo’s JsonRestStore to interact with server using a REST interface, and encapsulating this interaction. We can then plug the store into a widget very easily now:

var store = new dojox.data.JsonRestStore({ target: "data" });
grid = new dojox.grid.DataGrid({
   store: store,
   // other options on the grid
});

The standard interface makes it easy for the grid to query the store and show the results, complete with automated virtual paging (new queries are generated as you scroll down). The grid also will automatically respond to any changes in data through the standard notification API. This is automatically handled by the grid to store interface. We can even edit directly in the grid, and the grid will send the changes to the store, to be delivered to the server for us.

Integrating with the Server

Web applications are more than just a client-side interaction, they must effectively integrate client code with the server-side interaction. Dojo Data provides great tools for comprehensive integration. While the jQuery Ajax APIs are certainly sufficient for communication with a server, Dojo’s REST module goes further and provides a complete foundation for standards-based REST communication that fully integrates with the Data interface. RESTful interaction can therefore be consistently handled in the same way as other data sources without custom coding for each HTTP request.

Make it Fast!

By far the biggest bottlenecks for most web applications is network communication and latency. The more requests your application needs to make to load, the longer the load time. As your application grows, naturally you often start including more scripts, loading more configuration information or templating HTML, which can often add up to a very slow application by the time you are done. Dojo’s build tools help solve this problem, by giving you a one-step process for shrinking JavaScript files, combining all our JS files together (using the module dependencies), combining CSS files, and even inlining config strings and templates directly into JS files, so that you application can load with just a few requests.

Creating your custom build for your application can be very easy. With Dojo 1.6′s new support for HTML parsing, we can run a build by simply pointing to an HTML file that loads an entry module (or modules) that load all other dependencies, and a build is automatically generated for you:

build htmlFiles=path/to/page.html action=release

There are numerous other options for how to run builds in the build documentation.

Because Dojo uses a true module system, the build can create a single file that gives you only the bytes you really need. This is becoming increasingly important as we build applications for bandwidth constrained mobile devices. jQuery alone is not modular. When dealing with manual script tracking, it is too easy for functionality to be duplicated across many plugins. With a module system, a module only gets loaded once, and truly optimal builds are easy to achieve. Again, RequireJS is another option for getting started with modules (RequireJS has a build system as well), and provides a smooth transition to modular development, and inclusion of Dojo modules.

Remember, you can use your existing jQuery scripts and create modules and define dependencies with them for fast, highly automated builds. Using a build process is also important for maintaining an environment for developers where they can pursue intelligent modularization and code practices (with comments and clarity) without worrying that it will result in numerous requests and excessive script size. If you notice that you, or fellow developers, are writing excessively terse code or trying to stuff everything into a single script because of worries about the download times, it is time to start using Dojo modules and the build.

Asynchronous Encapsulation

Asynchronicity is a big part of web applications, particularly as you start relying more on Ajax techniques to interact with the server. However, without intentional forethought, asynchronous programming often leads to extremely complex and fragile code with poor interfaces making it very difficult to manage and reuse. This problem has received significant computer science research and the solution is in the form of promises, entities that encapsulate the eventual asynchronous completion of a computation. By using promises, asynchronous-based functions can be called without callbacks, preserving natural function signatures, and returning promises. The callbacks are then registered on these returned promises, properly separating the concerns of the call from the concerns of time and asynchronicity. Dojo provides an implementation of promises with the dojo.Deferred constructor, that makes it easy to write more robust and manageable asynchronous code. This was recently improved for Dojo 1.5.

Dojo’s Ajax/XHR capabilities are already based on promises and provide a powerful API for for communicating with the server:

dojo.xhrGet({url:"some-resource"}).then(function(content){
  // use the content once it is loaded
});

Other Awesome Tools

Dojo’s extension repository (called DojoX, like plugins for Dojo) includes numerous other awesome modules that can be invaluable for different applications. Here are just a few of many:

  • dojo.declare – A robust class emulation system, complete with super calls, multiple inheritance, and namespace creation
  • dojo.publish – Dojo provides a publish/subscribe system for wiring up your application with loose coupling.
  • Dojo array utilities – Cross-platform array utilities based on JavaScript 1.7 and 1.8 array methods (forEach, filter, indexOf, etc)
  • dojox.gfx – Comprehensive graphics library that abstracts away the differences between different browser rendering engines (SVG, Canvas, VML, etc.).
  • dojox.charting – Beautiful charts with events, theming, numerous chart types, all built on dojox.gfx for cross-browser support.
  • dojox.grid – A multi-purpose data grid, the workhorse of numerous data intense web applications. The grid has numerous features including sorting, virtual paging, column reordering, complex column and row grouping, selection, in-context editing, and more.
  • Language utilities like dojo.partial for partial application of arguments.

Conservative Transitioning

I have intentionally avoided the approach of switching from jQuery APIs to Dojo APIs for functionality that jQuery already provides. Simply switching APIs obviously isn’t going to improve your application, and can be a time-consuming and costly effort. The main benefit would be to reduce the number of libraries that you are loading on your page, so you are only using dojo.js. For large applications, the size of jQuery.js is generally not very signficant, and so the motivation to do this may be low. If you really do want to eliminate jQuery at some point, you might want to consider using plugd (see the project page for examples), which provides a similiar API to jQuery as an interface to dojo.js, and can reduce the effort in switching to Dojo by preserving the brevity of jQuery style interaction, but removing jQuery is not the point of this post.

This post is not intending to suggest that if you are starting from scratch, that you should combine as many libraries as possible. A library like Dojo will provide you most everything you need, and combining libraries for no reason will just add unnecessarily bloat and complexity. These suggestions are targeted for development teams that have already invested in jQuery, and realize that they can benefit from a scalable infrastructure, but don’t want to abandon their investment. Good developers recognize when it is time to utilize tools that will make application development manageable and scalable down the road. If you are benefiting from jQuery, but want a more complete infrastructure, let jQuery and Dojo complement each other, and enjoy the power of both!