grand-central-pipeline

A javascript asset pipeline for Node

npm install grand-central-pipeline
20 downloads in the last month

Grand Central Pipeline

A javascript asset pipeline for Node and Express. Based on the Sprockets/Rails methods for giving directives and concatenating javascript files. Minifies using UglifyJS in production environments.

TODO:

  • Client-side debugging
  • Examples folder with simple Express app

Documentation

Breaking Changes in 0.0.8

  • The dest directory is now your main public/assets directory. No need to specify a javascripts folder; any requested JS files will have dest as a base. So requesting /javascripts/app.js will compile the file in [dest]/javascripts/app.js from the file [src]/app.js.

Setup with Express

Grand Central Pipeline can be used as middleware to serve javascript assets from any Express application.

Options that can be specified:

  • source ( required ) : the directory of the actual javascript files to be compiled.
  • dest ( required ) : the asset directory you want any compiled files to be requested from.
  • minify (default false) : set to true to minify all javascript. If not present, GCP minifies in production and concatenates in development.
  • templateName (default jst) : the name of the global client-side object that stores all javascript templates.

All options and defaults:

require('grand-central-pipeline')({
    source: '',   // required
    dest: '',     // required
    minify: false,
    templateName: 'jst',
    templateDir: '',
    env: (current Node Environment || 'development')
});

Example code in your app.js file or wherever you initialize your Express app:

var express = require('express'),
    path = require('path'),
    gcp = require('grand-central-pipeline'),
    app = express();

app.configure(function(){
    app.use(gcp({
        source: path.join(__dirname, 'client'),
        dest: path.join(__dirname, 'public')
    }));
    // It's best to put the GCP middleware above Express's static asset pipline:
    app.use(express.static(path.join(__dirname, 'public')));
});

All client-side javascript goes in the source directory (/client in this case). When a file is requested, it is compiled into a single JS file in the public dest directory (/public in this case). So a request for /javascripts/app.js will be compiled into the public/javascripts directory.

Any requests made outside of /javascripts will not be run through the processor.

Minification

In the development environment, required JS files are concatenated and labeled as is. In production, they are minified using UglifyJS.

Directive Processor

Modeled after Sprockets, GCP is run on every requested javascript file. It scans for comment lines beginning with = at the top of the file.

Example in client/sample.js:

//= require lib/jquery
//= require_tree ./ui

/* Multi-line comment
 *= require file1 file2 file3
 */

$(function(){ document.write("Hello World") });

This would output to, and be requested from /javascripts/sample.js, and will include the required files and directories in the order they are listed. Code at the bottom of the file will be at the end of the combined version.

It can be linked to in views as:

<script type="text/javascript" src="/javascripts/sample.js"></script>

If javascripts/folder/sample.js is requested by the client, the corresponding source file should be in client/folder/sample.js.

The Directive Processor is recursive, meaning all bundled files are also checked. So if 'models.js' is required, that file will also be checked for any directives and those files will also be bundled.

GCP Directives

require

require path inserts the contents of the asset source file specified by path. If the file is required multiple times, it will appear in the bundle only once.

include

include path works like require, but inserts the contents of the specified source file even if it has already been included or required.

require_directory or requireDirectory

require_directory path requires all source files in the directory specified by path. Files are required in alphabetical order.

require_tree or requireTree

require_tree path works like require_directory, but operates recursively to require all files in all subdirectories of the directory specified by path.

Templating

Javascript templating is also supported. GCP supports Embedded Javascript/Underscore (.ejs) and Handlebars (.hbs) templates. Any files required by the requested JS (as in using //= require sample.hbs) with those extensions will be compiled.

The templates can be accessed through the namespace jst['path/file'] or whatever template name you provide in the options.

So if your template's actual path was client/templates/home/index.ejs the corresponding client-side javascript would be:

var template = jst['templates/home/index'];
$("div").html(template({ JSONDATA }));

Make sure you have the appropriate client-side libraries for templating:

  • Underscore.js
  • Handlebars runtime library. Each template is also a Handlbars partial with the name path.file that can be accessed with {{> path.file}}. So for the example below, the partial name would be list.

Template in client/templates/list.hbs, assuming the template (or folder) is required in app.js:

<script type="text/javascript" src="javascripts/handlebars-runtime.js"></script>
<script type="text/javascript" src="javascripts/app.js"></script>
<script type="text/javascript">
    var template = jst['templates/list'];
    $("#list").html(template({ DATA }));
</script>

Use the option templateDir if you have a single folder with templates in your source directory. So with the option templateDir: 'templates', the file project.hbs within source/templates will be called on the client-side with jst['project']. You still need to //= require_tree ./templates for this to work.

Command Line Tool

$ gcp [source] [destination] --min --all
  • source is the only required argument. The source javascript file will be processed and concatenated into the same directory as `filename.dist.js'.
  • destination is the destination of the processed file.
  • --min minifies the javascript.
  • --all both concatenates and minifies.

Client-side Debugging

[WORK IN PROGRESS] The GCP client-side library handles errors to return the correct file names and line numbers for debugging.

Skipping files

If you don't want a .js file to be compiled, add "_skip" to the filename. So file_skip.js will be passed over. This also works for folders, so /files_skip/app.js and anything in that folder will be skipped.

npm loves you