Login Register

5-minute Custom Build

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:

ack '^\s*(dojo.require[^;]*;)' -h --output='$1' | sort | uniq

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:

cat <<EOF > includes.js
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.provide("include.js");
dojo.require("dijit.form.Button");
dojo.require("dijit.form.CheckBox");
...

Source the includes file from your html page:

<script type="text/javascript" src="includes.js"></script>

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:

dependencies = {
    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

./build.sh profileFile=/path/to/my.profile.js action=release \
           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 selfupdate to 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

sudo apt-get install 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.provide("mystuff.entrypage");

dojo.require("dijit.dijit");
dojo.require("mystuff.common")

You can specify entrypage as a layer in your build like this:

dependencies = {
    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:

dependencies = {
    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

Oh I forgot to mention I'm

Oh I forgot to mention I'm trying to get this working under a normal (i.e. not adminstrator) account under Windows.

Not sure if that could cause a problem somehow? And just in case it's of any importance I'm running on Windows XP Prof. SP2.

Thanks,
Peter

Great!

Great!

RE: Need Help

Hello,

Have you managed to fix that problem yet? I have downloaded this version and I'm having the exact same problem. Any help would be greatly appreciated.

Thanks in advance,
Peter

Peter, are you trying to use

Peter, are you trying to use the Grid like the previous person? It would be good to know your build profile. I guess I missed this thread earlier, so I have not tried the previous person's build profile yet, but it would be good to confirm with your build profile.