Last week, we announced Free Dojo Support to help Dojo developers with their ongoing development efforts and improve the way they were using Dojo.
Our First Question
Our first question comes from Dojo user Abdullah H. Al-Shaikh who asked:
I Have Been Working On Dojo For Quite Some Time Now… But I Can’t Put My Finger On The Proper Way To Start And Then Build A Stable Large Scale Dojo Project.
My Question Is What Is The Best Way To Start A Dojo Project?
I’m Looking For:
- Best Practices.
- Applying Modularity
- Prototyping vs. Closures.
Our Answer: It Depends
First things first, we must clearly emphasize a key point in web development:
There is no singular, “right” way to build a web application.
Thankfully, the Dojo Toolkit, gives you many options to optimize for the specific requirements of your application.
First, to limit the complexity of our answer, we’ll assume that you are:
- Familiar with Dojo (if you’re new to Dojo and coming from jQuery, we recommend our previous blog post “From jQuery to Large Applications”).
- Using the Dojo Build Tool to optimize performance (or would like to use it).
- Your application is single-page, or has sufficiently complex pages.
- Using Dojo 1.6.x.
The SitePen Approach to building web apps is pragmatic and we use the following guidelines and best practices.
Boilerplate File Structure
Every project should start with an organized file structure. To avoid a lot of thrashing and the interruptions that arise from reorganizing mid-development, start with a solid boilerplate. Depicted below is how we like to start our projects. You can create an empty file tree structure to match. Feel free to vary any of the ingredients to suit your specific application requirements, as each application is different.
Why this structure?
As developers, we like having cleanly structured code that’s easy to manage and maintain, but performance constrains us. For example, it’s ideal to have each logical segment of code be stored in a separate file, but delivering hundreds or even thousands of files to the web browser over HTTP will lead to significant performance problems.
The Dojo Build Tool allows you to work with and maintain a logical source code tree, yet deliver a fully-optimized application to your users. You’ll integrate the Dojo Build Tool into your staging and release process to manage this, and the boilerplate helps manage this by providing a source directory tree (
/src/static/dojo , etc.), and a release directory tree (
/release/ ) that are kept separate. When it comes time to build, the Dojo Build Tool will output an optimized and compressed copy of your code in the
/release/ directory. You only need to run the build when you’re ready to deploy your code and need an optimized release suitable for delivering on the web.
Adding Dojo to your Boilerplate
When building large applications you need complete access to all of the Dojo development tools and utilities. When setting up your boilerplate, you can either download a full release and decompress it into your boilerplate source tree, or you can include a checkout from our subversion source code repository.
We generally recommend a Dojo subversion checkout, using svn:externals because it has the added benefit allowing you to more easily move your application to a different branch or tagged version. If you don’t wish to go this route you can grab the full SDK version of the Dojo release and place it in your boilerplate. In either case your copy of the Dojo SDK should be placed in
src/static. For example, you would place
Notes: Although you could use the pre-built CDN releases hosted by Google and AOL, our experience is that sooner or later you’ll want to have those files available locally – for your custom build, or troubleshooting and checking the source, even if you rely on the CDN to host parts of your application.
Rebecca Murphey’s Dojo Scaffold is a similar effort to the boilerplate mentioned here. The structure is a little different, but also provides a valuable starting point.
Now that we have our source code tree in place, the next step is determining how to best setup and configure our application, and we do this with an application controller. When we build applications at SitePen, we typically start with an application control pattern that has been refined over the years from our experience building web apps.
You can think of this pattern as the glue that cleanly binds all the various pieces of our applications. It operates on the page level, to implement configuration and an explicit lifecycle over a loosely-coupled architecture for assembling single-page-applications of many moving parts. We find great benefit in application controllers for generally having more explicit control of each application, even for Dojo Mobile applications!
This topic alone is substantial, so we’ve created an entire tutorial on Dojo application controllers and defer to that resource to help you effectively manage the modularity of your application!
Modularity and Namespaces
dojo.provide statement at the top of each file, allows you to load it as just another dependency using
// contents of /src/static/yourns/Foo.js dojo.provide("yourns.Foo"); // ... contents of module
// contents of /src/static/yourns/Bar.js dojo.provide("yourns.Bar"); dojo.require("yourns.Foo"); // ... contents of module
Overall, Dojo works well with other toolkits. We’ve been careful not to break the work of others. But what happens when another toolkit does not play nicely with others?
One solution we’re involved with is helping define the CommonJS Asynchronous Module Definition (AMD) implementation that’s now beginning to be used in Dojo 1.6. It provides extreme flexibility for defining your modules, their dependencies, and more. Dojo 1.7 and beyond fully adopt the CommonJS AMD approach which will provide a lot more power and flexibility when released.
Prototyping vs. Closures
We use both prototypes and closures as the syntax for writing modules in Dojo. Closures provide ease of creating private methods and an easier to follow syntax, whereas prototypes are commonly used for modules where many instances are expected to be declared. For example,
dijit.form.Button uses the prototype model because there may be many buttons in a page and you’ll possibly have shared fields, whereas some of the encryption libraries in DojoX were deliberately created with closures (or self-executing functions) to prevent access to private variables.
Our blog post on Creating and Enhancing Dojo Classes the right way provides additional insight on this topic.
You now have a solid starting point for your Dojo application with a boilerplate, the Dojo SDK, an application controller, a module system, and an introduction to prototypes and closures.
In addition to using a Dojo build and optimizing your application for performance, another point of interest is the API documentation viewer. When using the full Dojo source tree, it’s possible to setup the API docs scripts from the outset, so you can see your API documentation as you comment your source code! This allows you to have an API viewer for your application code that works just like Dojo’s API Viewer. Documenting your code and using the API viewer will save you a lot of time in the future as your app begins to grow.
Lastly, you should always make sure you have tests for your modules! Dojo provides tests with every module and you can browse these tests in the Dojo SDK (look for the
test folders in each module directory). Starting with a stubbed out test suite for your application, a sample test or two makes it much easier to work testing into your development process. In practice you might have subdirectories which have their own tests directories, but its much easier to modify and copy existing files that are demonstrated to work.