coffee-toaster
Version:
Minimalist build system for CoffeeScript.
758 lines (561 loc) • 20.4 kB
Markdown

Minimalist build system for CoffeeScript.
> Version 0.6.13
[](http://travis-ci.org/serpentem/coffee-toaster)
# Features
* Inheritance support across multiples files for the lazy
* Vendors management
* Automagically packaging system with namespaces
* Micro build routines
* Exports aliases
* Broken and circular-loop dependencies validation
* Live syntax-check
* Growl support
* Debug Mode
* Minify support
* Scaffolding routines
# Issues
Do not hesitate to open a feature request or a bug report.
> https://github.com/serpentem/coffee-toaster/issues
# Mailing List
A place to talk about it, ask anything, get in touch. Luckily you'll be answered
sooner than later.
> https://groups.google.com/group/coffee-toaster
*NOTE: The list is `active` and `maintained`, though the low activity. So don't
be shy.*
# About
Minimalist build system for CoffeeScript, made for those who dare to use class
definitions in CoffeeScript while being able to easily inherit from external
files. The system is powered with import directives that uses wildcards
facilities, exposed scopes, excluded files filter options and a packaging system
that can inject your folders-as-namespaces to all your classes based on where
they are under your src folder.
CoffeeToaster was created initially as a base for creating the
[Theoricus Framework](https://github.com/serpentem/theoricus).
# Docs
- [Installing](#installing)
- [Scaffolding](#scaffolding)
- [Initializing new app](#initializing-new-app)
- [Initializing config file](#initializing-config-file)
- [Usage](#usage)
- [Import directive](#import-directive)
- [Compile](#compile) `-c`
- [Watch](#watch) `-w`
- [Debug](#debug) `-cd`, `-wd`
- [Autorun](#autorun) `-a`, `-ad`
- [Representative structure](#representative-structure)
- [HTML inclusion](#html-inclusion)
- [Advanced options](#advanced-options)
- [Conclusion](#conclusion)
- [Note for VIM Users](#vim-users)
- [Config file](#config-file)
- [Config options](#config-options)
- [`folders`](#config-options-folders)
- [`exclude`](#config-options-exclude)
- [`vendors`](#config-options-vendors)
- [`bare`](#config-options-bare)
- [`packaging`](#config-options-packaging)
- [`expose`](#config-options-expose)
- [`minify`](#config-options-minify)
- [`httpfolder`](#config-options-httpfolder)
- [`release`](#config-options-release)
- [`debug`](#config-options-debug)
- [Examples](#examples)
- [API](#api)
- [Contributing](#contributing)
- [Setup](#setup)
- [Building](#building)
- [Watching](#watching)
- [Testing](#testing)
- [CHANGELOG](#changelog)
<a name="installing" />
# Installing
----
`npm install -g coffee-toaster`
<a name="scaffolding" />
# Scaffolding
----
There are two simple `scaffolding` routines bundled with CoffeeToaster for
creating new projects structure from the scratch and also for creating the
config `toaster.coffee` file for existent projects.
<a name="initializing-new-app" />
## Initializing new app
CoffeeToaster suggests a very simple structure for initial projects, you can
customize it as you like.
`toaster -n mynewapp`
You will be asked for some things:
> source folder
Relative folderpath to your source folder, default is `src`.
> release file
Relative filepath to your release file, default is `www/js/app.js`
> http folder
The folderpath to reach your debug file through http, default is an `empty
string`. Imagine that the `www` is your root web folder, and inside of it you
have a `js` dir where you put your debug file. In this case you'd just need to
inform 'js' as the http folder. It tells toaster *how to reach your debug js
file* starting from the `/` on your server.
This property is only for **debug**, your *release* file will not be affected.
### Result
Considering all the default values, you'll end up with a structure as such:
````
myawsomeapp/
├── src
├── vendors
├── www
└── js
└── toaster.coffee
4 directories, 1 file
````
<a name="initializing-config-file" />
## Initializing config file
You can also initialize an existing project with a config `toaster.coffee` file
such as:
````
cd existing-project
toaster -i
````
Some of the same information (`src`, `release` and `httpfolder`) will be
required, answer everything according to your project's structure and a config
`toaster.coffee` file will be created inside of it.
<a name="usage" />
# Usage
----
Toaster help screen.
````
CoffeeToaster
Minimalist build system for CoffeeScript
Usage:
toaster [options] [path]
Examples:
toaster -n myawsomeapp (required)
toaster -i [myawsomeapp] (optional)
toaster -w [myawsomeapp] (optional)
toaster -wd [myawsomeapp] (optional)
Options:
-n, --new Scaffold a very basic new App
-i, --init Create a config (toaster.coffee) file
-w, --watch Start watching/compiling your project
-c, --compile Compile the entire project, without watching it.
-d, --debug Debug mode (compile js files individually)
-a, --autorun Execute the script in node.js after compilation
-j, --config Config file formatted as a json-string. [string]
-f, --config-file Path to a different config file. [string]
-v, --version
-h, --help
````
<a name="import-directive"/>
## Import directive
The import directive is known by:
````coffeescript
#<< app/views/user_view
#<< app/utils/*
````
By putting `#<< app/views/user_view` in your CoffeeScript file, you're telling
CoffeeToaster that there's a dependency. It's like a `require`, except that you
can't save a reference of the imported file to a variable. Instead, this
directives shoud be put in the first lines of your files.
This is how you organically tells Toaster about the specific ordering
options to be considered when all of your files get merged. Files imported this
way will only be gracefully sorted out in your final output javascript so
every file is always **defined** before it's **needed**.
Wild cards `#<< app/utils/*` are also accepted as a handy option.
If you're writing a `class B` that will extends the `class A`, you shoud first
import the `class A` so it will be available for being extended by `class B`.
* src/app/a
````coffeescript
class A
constructor:->
console.log 'Will be used as base class.'
````
* src/app/b
````coffeescript
#<< app/a
class B extends A
constructor:->
console.log 'Using class A as base class'
````
Think of it as a glue that you use to chain all of your files appropriately.
<a name="compiling"/>
## Compile
Compile your project according your [config file](#config-file).
````bash
cd existing-project
toaster -c
````
<a name="watching"/>
## Watch
Starts Toaster in watching'n'compiling mode:
````bash
cd existing-project
toaster -w
````
Any changes you make to your `src` files will trigger the `compile` action.
<a name="debugging"/>
## Debug
In debug mode option `-d` all files will be compiled individually inside a
folder called `toaster` in the same directory you've pointed your debug file,
aiming to ease the debugging process.
````bash
toaster -wd
toaster -cd
````
For example, if you have `release/app-debug.js`, a folder will be created at
`release/toaster` and all your CoffeeScript files will be compiled to Javascript
within.
<a name="representative-structure"/>
### Representative Structure
Bellow is a representative directory structure after compiling in debug mode.
````
/usage
|-- src
| `-- app
| |-- controllers
| | `-- users_controller.coffee
| |-- models
| | `-- user_model.coffee
| `-- views
| `-- user_view.coffee
|-- www
| `-- js
| |-- app-debug.js
| |-- app.js
| `-- toaster
| `-- app
| |-- controllers
| | `-- users_controller.js
| |-- models
| | `-- user_model.js
| `-- views
| `-- user_view.js
`-- toaster.coffee
````
Every CoffeeScript file is compiled individually inside the `www/js/toaster`
directory, so you can debug it sanely.
The debug file `www/js/app-debug.js` is the boot-loader responsible for loading
all these individual compiled JS files into the right order.
<a name="autorun"/>
## Autorun
In autorun mode option `-a` the script is recompiled after each file change and
it is executed in a node.js child process. It is possible to use autorun in
combination with debug option `-d` to set the script breakpoint on the first line
````bash
toaster -a
toaster -da
````
of if you like the `watch` option
````bash
toaster -wa
toaster -wda
````
to better debug your application via node.js you can use some tools like
[node-inspector](https://github.com/dannycoates/node-inspector)
It is also possible to pass arguments to the compiled script
````bash
toaster -wa argument argument2 argument3
toaster -wda argument argument2 argument3
````
Please note that the `-a` arguments has to be the last of the group in order to
make it work: `toaster -ad argument` will not behave as expected and
`toaster -da argument` should be used instead
<a name="html-inclusion"/>
## HTML inclusion
So in your `.html` you'll have two options:
> 1) Include your release file.
````html
<script src="js/app.js"></script>
````
> 2) Include the toaster boot-loader (your debug mode).
````html
<script src="js/app-debug.js"></script>
````
<a name="advanced-options"/>
## Advanced options
You can pass your own config file for toaster instead of the default one
`toaster.coffee`, with the `-f` or `--config-file` option:
````bash
toaster -wdf config/mycustomconfig.coffee
````
*NOTE: It's important that you always call this from your project base folder,
otherwise the paths of your config can get messy. Remembers also that the paths
in your config file shoud ideally be always relative to your project base
folder.*
Alternativelly, you can even pass the whole configuration as a JSON string, with
the `-j` or `--config` option:
````bash
toaster -wdj '{"folders":{"src":""},"expose":"window","release":"app.js","debug":"app-debug.js"}'
````
*NOTE: The same above.*
<a name="conclusion"/>
## Conlusion
Every time something changes, CoffeeToaster recompiles all of your application
by:
* collecting all .coffee files and processing everything, adding namespace's
declarations to class definitions based on the folder they are located
* reordering everything, always defining files and classes before they're needed
* merge all yours vendors in the given order
* declare root namespaces
* merge everything
<a name="vim-users"/>
### VIM Users
Due to the way VIM handles files, you'll need to disable the creation of `swap`
and `backup` files.
To do it, just put these three lines in your `.vimrc`:
``` vim
" for coffee-toaster
set nobackup " no backup files
set nowritebackup " only in case you don't want a backup file while editing
set noswapfile " no swap files
```
This will guarantee the expected behavior of Toaster and make it play nicely
with VIM without any conflicts. For more info about why it's really needed,
please check this [thread](https://github.com/serpentem/coffee-toaster/issues/47).
<a name="config-file" />
# Config file
----
The `toaster.coffee` is the config file from where Toaster seek all information
about your app, vendores, build options and so on. There are two main usages
you can make of this file:
* **1) Single source folder:**
When all your code is bellow one single source folder your set up the main
`toast` call passing the folder path directly.
````coffeescript
# src folder
toast 'src'
# excluded items (will be used as a regex)
exclude: ['folder/to/exclude', 'another/folder', '.DS_Store' ]
# packaging vendors among the code
vendors: ['vendors/x.js', 'vendors/y.js' ]
# gereral options (all is optional, default values listed)
bare: false
packaging: true
expose: '' # can be 'window', 'exports' etc
minify: false
# httpfolder (optional), release and debug (both required)
httpfolder: 'js'
release: 'www/js/app.js'
debug: 'www/js/app-debug.js'
````
* **2) Multi source folder:**
When your code is splitted between two or more source folders you can set the
main `toast` call without any path, and inform your folders right bellow it.
````coffeescript
toast
folders:
'src/my/app/folder': 'app'
'src/my/lib/folder': 'lib'
# ...
````
<a name="config-options" />
## Config options
Let's take a closer look at all properties you can have in your `toaster.coffee`
file and what each one of these is responsible of.
<a name="config-options-folders" />
### `folders`
> Mandatory: `no` <BR/>
> Type: `Object` <BR/>
> Default: `null` <BR/>
In case you have more than one `src` folder, you can set an `object` of
`objects` containing setup information about all your source folders, in the
format `'folderpath':'folderalias'`.
The **hash-key** is the `path` of your folder, and the **hash-value** is the
`alias` you want to prepend to all files under that.
*Pay attention to this specially when using Toaster with the '-j'
[option](#advanced-options).*
To give an example, the equivalent use of this config:
````coffeescript
toast 'src'
# ...
````
Would be:
````coffeescript
toast
folders:
'src': ''
````
**NOTE: Aliases take effect only if the [`packaging`](#config-options-packaging)
is set to `true`.**
Aliases lets you set a virtual top namespace to your source folder, if you have
`src/app/app.coffee` which is a `class App`, you'll usually access it using
`new app.App`.
Now if you set an alias like `'src':'awesome'` the whole structure under your
source folder will be addressed under that `awesome` namespace and you need
to prepend it when accessing your classes, i.e. `new awesome.app.App`.
<a name="config-options-exclude" />
### `exclude`
> Mandatory: `no` <BR/>
> Type: `Array` <BR/>
> Default: `[]` <BR/>
Let's you excplicity exclude some folder, file or file type from Toaster
search/process mechanism. The string you use here will effectively turn into
a RegExp like that:
````coffeescript
new RegExp '.DS_store'
new RegExp '.swp'
new RegExp 'my/folder/to/be/excluded'
````
<a name="config-options-vendors" />
### `vendors`
> Mandatory: `no` <BR/>
> Type: `Array` <BR/>
> Default: `[]` <BR/>
You can define vendors such as:
````coffeescript
vendors: ['vendors/x.js', 'vendors/y.js', ... ]
````
It's an ordered array of all your vendor's paths. These files must be purely
javascript, preferably minified ones -- Toaster will not compile or minify them,
only concatenate everything.
<a name="config-options-bare" />
### `bare`
> Mandatory: `no` <BR/>
> Type: `Boolean` <BR/>
> Default: `false` <BR/>
If `true`, compile your CoffeeScript files without the top-level function safety
wrapper:
````javascript
(function() {
console.log('My peace of code!');
}).call(this);
````
So you will end up with just `your peace of code`:
````javascript
console.log('My peace of code!');
````
<a name="config-options-packaging" />
### `packaging`
> Mandatory: `no` <BR/>
> Type: `Boolean` <BR/>
> Default: `false` <BR/>
When packaging is `true`, Toaster will rewrite **all** your `class`
declarations.
If you have a file in `src/app/models/user.coffee` with this contents:
````coffeescript
class User
````
Toaster will rewrite your declaration prepending a `namespace` to it, based on
the folder the class is located, resulting -- in this example -- into this:
````coffeescript
class app.models.User
````
This rewriting process is **saved** directly into your `file`. In case you move
this class to another folder, the prepended `namespace` will be rewrited again,
always following your folder structure.
In other words, your don't need to worry about hardcoded namespaces in your
files, because Toaster will handle all the dirty for you.
<a name="config-options-expose" />
### `expose`
> Mandatory: `no` <BR/>
> Type: `String` <BR/>
> Default: `null` <BR/>
If informed, list all you packages of classes in the given scope. If you use
`window` as your expose scope, your classes will be available also in the window
object -- or whatever scope you inform, suck as `exports` if you're building
for NodeJS.
In the end you'll be able to access your files throught this scope where your
classes was exposed.
````coffeescript
new window.app.models.User
new exports.app.models.User
````
<a name="config-options-minify" />
### `minify`
> Mandatory: `no` <BR/>
> Type: `Boolean` <BR/>
> Default: `true` <BR/>
If `true`, minify your release file using UglifyJS.
Debug files are **never** minified.
<a name="config-options-httpfolder" />
### `httpfolder`
> Mandatory: `no` <BR/>
> Type: `String` <BR/>
> Default: `''` <BR/>
The folder path to reach your debug file through http, in case it is not inside
your root directory. Imagine that the `www` is your root folder and when you
access your webiste the `/` referes to this folder.
Inside this `www` folder you have another folder called `js` where you put all
your compiled js, resulting from a config like this:
````coffeescript
toast 'src'
# ...
release: 'www/js/app.js'
debug: 'www/js/app-debug.js'
````
Following this case you'd just need to inform `js` as your http folder. Toaster
will use it to reach your **debug** files. For that, it will writes the
declarations inside the `debug boot loader` following this location in order to
import your scripts properly when in debug mode, prepending your `httpfolder` to
all file paths:
````javascript
// app-debug.js
document.write('<scri'+'pt src="js/toaster/app.js"></scr'+'ipt>')
````
Without knowing that your JS files is under the `js` folder this path would be
broken.
**NOTE: Your release file will not be affected by this property.**
<a name="config-options-release" />
### `release`
> Mandatory: `yes` <BR/>
> Type: `String` <BR/>
> Default: `null` <BR/>
The file path to your **release** file.
<a name="config-options-debug" />
### `debug`
> Mandatory: `yes` <BR/>
> Type: `String` <BR/>
> Default: `null` <BR/>
The file path to your **debug** file.
<a name="examples"/>
# Examples
----
You'll certainly find some useful resources in the examples provided.
Examine it and you'll understand how things works more instinctively.
Install coffee-toaster, clone the usage example and try different config
options, always looking for the differences in your javascript release file.
> [Single folder example](https://github.com/serpentem/coffee-toaster/tree/master/examples/single-folder)<BR>
> [Multi folder example](https://github.com/serpentem/coffee-toaster/tree/master/examples/multi-folder)<BR>
> [API example](https://github.com/serpentem/coffee-toaster/tree/master/examples/introspection)<BR>
<a name="api"/>
# API
----
You can use Toaster through API as well, in case you want to power up your
compiling tasks or even build some framework/lib on top of it.
See the API example for further information.
> [API example](https://github.com/serpentem/coffee-toaster/tree/master/examples/introspection)
````coffeescript
Toaster = (require 'coffee-toaster').Toaster
toasting = new Toaster [basedir], [options], [skip_initial_build]
toasting.build [header_code_injection], [footer_code_injection]
````
<a name="contributing"/>
# Contributing
----
<a name="setup"/>
## Setting everything up
Environment setup is simple achieved by:
````bash
git clone git://github.com/serpentem/coffee-toaster.git
cd coffee-toaster && git submodule update --init
npm link
````
<a name="building"/>
## Building
Builds the release file inside the `lib` folder.
````bash
make build
````
<a name="watching"/>
## Watching'n'Compiling
Starts watching/compiling using a previuos version of the CoffeeToaster itself.
````bash
make watch
````
<a name="testing"/>
## Testing
Run all tests.
````bash
make test
````
<a name="changelog"/>
# Changelog
----
> [CHANGELOG.md](https://github.com/serpentem/coffee-toaster/tree/master/build/CHANGELOG.md)