Write pure JavaScript modules, without any concern about concatenation order and require calls.
CommonJS is awesome for external libraries, but not perfect when you want to split you own application in modules.
For example, want to use your awesome utils
module in every file but keep your global var clean ? You need to
require your utils
module in every file:
// If you are in the same directory
var utils = require('./utils');
utils.doAnAwesomeJob();
// If you're not, it can be unpleasant
var utils = require('./../../../../../utils');
utils.doAnAwesomeJob();
What about making utils
module, and all your application modules, directly accessible from any of them. Well, Mokuai
makes it possible.
// Do not need to require it, just use it
utils.doAnAwesomeJob();
Your module does not have a pleasant var name ? No problem, all modules are accessible from the modules
keyword.
modules['my-awesome-utils-function'].doAnAwesomeJob();
Mokuai wraps your modules into a special closure.
All modules are saved in a modules
object, and are refered with a special getter
which initializes your module when
it is first called, just like a require
call.
To be easily accessed anywhere, all your modules are declared in a with statement and it works like magic.
The only limit is that your modules names have to be unique. Everything else is possible.
Each module exports its value just like in CommonJS:
With module.exports
var utils = {
doAnAwesomeJob: function(){
// ... do something awesome
},
// ...
};
// ...
module.exports = utils;
or just using the exports
shortcut
exports.doAnAwesomeJob = function(){
// ... do something awesome
};
// ...
Mokuai lets you prepend/append your modules with any code.
For example, you can append your application launcher:
// Launch application when DOM ready
$(App.launch);
or save a dangerously overridden global var by prepending this kind of code:
// Application defines a module named 'window', so all modules can't access the real global window var anymore.
// Fortunately, we can prepend this to save the original window
modules.originalWindow = window;
All modules are wrapped in a mokuai closure. So nothing is exported by default.
But you can still export things using the exports option.
If the exports value is true, then all your modules will be exported. If the exports value is a string, then only the module with the exports name will be exported.
Export works in CommonJS environments, like Node.js:
// exports=true
module.exports = modules;
// exports='utils'
module.exports = modules['utils'];
and in the browser too:
// exports=true
window['modules'] = modules;
// exports='utils'
window['utils'] = modules['utils'];
In the browser, you can customize the name of your exported module using the exportsname option:
// exports=true and exportsname=MyAwesomeModules
window['MyAwesomeModules'] = modules;
// exports='utils' and exportsname=MyAwesomeUtils
window['MyAwesomeUtils'] = modules['utils'];
Still find it verbose to use module.exports to export your module ? Well you can use the autoexports option to automatically export the name of your module.
// With autoexports to true, no need to use module.exports.
// My module name is 'utils', so I just need to write this:
var utils = {
doAnAwesomeJob: function(){
// ... do something awesome
}
// ...
};
// ...
If you want to use the mokuai cli, install it globally via npm:
$ npm install mokuai --global
Then you can use the mokuai
command, as follow:
$ mokuai --help
Usage: mokuai <[modulename:]file ...> [options]
Wrap your CoffeeScript modules with mokuai.
If the --output (-o) option is not used, the result is printed into the console.
Modules are automatically named after file basenames (path/to/file.coffee => file).
Files can also be prefixed by a custom module name and a colon (custom:path/to/file.js => custom).
Options:
-h, --help output usage information
-V, --version output the version number
-p, --prepend <value> (repeatable) add the <value> file to prepended files (files that are prepended to modules)
-a, --append <value> (repeatable) add the <value> file to appended files (files that are appended to modules)
-e, --exports [value] define the exports mokuai option ([value] is optional and can be either false, true, or any module name)
-n, --exportsname <value> set the exportsname mokuai option to <value>
-A, --autoexports set the autoexports mokuai option to true
-o, --output <output> set the output file (if not set, print the result in the console)
Examples:
$ mokuai path/to/module.coffee customname:path/to/another/module.coffee
$ mokuai <files> --output gen/app.js
$ mokuai <files> --exports --output gen/app.js
$ mokuai <files> --exports --exportsname MyApp --output gen/app.js
$ mokuai <files> --exports AppModule --exportsname MyApp --output gen/app.js
$ mokuai <files> --exports MainModule --exportsname MyApp --output gen/app.js
$ mokuai <files> --append prepare.coffee --append launch.coffee --autoexports --output gen/app.js
$ mokuai <files> --prepend prepend.coffee --append append.coffee --exports --output gen/app.js
Modules are automatically named after files basenames, unless you prefix the filepath with a custom name followed by a colon.
For example:
$ mokuai path/to/module.coffee customname:path/to/another/module.coffee --output closure.js
will create 2 modules named module
and customname
.
prepend / append options are repeatable to allow multiple files:
$ mokuai <files> --prepend prepend1.coffee --prepend prepend2.coffee --append append1.coffee --append append2.coffee
If you want to use the library in a Node.js project, install it locally via npm:
$ npm install mokuai
or save it as a dev dependency, adding the --save-dev
option:
$ npm install mokuai --save-dev
Then, you can just require mokuai
in your code and use it as follow.
var mokuai = require('mokuai');
var closure = mokuai({
moduleName1: 'moduleContent1',
moduleName2: 'moduleContent2',
// ...
moduleNameN: 'moduleContentN'
}, {
prepend: [
'prependContent1',
'prependContent2',
// ...
'prependContentN'
],
append: [
'appendContent1',
'appendContent2',
// ...
'appendContentN'
],
autoexports: false,
exports: 'moduleName1',
exportsname: 'MyCustomExportsName',
});
// Do whatever you want with 'closure'
If you want to compile from filepaths instead of modules contents:
var mokuai = require('mokuai');
var closure = mokuai.fromFiles({
moduleName1: 'path/to/module1.coffee',
moduleName2: 'path/to/module2.coffee',
// ...
moduleNameN: 'path/to/moduleContentN.coffee'
}, {
prepend: [
'path/to/prependContent1.coffee',
'path/to/prependContent2.coffee',
// ...
'path/to/prependContentN.coffee'
],
append: [
'path/to/appendContent1.coffee',
'path/to/appendContent2.coffee',
// ...
'path/to/appendContentN.coffee'
],
autoexports: false,
exports: 'moduleName1',
exportsname: 'MyCustomExportsName'
});
// Do whatever you want with 'closure'