Setting up
Before you can use the JS.require() function, you need the following loaded
into the page:
JS.packages, the dependency manager- A list of dependencies
You can get JS.packages either by loading the package.js or loader.js
into your environment. (loader.js is package.js plus dependency data for
jsclass itself; if you just want to use JS.packages to manage your code
without using the rest of the jsclass library, use package.js.)
After loading the package manager, you need to tell it where to find your code.
The package manifest
To describe your packages, you list the external script files used by your application, stating which JavaScript objects are provided by the file and which objects it depends on. For example, here are a few modules from the JS.Class library:
JS.packages(function() { with(this) {
file(JSCLASS_PATH + '/core.js')
.provides('JS.Module',
'JS.Class',
'JS.Kernel');
file(JSCLASS_PATH + '/comparable.js')
.provides('JS.Comparable')
.requires('JS.Module');
file(JSCLASS_PATH + '/enumerable.js')
.provides('JS.Enumerable')
.requires('JS.Module',
'JS.Class');
file(JSCLASS_PATH + '/hash.js')
.provides('JS.Hash',
'JS.OrderedHash')
.requires('JS.Class',
'JS.Enumerable',
'JS.Comparable');
}});
Notice how Enumerable depends on Class and Module, which are both
provided by the same file, core.js. Similarly, Hash requires Enumerable
and Comparable, which both have a dependency on Module. The package
manager resolves all this and only loads each file once. Object detection is
used to figure out whether each file has been loaded and a file is not
requested unless some of its objects appear to be missing.
Where possible, the package system will attempt to load scripts in parallel
where it spots that execution order doesn’t matter. For example, Enumerable
and Comparable do not depend on each other, so when we want to load Hash
we can load these dependencies in parallel. If the load order of a set of
scripts is important, you must make sure you make this clear using the
requires() statement. A file will not be loaded until all the objects it
requires are present.
A package can also list multiple files. In this case, because JS.packages
doesn’t know anything about the relationships between the files, it cannot
automatically parallelize downloads and will just download them sequentially
when you call JS.require(). This is provided as a convenience for loading
libraries composed of multiple files, where listing their interdependencies is
more trouble than it’s worth and you’d rather specify the load order youself.
For example, to load the Fancybox library, you could do this:
JS.packages(function() { with(this) {
file( 'fancybox/lib/jquery-1.7.1.min.js',
'fancybox/source/jquery.fancybox.pack.js',
'fancybox/source/helpers/jquery.fancybox-buttons.js',
'fancybox/source/helpers/jquery.fancybox-thumbs.js')
.provides('jQuery.fancybox');
}});
In addition to requires(), there is a statement called uses() that
specifies a ‘soft dependency’, i.e. an object the package needs but that does
not necessarily need to be loaded first. For example, Set uses a
Hash for storage but you could load Hash after the Set
package just fine. On the other hand, Set mixes in
Enumerable and this must be loaded before Set is
defined. And, Hash is itself based on Enumerable. So the package config
for this looks like:
JS.packages(function() { with(this) {
file(JSCLASS_PATH + '/enumerable.js')
.provides('JS.Enumerable');
file(JSCLASS_PATH + '/hash.js')
.provides('JS.Hash')
.requires('JS.Enumerable');
file(JSCLASS_PATH + '/set.js')
.provides('JS.Set')
.requires('JS.Enumerable')
.uses('JS.Hash');
});
The advantage of using uses() is that it helps the package system optimise
the downloading of packages, since if the load order does not matter the
packages can be downloaded in parallel.