Installation
First install nodejs, them run following:
$sudo npm i cjsc -g
Getting Started
Let's make a module foo.js:
console.log( "foo.js: Hello World" );
Now we address this module from other one bar.js:
require( "./foo" );
console.log( "bar.js: Hello World" );
Compiling bar.js
$cjsc bar.js -o out.js
If we run out.js the output would be:
foo.js: Hello World
bar.js: Hello World
Well, let's try now something more sophisticated. foo.js:
console.log( "foo.js: constructing" );
module.exports = { name: "foo.js" };
bar.js:
console.log( require( "./foo" ) );
console.log( require( "./foo" ) );
The output of out.js after compilation:
foo.js: constructing
{ name: "foo.js" }
{ name: "foo.js" }
Mark that constructing code is invoked only once and the imported object is retrieved from the cache with every require request.
What happens if we include a non-JavaScript file? Let's try with foo.txt:
Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet
bar.js:
var str = require( "./foo.txt" );
console.log( "bar.js:" + str );
The output:
bar.js:Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet
Deeper in File Modules
Every module has exposed module variable that references to an object representing the module. Like in nodejs the object has following structure:
- module.id {string} - The identifier for the module.
- module.filename {string} - The fully resolved filename to the module.
- module.loaded {boolean} - Whether or not the module is done loading.
- module.parent {Object} - The module that required this one.
- module.children {Object[]} - The module objects required by this one
Caching goes the same as in nodejs. Modules are cached after the first time they are loaded.
So every call to require('foo') returns exactly the same object, if it refers to the same file. Multiple calls to require('foo') don't execute the module code multiple times.
Command-line options
Compile main-module.js into build.js:
./cjsc main-module.js -o build.js
or
node cjsc.js main-module.js -o build.js
Compile main-module.js into build.js and generate source map
./cjsc main-module.js -o build.js --source-map=build/build.js.map --source-map-url=http://localhost/
or with the following options for automatic naming
./cjsc main-module.js -o build.js --source-map=*.map
or this way to explicitly specify the path to sources relative to the source map
./cjsc main-module.js -o build.js --source-map=build/*.map --source-map-root=../src
Whereas:
- --source-map is a source map file path relative to the project directory (the directory where cjsc is running)
- --source-map-url by default is "." and means the same path as source map file
- * --source-map-root is sources path relative to the source map file. For instance: sources are in project/src, build is in project/build. So specify --source-map-root=../src to let the browser know that it must look for mapped source file in ../src/**/file.js relative to the source map path.
Compile main-module.js into build.js and minify build.js
./cjsc main-module.js -o build.js -M
With a banner
./cjsc main-module.js -o build.js -M --banner="/*! pkg v.0.0.1 */"
Setting up Grunt task
Gruntfile.js:
grunt.loadNpmTasks('grunt-cjsc');
grunt.initConfig({
cjsc: {
development: {
options: {
minify: true
},
files: {
"path/compiled.js" : "path/source.js"
}
}
}
});
package.json:
"devDependencies": {
//..
"grunt-cjsc": ">=1.0.0"
}
Please find details at https://github.com/dsheiko/grunt-cjsc
Configuring dependencies
You can configure your dependencies in a JSON file. E.g. config.json:
{
"dependency-name": {
"path": "dependency-path",
"globalProperty": "global-property",
exports: [ "variable", "variable" ],
require: [ "dependency-name", "dependency-name" ]
}
}
or
{
"dependency-name": {
"path": "dependency-path",
"globalProperty": "global-property",
exports: "variable",
require: "dependency-name"
}
}
To enable the configuration use --config option:
node cjsc main.js -o out.js --config=config.json
Making module of a globally exposed variable
config.json:
{
"jQuery": {
"globalProperty": "jQuery"
}
}
main.json:
var $ = require( "jQuery" );
// $ - is a reference to globally exposed jQuery instance (assuming window.jQuery si defined outside this module)
console.log( $( window ) );
Compilation:
node cjsc main.js -o build.js --config=config.json
Making modules of jQuery and its plugins
config.json:
{
"jQuery": {
"path": "./vendors/jquery-2.1.0.min.js"
},
"placeholder": {
"path": "./vendors/jquery.placeholder.js",
"require": "jQuery",
"exports": "jQuery"
}
}
main.json:
// Obtain jQuery as UMD-module
var $ = require( "jQuery" );
// Attach plugin to jQuery
require( "placeholder" );
console.log( $.fn.placeholder );
Compilation:
node cjsc main.js -o build.js --config=config.json
Making modules of 3rd party libraries
Options #1:
// Load 3rd-party library and export the globals it exposes ("exp1" and "exp2")
var exp1 = require( "./vendors/lib.js", "exp1", "exp2" ).exp1,
// Take the second exported object from the module cache
exp2 = require( "./vendors/lib.js" ).exp2;
console.log( "exp1", exp1 );
console.log( "exp2", exp2 );
Options #2 by config.json:
{
"lib": {
"path": "./vendors/lib.js",
"exports": [ "exp1", "exp2" ]
}
}
main.json:
var lib = require( "lib" );
console.log( lib.exp1, lib.exp2 );
Compilation:
node cjsc main.js -o build.js --config=config.json
If 3rd party code exposes the only object, it can be done like that config.json:
{
"lib": {
"path": "./vendors/lib.js",
"exports": "exp1"
}
}
Note: The "path" must be relative to the project directory (where the compiler is running from)
main.json:
var lib = require( "lib" );
// Exp1
console.log( lib );
Using Mustache templates
Template file: ./mustache/example.tpl
{{title}} spends {{calc}}
Module that uses the template
var mustache = require( "./mustache/mustache" ),
tpl = require( "./mustache/example.tpl" ),
view = {
title: "Joe",
calc: function () {
return 2 + 4;
}
};
console.log( mustache.render( tpl, view ) );
Using Handlebars templates
Template file: ./handlebarsjs/example.hbs
<div class="entry">
<h1>{{title}}</h1>
<div class="body">
{{body}}
</div>
</div>
Module that uses the template
var handlebars = require( "./handlebarsjs/handlebars", "Handlebars" ),
tpl = require( "./handlebarsjs/example.hbs" ),
view = {
title: "My New Post",
body: "This is my first post!"
};
console.log( handlebars.compile( tpl )( view ) );
Using Browserify-plugin
$npm install -g browserify-replace
$node cjsc.js -o /tmp/build.js demo/use-browserify-replace.js -t [ browserify-replace \
--replace '{ "from": "\\$foo", "to": 42 }' \
--replace '{ "from": "\\$bar", "to": "quux" }' ]
$node /tmp/build.js
Output:
42
quux