cc.loader
A JavaScript module loading/creation system for the web including support for baking. It includes support for asynchronously loading modules and their dependencies from multiple script files using a simple but powerful JavaScript API. It can optionally integrate with Joose to ease adding classes to modules or creating module files that are classes. cc.loader is written in CoffeeScript but supports JavaScript and CoffeeScript modules and compiles/bakes all CoffeeScript to JavaScript.
installation
To install globally:
sudo npm install -g cc.loader
usage
creating modules
To create a module with dependencies:
cc ;
Each cc.loader module file must define a module name corresponding to its path otherwise the module will fail to load (but with a helpful error message). For example "other.submodule" must be defined in "other/submodule.js" or "other/submodule.coffee". A configurable prefix which defaults to "lib" can also be prepended to the script path. Conversely when requiring a module as a dependency the filesystem path to load it from is determined from the module path.
Populating a module with cc.set:
// file must exist at <prefix>/friend/root.js based on the module name.cc;
modules and namespaces
Each module has an associated JavaScript namespace with an identical name. There is no requirement for a module to populate this namespace but cc.loader provides simple mechanisms to do so if you want to use them.
The this object inside of the "defines" callback can be used to inject functions and variables into the JavaScript namespace associated with a module name:
cc;
Two modules split over two files:
// file: lib/pet/cat.jscc;
// file: lib/root.jscc;
Multiple modules can exist in a single file but only things defined by the module which has a name corresponding to the filesystem path are publicly available when "defines" callbacks of including modules are run.
loading modules
To use from html without baking:
baking
When using cc.require or <script> tags one web request is made to load each script. Each request involves a potentially large set of replicated headers which slows down the load speed of the page. Installing cc.loader provides the "ccbaker" command which can be used to combine all modules reachable from a certain module file into a single (potentially minified/obfuscated) JavaScript file which can be loaded quickly.
To bake a module together with its dependencies and minify the output:
% ccbaker module.js > output.js
The root directory is determined from the name of the module in the first source file passed and where it sits in the filesystem tree. "hello.baker" at lib/hello/baker.js would set the root to "lib" but a module named "baker" at lib/hello/baker.js would set the root as "lib/hello".
Full arguments:
% ccbaker -h
ccbaker [arguments] <paths to source files>
arguments:
-c compile coffeescript modules to javascript only
-C do not compile coffeescript to javascript
-i [path] include raw source file before modules, can be used
multiple times
-l do not include cc.loader in output
-m do not minify javascript
-o obfuscate javascript
-s use strict mode for packed file
-w [path] output baked file to [path] and keep watching all reachable
paths for changes, recreating baked file as they change
-v print extra information to the terminal on stderr
e.g. Bake the modules reachable from two files without minifying the output:
% ccbaker -m primary.js secondary.coffee > output.min.js
advanced usage
integration with joose
Joose is a object system for JavaScript. cc.loader provides some utility functions for creating Joose classes using the suggested namespace structure.
To create a Joose class under the module namespace:
cc
A module itself can be a Joose class:
// file: lib/root/Enemy.jscc
An alternative way of making a module that is a Joose class:
// file: lib/root/Boss.jscc;
Shorthand to create a module class that inherits another:
// file: lib/root/EndBoss.jsccparent'joose.Boss';
// file: lib/root.jscc
hooks for custom class systems
cc
// Since the parent namespace "Cat" defines "extend", then HouseCat is set to// the return value of Cat.extend({ playful: true })ccparent'Cat'
console // true, true
empty modules
A module doesn't have to have a "defines" call but if not it must call "empty". This can be useful for creating modules that serve only to bundle other modules together:
cc;
module that is a function
// This module only defines a function at the corresponding namespace.cc
notes on development
IE makes it very difficult to reliably determine whether a script has loaded without polling, so errors indicating module load failures will not be seen until after a 10 second or so delay. For this reason developing module structures under IE is not recommended. Once the module structure works then debugging code under IE with full path names should be as easy as in a decent browser.
The poll timeout can be set with the following code and should be set before requiring the first module:
ccieScriptPollTimeout = 5000; // in milliseconds, 5000 is the default
The reason every file requires a module corresponding to the filename is to support IE 8 and below.
dependencies
- baker: node.js, npm will fetch other node module dependencies.
- web: nothing to use the library or a baked library. If Joose is loaded then a small amount of extra API is available.
testing
% git clone git://github.com/nuisanceofcats/cc.loader.git
% cd cc.loader
% npm test
cc.loader test server listening on: 8012
please go to http://localhost:8012/
FAQ
- What does the name mean? I like C.C. Lemon
- Why not RequireJS? - RequireJS supports a lot of things, but has a large manual so it can be perceived as rather difficult to use. I prefer to use the namespacing system cc.loader provides over assigning every dependency to a variable as in RequireJS.