Working on the drag and drop form editor, I'm pulling in lots of modules: almost
everything in dijit.form, dojo.dnd (of course), and dijit.lang.functional &
dijit.lang.aspect because they're fun. Each module I require then pulls in
more files that it needs, so I was up to 131 web requests to load a single
page. The latency is acceptable on localhost, but it's absolutely terrible over
the network.
Pete Higgins has a couple of great screencasts over at dojocampus, but
it's kind of hard to refer back to a video, so here's my 5-minute build tutorial.
I'm assuming that your app code is in a directory next to dojo:
lib |-- dijit |-- dojo |-- dojox |-- mystuff `-- util
First, find all the dojo modules that you're pulling in. cd to the root of
your app and run:
This picks up all the dojo.require calls within your code and prints each one
out only once. The regex starts with \s* because I didn't want it finding
require's that I had commented out. I'm using ack, a replacement for grep that
uses perl regexes and is recursive by default. Using find and grep instead is
left as an exercise to the reader.
This prints the require's to the screen, but we want to put them all in a file for the
build system:
dojo.provide("includes.js");
`ack '^\s*(dojo.require[^;]*;)' -h --output='$1' | sort | uniq`
EOF
I'm calling the file 'includes.js', and starting it with
dojo.provide("includes.js"); It looks like this:
dojo.require("dijit.form.Button");
dojo.require("dijit.form.CheckBox");
...
Source the includes file from your html page:
This won't change anything right now, but it gets us prepared for later on.
Next we need to create a profile so the build system knows what to look for.
We'll call it my.profile.js:
layers: [
{
name: "../mystuff/includes.js",
dependencies: [
"mystuff.includes"
]
}
],
prefixes: [
[ "dijit", "../dijit" ],
[ "dojox", "../dojox" ],
[ "mystuff", "../mystuff" ]
]
}
We create one layer, with the name ../mystuff/includes.js. The path is relative to
the dojo directory, so the build system will put the compressed file in the same
place the includes file currently resides.
The only dependency for this layer is includes.js, which we created earlier.
It's full of more dojo.require dependencies that the build system will trace
for us.
The prefixes array tells the build system what directories we want to include
in our build version. These directories will be copied over to the build site.
You need to list any modules that you use, even if they're not directly
referenced in a layer. See the dojobook for more info.
Now we're ready to start building. cd to util/buildscripts, where you'll
find a bunch of different build scripts. We want to use build.sh. The
incantation is
cssOptimize=comments optimize=shrinkSafe
Give profileFile the correct path to the profile created above, and leave the
rest of the parameters as is. They tell the build system to crank the
optimizations up to 11, removing comments, newlines, spaces, and turning on
shrinkSafe.
After a bit of churning, you'll have a shiny compressed version ready to stream
over the wires. My transfer size was cut by 56% (down to 9 requests), reducing
browser latency and making my app much more responsive.

Hey, Great stuff. You should
Hey, Great stuff. You should consider writing some cookies over at DojoCampus like this: short, sweet, to the point. Otherwise, this will get lost in blog-aggregation forever! :)
Regards,
Peter Higgins
any idea how to get "ack" running on a mac ?
Macports dosen't seem, to know neither "ack" nor "p5-app-ack", but there are trails in their trac about this, so it must be anywhere there
regards
Roberto
ack on mac
I don't know about ports (and I'm not on a mac). I just get the standalone version and drop it in
~/bin, which is already on my path.make sure you on the latest MacPorts
try a
sudo port selfupdateto make sure you're on the latest MacPorts. I have ack installed from p5-app-ack via MacPorts, so I'm pretty sure it works...Ubuntu: package ack-grep
in case anyone is curious on Ubuntu the package and resulting command name is ack-grep
Neat approach! If you don't
Neat approach! If you don't want to bother with having to update mystuff.includes all the time, the build system is already capable of following dojo.require statements and turning one page into a fully-baked layer. For example, say you have mystuff.entrypage:
dojo.require("dijit.dijit");
dojo.require("mystuff.common")
You can specify entrypage as a layer in your build like this:
layers: [
{
name: "../mystuff/entrypage.js",
dependencies: [
"mystuff.entrypage"
]
}
],
prefixes: [
[ "dijit", "../dijit" ],
[ "dojox", "../dojox" ],
[ "mystuff", "../mystuff" ]
]
}
and mystuff/entrypage.js will be overwritten with it's contents prefixed with all of the necessary files pulled in via the dojo require system. You can add one new layer per page you have and reduce the number of js requests per page down to 2. If you have some stuff that's really commonly used within the app (say dijit.form, dojo.dnd, dijit.lang.functional and dijit.lang.aspect), you could put those things in mystuff.includes (or mystuff.common) and then make your page layer dependent on mystuff.includes:
layers: [
{
name: "../mystuff/includes.js",
dependencies: "mystuff.includes"
},
{
name: "../mystuff/entrypage.js",
dependencies: [
"mystuff.entrypage"
],
layerDependencies: [ "../mystuff/includes.js" ]
}
],
prefixes: [
[ "dijit", "../dijit" ],
[ "dojox", "../dojox" ],
[ "mystuff", "../mystuff" ]
]
}
That should reduce the number of js requests to three (one for dojo.js, one for mystuff/includes.js and one for mystuff/entrypage.js). If you really want to get fancy, you can redefine what dojo.js is to include your stuff in mystuff.includes and get back to two JS requests per page.
Need help
Hi,
Thanks for showing the right direction.I am completely new to Dojo Toolkit,so facing problems regarding Dojo Custom build.
I am using Dojo grid and the current js file i.e. dojo.xd.js(http://o.aolcdn.com/dojo/1.1.1/dojo/dojo.xd.js) file that refers to AOL CDN site(Dojo's file hosting site)
But for better performance,I want to do Custom build for my application.
I have tried your approach.
Let me explain what exactly I did for Dojo Custom build.
I have downloaded dojo-release-1.1.0-src.zip from the site http://download.dojotoolkit.org/release-1.1.0/
After extracting there are 4 folders...
dijit
dojo
dojox
util
Then I have created one folder "abhay" in \util\buildscripts directory and put all dojo.require statements as follows.
buildsuccess.js
dojo.provide("abhay.buildsuccess");
dojo.require("dojo.data.ItemFileReadStore");
dojo.require("dojo.data.ItemFileWriteStore");
dojo.require("dojox.grid.Grid");
dojo.require("dojox.grid._data.model");
dojo.require("dojo.parser");
dojo.require("dijit.form.ComboBox");
Then in \util\buildscripts\profiles directory I put my profile file i.e. test.profile.js.
test.profile.js
dependencies ={
layers: [
{
name: "dojo.js",
dependencies: [
"abhay.buildsuccess"
]
},
{
name: "../abhay/buildsuccess.js",
layerDependencies: [
"dojo.js"
],
dependencies: [
"dojo.data.ItemFileReadStore",
"dojo.data.ItemFileWriteStore",
"dojox.grid.Grid",
"dojox.grid._data.model",
"dojo.parser",
"dijit.form.ComboBox",
"dojo.data.util.filter",
"dojo.data.util.simpleFetch",
"dojo.date.stamp",
"dojox.grid.VirtualGrid",
"dojox.grid._data.editors",
"dojox.grid._data.fields",
"dijit.form.ValidationTextBox",
"dijit.form.nls.ComboBox",
"dojo.data.util.sorter",
"dojox.grid._grid.lib",
"dojox.grid._grid.scroller",
"dojox.grid._grid.view",
"dojox.grid._grid.views",
"dojox.grid._grid.layout",
"dojox.grid._grid.rows",
"dojox.grid._grid.focus",
"dojox.grid._grid.selection",
"dojox.grid._grid.edit",
"dojox.grid._grid.rowbar",
"dojox.grid._grid.publicEvents",
"dijit.form.TextBox",
"dijit.Tooltip",
"dijit.form.nls.validate",
"dijit._Widget",
"dijit._Templated",
"dojox.grid._grid.builder",
"dojox.grid._grid.cell",
"dijit.form._FormWidget",
"dijit._base",
"dojo.string",
"dojox.grid._grid.drag",
"dijit._base.focus",
"dijit._base.manager",
"dijit._base.place",
"dijit._base.popup",
"dijit._base.scroll",
"dijit._base.sniff",
"dijit._base.bidi",
"dijit._base.typematic",
"dijit._base.wai",
"dijit._base.window"
]
}
],
prefixes: [
[ "dojox", "../dojox" ],
[ "dijit", "../dijit" ],
[ "abhay", "../abhay" ]
]
};
Then running the following command from command prompt.
C:\dojo\dojo-release-1.1.0-src\dojo-release-1.1.0-src\util\buildscripts>build.ba
t profile=test action=release optimize=shrinkSafe
Build done successfully i.e in \release\dojo\abhay folder buildsuccess.js file created successfully. But when I tried to use that js file in my Dojo Grid,it complains dojo not defined.
So kind of you.Please help me to get rid off this problem.
One thing please also clarify as I have mentioned layerDependencies as dojo.js
so in prefixes I didn't include [ "dojo", "../dojo" ]
If I include [ "dojo", "../dojo" ] prefixes,then I got this error. Could not load 'dojo.i18n'; last tried
Please help me and let me know where exactly I am missing.
Thanks again in advance.
Thanks & Regards,
Abhay
Great!
Great!