Login Register

Creating Your Own Modules

Easy Way: A Dojo Peer Directory

So suppose you want to create your own module called explosive.space.Modulator. The most straightforward method involves creating dojoroot/explosive/space/Modulator. That way, "explosive" is at the same directory level as "dojo" and "dijit":

[criecke@smoochie js]$ ls
dijit  dojo  dojox  util
[criecke@smoochie js]$ mkdir --parents explosive/space
[criecke@smoochie js]$ ls
dijit  dojo  dojox  explosive  util

Now create the file "explosive/space/Modulator.js":

dojo.provide("explosive.space.Modulator");
dojo.declare("explosive.space.Modulator",null,{
    // fil in the body here
});

And you're ready to include it like any other Dojo module:

dojo.require("explosive.space.Modulator");
var eludiumFuel36 = new explosive.space.Modulator();

Sometimes instead of classes, you may want to define plain ol' functions in a module. That's fine too. For example: you could define explosive.space.utilities:

dojo.provide("explosive.space.utilities");
explosive.space.utilities.shuffleOverToCannon = function(steps) {
   // body here
}

Then, after the dojo.require, you can call explosive.space.utilities.shuffleOverToCannon().

Cleaner Way: External Directories

The problem with this approach is your mucking up the dojo root directory. It's better to keep your development separate from Dojo itself. It tends to make source control easier to deal with.

So let's say you put "explosive/space/Modulator.js" underneath private_dojo at the same level as Dojo root. Then you only need to add the registerModulePath statement:

dojo.registerModulePath("explosive","../../private_dojo/explosive");
dojo.require("explosive.space.Modulator");

The module path is specified relative to the /dojoroot/dojo directory.

Enterprise-Class Way: Custom Builds

An alternate method, which doesn't require the registerModulePath, is to have a build script (Ant, Makefile, or whatever) mix both Dojo and your custom stuff under the same root. That way your source code stays separate from Dojo's in development, but mixes together in a nice way for production. See Custom Builds for details.

Namespaces, dojo.require, dojo.provide, and dojo.declare

Unfortunately, there is a catch-22 in dojo for what convention to use when naming a module and its classes. Before I go into it, though, I'll explain what dojo.require(), dojo.provide(), and dojo.declare() actually do. Then I'll return to the convention problems surrounding what arguments -- namespaces, actually -- to pass them. That way, you'll be able to make an informed decision on how to handle the convention problem yourself.

Briefest of brief module overviews

A module is a .js file that contains many object functions, typically made with dojo.declare() (and often called dojo classes). The first line of a module file is a dojo.provide() call, whose argument corresponds to the module file's name. So dojo.provide("a.b.c.d") would typically mean the file was [dojo toolkit root]/a/b/c/d.js. (For more details, see the dojo book entry above.)

