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.