# Piler
[](http://travis-ci.org/epeli/piler)
Feature highlights
* Minify and concatenate JS and CSS for fast page loads
* Tag rendering
* Namespaces
* Transparent preprocessor
* Push CSS changes to the browser using Socket.IO
* Easy code sharing with server
## Awesome Asset Manager for Node.js
*Piler* allows you to manage all your JavaScript and CSS assets cleanly and
directly from code. It will concatenate and minify them in production and it
takes care of rendering the tags. The idea is to make your pages load as
quickly as possible.
So why create a yet another asset manager? Because Node.js is special. In
Node.js a JavaScript asset isn't just a pile of bits that are sent to the
browser. It's code. It's code that can be also used in the server and I think
that it's the job of asset managers to help with it. So in *Piler* you can take
code directly from your Javascript objects, not just from JavaScript files.
Copying things from Rails is just not enough. This is just a one reason why
*Piler* was created.
Server-side code:
```javascript
clientjs.addOb({BROWSER_GLOBAL: {
aFunction: function() {
console.log("Hello I'm in the browser also. Here I have", window, "and other friends");
}
}});
```
You can also tell *Piler* to directly execute some function in the browser:
```javascript
clientjs.addExec(function() {
BROWSER_GLOBAL.aFunction();
alert("Hello" + window.navigator.appVersion);
});
```
Currently *Piler* works only with [Express], but other frameworks are planned
as well.
*Piler* is written following principles in mind:
* Creating best possible production setup for assets should be as easy as
including script/link to a page.
* Namespaces. You don't want to serve huge blob of admin view code for all
anonymous users.
* Support any JS- or CSS-files. No need to create special structure for your
assets. Just include your jQueries or whatever.
* Preprocessor languages are first class citizens. Eg. Just change the file
extension to .coffee to use CoffeeScript. That's it. No need to worry about
compiled files.
* Use heavy caching. Browser caches are killed automatically using the hash
sum of the assets.
* Awesome development mode. Build-in support for pushing CSS changes to
browsr using Socket.IO.
**Full example Express 2.x**
```javascript
var createServer = require("express").createServer;
var piler = require("piler");
var app = createServer();
var clientjs = piler.createJSManager();
var clientcss = piler.createCSSManager();
app.configure(function() {
clientjs.bind(app);
clientcss.bind(app);
clientcss.addFile(__dirname + "/style.css");
clientjs.addUrl("http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js");
clientjs.addFile(__dirname + "/client/hello.js");
});
app.configure("development", function() {
clientjs.liveUpdate(clientcss);
});
clientjs.addOb({ VERSION: "1.0.0" });
clientjs.addExec(function() {
alert("Hello browser" + window.navigator.appVersion);
});
app.get("/", function(req, res){
res.render("index.jade", {
layout: false,
js: clientjs.renderTags(),
css: clientcss.renderTags()
});
});
app.listen(8080);
```
**Full example Express 3.x**
```javascript
var express = require('express'),
http = require('http'),
piler = require("piler"),
app = express();
var clientjs = piler.createJSManager();
var clientcss = piler.createCSSManager();
var srv = require('http').createServer(app);
app.configure(function(){
clientjs.bind(app,srv);
clientcss.bind(app,srv);
clientcss.addFile(__dirname + "/style.css");
clientjs.addUrl("http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js");
clientjs.addFile(__dirname + "/client/hello.js");
});
app.configure("development", function() {
clientjs.liveUpdate(clientcss);
});
clientjs.addOb({ VERSION: "1.0.0" });
clientjs.addExec(function() {
alert("Hello browser" + window.navigator.appVersion);
});
app.get("/", function(req, res){
res.render("index.jade", {
layout: false,
js: clientjs.renderTags(),
css: clientcss.renderTags()
});
});
srv.listen(8080);
```
index.jade:
```jade
!!! 5
html
head
!{css}
!{js}
body
h1 Hello Piler
```
## Namespaces
The example above uses just a one pile. The global pile.
If you for example want to add big editor files only for administration pages
you can create a pile for it:
```javascript
clientjs.addFile("admin", __dirname + "/editor.js");
clientjs.addFile("admin", __dirname + "/editor.extension.js");
```
This will add file editor.js and editor.extension.js to a admin pile. Now you
can add that to your admin pages by using giving it as parameter for
*renderTags*.
```javascript
js.renderTags("admin");
```
This will render script-tags for the global pile and the admin-pile.
*js.renderTags* and *css.renderTags* can take variable amount of arguments.
Use *js.renderTags("pile1", "pile2", ....)* to render multiple namespaces
Piling works just the same with css.
## Sharing code with the server
Ok, that's pretty much what every asset manager does, but with *Piler* you can
share code directly from your server code.
Let's say that you want to share a email-validating function with a server and
the client
```javascript
function isEmail(s) {
return !! s.match(/.\w+@\w+\.\w/);
}
```
You can share it with *addOb* -method:
```javascript
clientjs.addOb({MY: {
isEmail: isEmail
}
});
```
Now on the client you can find the isEmail-function from MY.isEmail.
*addOb* takes an object which will be merged to global window-object on the
client. So be carefull when choosing the keys. The object can be almost any
JavaScript object. It will be serialized and sent to the browser. Few caveats:
1. No circural references
1. Functions will be serialized using Function.prototype.toString. So closures
won't transferred to the client!
### Pattern for sharing full modules
This is nothing specific to *Piler*, but this is a nice pattern which can be
used to share modules between the server and the client.
share.js
```javascript
(function(exports){
exports.test = function(){
return 'This is a function from shared module';
};
}(typeof exports === 'undefined' ? this.share = {} : exports));
```
In Node.js you can use it by just requiring it as any other module
```javascript
var share = require("./share.js");
```
and you can share it the client using *addFile*:
```javascript
clientjs.addFile(__dirname + "./share.js");
```
Now you can use it in both as you would expect
```javascript
share.test();
```
You can read more about the pattern from [here](http://caolanmcmahon.com/posts/writing_for_node_and_the_browser)
## Logging
Sometimes it is nessesary to control pilers output based on the system environment your running your application in.
In default mode Pilers logger will output any information it has by using the "console" javascript object. The following example shows
how to configure a custom logger
### Logger interface
The basic logger facility implements the following methods.
```javascript
exports.debug = console.debug
exports.notice = console.log
exports.info = console.info
exports.warn = console.warn
exports.warning = console.warn
exports.error = console.error
exports.critical = console.error
```
### Inject a custom logger
The following example injects "winston", a multi-transport async logging library into pilers logging mechanism.
```javascript
var piler = require('piler');
var logger = require('winston');
// [More logger configuration can take place here]
global.js = js = piler.createJSManager({ outputDirectory: assetTmpDir , "logger": logger});
global.css = css = piler.createCSSManager({ outputDirectory: assetTmpDir, "logger": logger});
```
More information about winston can be found [here](https://github.com/flatiron/winston).
## Awesome development mode!
Development and production modes works as in Express. By default the
development mode is active. To activate production mode set NODE\_ENV
environment variable to *production*.
### Live CSS editing
This is really cool! You don't want to edit CSS at all without this after you
try it!
Because *Piler* handles the script-tag rendering it can add some development
tools when in development mode.
Using Express you can add Live CSS editing in development mode:
```javascript
app.configure("development", function() {
clientjs.liveUpdate(clientcss);
});
```
This is similar to [Live.js][], but it does not use polling. It will add
Socket.IO which will push the CSS-changes to your browser as you edit them.
If your app already uses Socket.IO you need to add the *io*-object as second
parameter to liveUpdate:
```javascript
var io = require('socket.io').listen(app);
clientjs.liveUpdate(clientcss, io);
```
### Script-tag rendering
In development mode every JS- and CSS-file will be rendered as a separate tag.
For example js.renderTags("admin") will render
```javascript
clientjs.addFile(__dirname + "/helpers.js");
clientjs.addFile("admin", __dirname + "/editor.js");
clientjs.addFile("admin", __dirname + "/editor.extension.js");
```
to
```html
```
in development mode, but in production it will render to
```html
```
So debugging should be as easy as directly using script-tags. Line numbers
will match your real files in the filesystem. No need to debug huge Javascript
bundle!
## Examples
Visit
[this](https://github.com/epeli/piler/blob/master/examples/simple/app.js)
directory to see a simple example using ExpressJS 2.x.
This
[example](https://github.com/epeli/piler/blob/master/examples/simple/app.js)
uses ExpressJS 3.x a custom logger (winston) and a global socket.io instance
together with Piler.
## API summary
Code will be rendered in the order you call these functions with the exception
of *addUrl* which will be rendered as first.
### createJSManager and createCSSManager
Can take an optional configuration object as an argument with following keys.
var jsclient = piler.createJSManager({
outputDirectory: __dirname + "/mydir",
urlRoot: "/my/root"
});
#### urlRoot
Url root to which Piler's paths are appended. For example urlRoot "/my/root"
will result in following script tag:
#### outputDirectory
If specified *Piler* will write the minified assets to this folder. Useful if
you want to share you assets from Apache etc. instead of directly serving from
Piler's Connect middleware.
### JavaScript pile
#### addFile( [namespace], path to a asset file )
File on filesystem.
#### addUrl( [namespace], url to a asset file )
Useful for CDNs and for dynamic assets in other libraries such as socket.io.
#### addOb( [namespace string], any Javascript object )
Keys of the object will be added to the global window object. So take care when
choosing those. Also remember that parent scope of functions will be lost.
You can also give a nested namespace for it
clientjs.addOb({"foo.bar": "my thing"});
Now on the client "my thing" string will be found from window.foo.bar.
The object will be serialized at the second it is passed to this method so you
won't be able modify it other than between server restarts. This is usefull for
sharing utility functions etc.
Use *res.addOb* to share more dynamically objects.
#### addExec( [namespace], Javascript function )
A function that will executed immediately in browser as it is parsed. Parent
scope is also lost here.
#### addRaw( [namespace], raw Javascript string )
Any valid Javascript string.
### CSS pile
These are similar to ones in JS pile.
#### addFile( [namespace], path to a asset file )
CSS asset on your filesystem.
#### addUrl( [namespace], url to a asset file )
CSS asset behind a url. Can be remote too. This will be directly linked to you
page. Use addFile if you want it be minified.
#### addRaw( [namespace], raw CSS string )
Any valid CSS string.
## Supported preprocessors
### JavaScript
For JavaScript the only supported one is [CoffeeScript][] and the compiler is
included in *Piler*.
### CSS
CSS-compilers are not included in *Piler*. Just install what you need using
[npm][].
* [Stylus][] with [nib][] (npm install stylus nib)
* [LESS][] (npm install less)
Adding support for new compilers should be
[easy](https://github.com/epeli/pile/blob/master/lib/compilers.coffee).
Feel free to contribute!
## Installing
From [npm][]
npm install piler
## Source code
Source code is licenced under [The MIT
License](https://github.com/epeli/piler/blob/master/LICENSE) and it is hosted
on [Github](https://github.com/epeli/piler).
## Changelog
v0.4.2 - 2013-04-16
* Fixes to work with ExpressJS 3.x
* Unit test fixes
* Make console output configurable
v0.4.1 - 2012-06-12
* Add getSources
* Put cache key to resource url instead of query string
v0.4.0 - 2012-06-17
* Remove Dynamic Helpers.
Dynamic Helpers where an Express 2.0 only API. This makes Piler more framework
agnostic and it will work with Express 3.0. This also removes support for
response object functions. We'll add those back if there is a need for them
(open up a issue if you miss them!) and we'll find good framework agnostic way
to implement them.
v0.3.6 - 2012-06-17
* Bind all production dependency versions
v0.3.5 - 2012-06-17
* Fix LESS @imports
* Fix Stylus without nib
* Use path module for Windows compatibility
v0.3.4 - 2012-03-29
* Fix Stylus @imports
v0.3.3 - noop
v0.3.2 - 2011-12-11
* Workaround compiler bug in CoffeeScript
v0.3.1 - 2011-11-17
* Fix CSS namespaces
v0.3.0 - 2011-10-13
* Rename to Piler
* Really minify CSS
* Implemented res.addOb
* Implement outputDirectory and urlRoot options.
* addOb can now take nested namespace string and it won't override existing
namespaces.
## Contact
Questions and suggestions are very welcome
- [Esa-Matti Suuronen](http://esa-matti.suuronen.org/)
- esa-matti [aet] suuronen dot org
- [EsaMatti](https://twitter.com/#!/EsaMatti) @ Twitter
- Epeli @ freenode/IRCnet
[Express]: http://expressjs.com/
[Node.js]: http://nodejs.org/
[Live.js]: http://livejs.com/
[LESS]: http://lesscss.org/
[Stylus]: http://learnboost.github.com/stylus/
[nib]: https://github.com/visionmedia/nib
[npm]: http://npmjs.org/
[CoffeeScript]: http://jashkenas.github.com/coffee-script/