Rake::Pipeline

Rake::Pipeline is a system for packaging assets for deployment to the web. It uses Rake under the hood for dependency management and updating output files based on input changes.

Usage

The easiest way to use Rake::Pipeline is via an Assetfile file in the root of your project.

A sample Assetfile looks like this:

output "public"

input "assets" do
  # this block will take all JS inputs, wrap them in a closure,
  # add some additional metadata, and concatenate them all into
  # application.scripts.js.
  match "*.js" do
    filter ClosureWrapper
    filter DataWrapper
    concat "application.scripts.js"
  end

  # this block will take all HTML and CSS inputs, convert them
  # into JavaScript
  match "*/*.{html,css}" do
    filter DataWrapper
    concat "application.assets.js"
  end

  match "*.js" do
    concat "application.js"
  end
end

Each input block defines a collection of files, and a pipeline that transforms those files. Within each pipeline, you can specify a series of filters to describe the transformations you'd like to apply to the files.

Upgrading from Previous Versions

The Assetfile syntax has changed in version 0.6.0. In previous versions, each Assetfile defined a single pipeline, and input statements would add input files to that pipeline. After version 0.6.0, multiple pipelines can be defined in an Assetfile. The input method now takes a block, and this block defines a pipeline. This means that any match blocks or filters must be defined inside an input block, and no longer at the top level. For example, this:

# Prior to 0.6.0
output "public"
input "assets"

match "**/*.js" do
  concat
end

would now be written as:

# After 0.6.0
output "public"

input "assets" do
  match "**/*.js" do
    concat
  end
end

Filters

A filter is a simple class that inherits from Rake::Pipeline::Filter. A filter must implement a single method, called generate_output, which takes two parameters: a list of input files and the output file.

Both the input and output files are Rake::Pipeline::FileWrapper objects. The most important methods on a FileWrapper are:

  • path: the path of the file, relative to its input root

  • read: read the contents of the file

  • write(string): write a String to the file

For example, a simple concatenation filter would look like:

class ConcatFilter < Rake::Pipeline::Filter
  def generate_output(inputs, output)
    inputs.each do |input|
      output.write input.read
    end
  end
end

If you had a series of input files like:

  • app/javascripts/one.js

  • app/javascripts/two.js

  • app/javascripts/three.js

and you specified the ConcatFilter in your Assetfile like:

filter ConcatFilter, "application.js"

The filter would receive a single call to generate_output with an Array of FileWrappers representing each of the three files, and a FileWrapper representing application.js.

Binary Data

If your filter is operating on binary data, like images, rather than textual data, like source code, you can specify that in your filter:

class ConcatFilter < Rake::Pipeline::Filter
  processes_binary_files

  def generate_output(inputs, output)
    inputs.each do |input|
      output.write input.read
    end
  end
end

This will stop `Rake::Pipeline` from trying to interpret the input files as `UTF-8`, which obviously will not work on binary data.

Filters

Rake::Pipeline comes with a built-in filter, Rake::Pipeline::ConcatFilter. Its implementation is the same as the ConcatFilter above. Other filters that are useful for web development like a CoffeeScriptFilter and SassFilter are available in [rake-pipeline-web-filters](github.com/wycats/rake-pipeline-web-filters).

Preview Server

To start up the preview server, run rakep server. This will start up a server that automatically recompiles files for you on the fly and serves up the files you need.

This should allow you to have a single index.html file pointing at the same files in both development and production.

Compiling Assets

To compile all assets before deployment, simply run:

$ rakep build

Encodings

If a filter does not specify that it processes binary files, Rake::Pipeline will open all inputs and outputs as UTF-8.

This means that if you have files encoded in other encodings, like Latin-1, Rake::Pipeline will raise an exception. In this situation, you need to open the offending file in your text editor and re-save it as UTF-8.

Public Release Requirement

Before publicly releasing this code, we need to properly support encodings other than UTF-8. That means using the default_external instead of hardcoding to UTF-8 and providing a mechanism for specifying the encoding of a file using a magic comment.