All development for curl.js and cram.js has stopped. For the foreseeable future, we will continue to respond to issues on github, as well as in the #cujojs room on freenode. However, keep in mind that there will be no further development, so some issues might not be resolved fully.
Also, if you are interested in becoming the lead maintainer of curl.js and/or cram.js, please let us know on #cujojs!
curl.js is a small and very fast AMD-compliant asynchronous loader. Size: ~4KB (gzipped) using Google's Closure Compiler.
If you'd like to use curl.js for non-AMD modules (ordinary javascript files), you'll want to use the legacy loader.
curl.js, like all async loaders, cannot circumvent browsers' security
restrictions when using the file: protocol. Therefore, you must use
curl from a page served from a web server (i.e. using http: or https:).
Trying to run curl.js from a page loaded from your local file system
will not work correctly in all browsers.
What the heck is "cujoJS"? cujoJS is the JavaScript Architectural Toolkit. More info: cujojs.com
What is "cram"? cram (cujoJS resource assembler) is the build tool companion to curl.js. You use cram to compile all of your modules into a small number of javascript files which are loaded much faster into the browsers.
define())More detailed information below and on the wiki.
It's that easy.
Got more in-depth questions? Browse the cujoJS discussion group or come chat with us on freenode @ #cujojs.
See the wiki for information about using curl.js with jQuery, dojo, or underscore.
define is undefined when wrapping cjs/node modules.bin/make-all.sh.define from cram parser.At it's core, curl.js provides an AMD environment:
define(['dep1', 'dep2', 'dep3' /* etc */], factory);
define(['dep1', 'dep2', 'dep3' /* etc */], module);
define(module);
define(name, ['dep1', 'dep2', 'dep3' /* etc */], factory);
define(name, ['dep1', 'dep2', 'dep3' /* etc */], module);
define(name, module);
These all define a module per the AMD specification.
define(function (require, exports, module) {
var dep1 = require('app/foo');
exports.foo2 = function () { return foo() + 2; };
});
Defines a module using the AMD-wrapped-CommonJS format. If a factory function
has parameters, but the dependency list is missing, this format is assumed.
The exports and module parameters are optional, but when specified, must
be in this exact order.
define(function (require) {
var dep1 = require('app/foo');
return function () { return foo() + 2; };
});
Another variation on AMD-wrapped-CommonJS that uses require() in the
tidy CommonJS manner, but returns the exports as per typical AMD.
define(['require', 'exports', 'module'], function (require, exports, module) {
var dep1 = require('app/foo');
exports.foo2 = function () { return foo() + 2; };
});
Another way to gain access to the CommonJS-like variables, require,
exports, module. When specified in the dependency list, these
"pseudo-modules" are provided as arguments to the factory function.
var dep1 = require('app/foo');
exports.foo2 = function () { return foo() + 2; };
curl.js also supports unwrapped CommonJS modules (and node.js modules) via the cjsm11 module loader. To use this module loader for a package, say Backbone, you would provide it to a package config, like this:
curl.config({
packages: [
{
name: 'backbone',
location: 'bower_components/backbone',
main: 'backbone.min.js',
config: { moduleLoader: 'curl/loader/cjsm11' } /* <-- hey! */
}
]
});
Read the notes in the src/curl/loader folder and the cjsm11.js file for more information about loading CommonJS and node.js modules.
curl.js's global API is for bootstrapping an app. You would typically only use this API once in your application to load the main module of your application.
For a complete description, check out the wiki.
curl(['main', 'other', 'another' /* etc */], callback, errorback);
Loads a module named "main" along with two other modules and then executes callback, handing it the exported values of the modules as parameters.
curl(['main', 'other', 'another' /* etc */])
.then(callback, errorback);
Promises-based API for executing callbacks.
when(curl(['dep1'])).then(callback);curl(config, ['main' /* etc */], callback, errorback);
Specify configuration options, load dependencies, and execute callback.
curl(['main', 'domReady!' /* etc */]).then(
callback,
errorback
);
curl(['main', 'domReady!' /* etc */], function (main) {
// do some bootstrapping here
});
Executes the callback when the dom is ready for manipulation AND all dependencies have loaded.
curl(['domReady!', 'js!nonAMD.js!order', 'js!another.js!order']), function () {
/* do something cool here */
});
Executes the function when the non-AMD javascript files are loaded and the dom is ready. The another.js file will wait for the nonAMD.js file before executing.
Note: Please use curl.js's new legacy loader for much more flexible and sensible loading of non-AMD scripts. Please read the docs in the src/curl/loader folder for more information.
Note: if a file supports AMD or CommonJS module formats, you can not use the js! plugin on that file.
curl(['js!nonAMD.js'])
.next(['dep1', 'dep2', 'dep3'], function (dep1, dep2, dep3) {
// do something before the dom is ready
})
.next(['domReady!'])
.then(
function () {
// do something after the dom is ready
},
function (ex) {
// show an error to the user
}
);
Executes callbacks in stages using .next(deps, callback).
Note: .next() does not load resources in parallel. Therefore, it is a
last resort when other options do not satisfy your use case. You should
use the preloads config option and/or the legacy loader
whenever possible.
curl = {
baseUrl: '/path/to/my/js',
pluginPath: 'for/some/reason/plugins/r/here',
paths: {
curl: 'curl/src/curl',
cssx: 'cssx/src/cssx',
my: '../../my-lib/'
},
apiName: 'someOtherName'
};
If called before the <script> that loads curl.js, a global curl var will
configure curl.js when it loads. All of the configuration parameters are
optional. curl.js tries to do something sensible in their absence. :)
Some common configuration options:
curl and require for curl.js's global
variablewindow, to place curl on when using
apiNameA more complete list can be found on the wiki.
<script>
// configure curl
curl = {
paths: {
cssx: 'cssx/src/cssx/',
stuff: 'my/stuff/'
}
};
</script>
<script src="https://github.com/cujojs/curl/raw/0.8.13/js/curl.js" type="text/javascript"></script>
<script type="text/javascript">
curl(
// fetch all of these resources ("dependencies")
[
'stuff/three', // an AMD module
'cssx/css!stuff/base', // a css file
'i18n!stuff/nls/strings', // a translation file
'text!stuff/template.html', // an html template
'domReady!'
]
)
// when they are loaded
.then(
// execute this callback, passing all dependencies as params
function (three, link, strings, template) {
var body = document.body;
if (body) {
body.appendChild(document.createTextNode('three == ' + three.toString() + ' '));
body.appendChild(document.createElement('br'));
body.appendChild(document.createTextNode(strings.hello));
body.appendChild(document.createElement('div')).innerHTML = template;
}
},
// execute this callback if there was a problem
function (ex) {
var msg = 'OH SNAP: ' + ex.message;
alert(msg);
}
);
</script>
The file structure for this example would look as follows:
js/
curl/
plugin/
i18n.js
text.js
domReady.js
cssx/
src/
cssx/
css.js
my/
stuff/
nls/
strings.js
base.css
template.html
three.js
curl.js
Web apps, especially large ones, require many modules and resources. Most of these modules and resources need to be loaded at page load, but some may be loaded later, either in the background or "just in time". They also need to be loaded as quickly as possible.
The traditional way to load javascript modules is via a <SCRIPT> element in
an HTML page. Similarly, CSS files are loaded via a <LINK> element, and
text resources are either loaded in the page or via XHR calls.
The problem with <SCRIPT> and <LINK> elements is that a browser must execute
them sequentially since it has no idea if one may depend on another. It just
assumes the developer has placed them in the correct order and that there are
dependencies. (The term "synchronous loading" is used to describe this process
since the elements are executed in a single timeline.)
If there are no dependencies between two files, loading them sequentially is a waste of time. These files could be loaded and executed in parallel (i.e at the same time).
An asynchronous loader does just that: it loads javascript files (and