For a completely different .js file to have access to all the dojo classes in the module a.b.c.d, just put the dojo function dojo.require("a.b.c.d") into that file. (If you're a Java programmer, this is just like adding an import statement.)

Now let's turn to these three functions.

dojo.require()

When you put dojo.require("foo.bar.goo") in a .js file, it first checks a global hash (named d._loadedModule, if you're interested) to see if an object foo.bar.goo is inside.

If foo.bar.goo is already in the hash, dojo.require() simply returns it. It needn't have bothered; it might as well do nothing, as we'll see.

If foo.bar.goo isn't in the hash, dojo.require() figures out from namespaces what file "foo.bar.goo" refers to. Namespaces are too large a topic to cover here, so let's just assume the file is "/foo/bar/goo.js". Then dojo.require loads this file. In other words, it acts just like this code would:

<script type="text/javascript" src="/foo/bar/goo.js"></script>

Finally, to prevent itself from loading this file a second time, dojo.require sticks an object foo.bar.goo into the hash.

Actually, that's not *quite* true, and that brings us to dojo.provide.

dojo.provide()

In fact, it isn't really dojo.require() that sticks the object foo.bar.goo into the hash -- dojo.provide("foo.bar.goo"), the first line of goo.js, does it when dojo.require loads goo.js.

The important thing to realize is that dojo.provide does practically nothing. All it does is add "foo.bar.goo" to the hash d._loadedModule. Why? So that future dojo.require("foo.bar.goo") statements won't load goo.js twice. That's all dojo.provide() is good for! Really!

dojo.declare()

Which brings us to dojo.declare(). The file goo.js is a so-called dojo module. It has only one dojo.provide() statement (for reasons that should be obvious now), but it can have many dojo.declare() statements. Each dojo.declare() creates a so-called dojo class, a function object that you can create instances of with the Javascript "new" keyword. In other words, you do: dojo.declare("X", ..., ... ) so that you can later do: var myX = new X(...).

The first parameter of dojo.declare is typically not "X" though, it is a long namespace. dojo.declare("a.b.c.Mulch", ...) will create a global context function a.b.c.Mulch().

And here's the key point: The first parameter of dojo.declare() does not have to look anything like the parameter of dojo.provide(). dojo.provide makes a global context object that is used for almost nothing, as we just saw. The object functions made by dojo.declare have nothing to do with it. Nothing!

So a perfectly legal module in /a/b/c/d.js could look like:

// This is file /a/b/c/d.js
dojo.provide("a.b.c.d");
dojo.declare("gumby.Foo", ..., ... );
dojo.declare("z.y.x.Blah", ..., ... );

This will leave three global objects: a.b.c.d, gumby.Foo, and z.y.x.Blah, none of which refer to each other. They belong to the same module only in the sense that their source code is in the same module file, but that's it. Some of the module files in /dojox/grid look a bit like this.

Belaboring the point

Just to emphasize how unrelated dojo.provide and dojo.declare are to each other, consider what happens when dojo.require("a.b.c.d") runs for the first and second times in, say, files First.js and Second.js.

The first time, when First.js is loaded, all three global objects a.b.c.d, gumby.Foo, and z.y.x.Blah wil come into existence simply because dojo.require("a.b.c.d") loads the file d.js from directory /a/b/c.

The second time, because the object a.b.c.d already exists, dojo.require just returns it. Can Second.js still find the other two objects/classes gumby.Foo and z.y.x.Blah? Of course it can, because they are global objects too. They need have nothing to do with a.b.c.d to be found and used.

Contradictory conventions

That said, there is a dojo convention to "provide what you declare." In other words, the argument of dojo.provide() should be the argument of the first dojo.declare().

So this convention says we should do:

dojo.provide("a.b.c.foo");
dojo.declare("a.b.c.foo", .... );

That brings us to the catch 22.

Unfortunately, the dojo style guide (http://www.dojotoolkit.org/developer/StyleGuide#Quick_Reference) tells us that modules should all be lowercase, and classes should all be capitalized. That means we should instead be doing maybe:

dojo.provide("a.b.c.foo");
dojo.declare("a.b.c.foo.Foo", .... );
// or a.b.c.Foo?
// or like Java, a.b.c.foo.WhateverInCaps?

So we have two dojo conventions that contradict each other. What should you do? My answer: understand these three functions dojo.require, provide, and declare, and then adopt a consistent convention. Who am I to tell you what to do? There's a fair bit of inconsistency in Dojo itself here, as you will see once you start browsing around the code base.

A note on objects

Note that if both dojo.provide and dojo.declare use "a.b.c.foo", then they both end up producing the same object a.b.c.foo. Does this matter? Nope. Remember, dojo.provide just sticks its object in some hash as a flag, for dojo.require to check. Whether that object is a full-blooded, dojo.declare'd class, or just an empty shell, makes no difference to dojo.require -- or to dojo.

Note also that if you do dojo.provide("a.b.c.foo"), and all the dojo.declares in its module begin with "a.b.c.foo.", then all the dojo classes will be properties of the module - and mere flag - object that dojo.provide created, namely of a.b.c.foo. Is this good for anything? Nope. It creates more order and harmony in the universe, but that's about it. Dojo makes no use of this fact, and so you shouldn't either. Plenty of modules in the dojo code base do not do this.

My personal suggestion, which is not a formal Dojo one: do this anyway. Among other things, this makes it easy to see at a glance what dojo.require() goes with what dojoType attribute. (With the dojo grid, these seem barely related, for example.) And it looks a bit like how Java does imports. But that's just IMHO.