/pannier

Portable asset processing tool for Ruby web apps

Primary LanguageRubyMIT LicenseMIT

Pannier

Build Status Code Climate

Pannier is a general-purpose Ruby asset processing tool. Its goal is to work the same way in any Rack environment. No Rails glue, no mandatory JavaScript or CSS libraries, preprocessors or gems.

A small configuration DSL describes asset processing: modification of file contents and file names, file concatenation. No decisions about uglifiers/optimisers/preprocessors have been made; that part is up to you.

The interface for plugging any asset processing library into Pannier is very basic and inspired by Rack. The lack of a plugin ecosystem that binds you to any particular preprocessor is considered a feature.

Pannier can also act as a Rack application that can be mounted (mapped to a path) within another Rack application, so it can serve your assets too. In that case, there are helper methods for including your assets in the view layer. Adding your own view helpers is easy too.

Why?

The Rails asset pipeline essentially consists of Sprockets and a bunch of inscrutable Rails coupling. You generate a new Rails app and everything is setup for you. We call this "convention over configuration". It's fine, but as soon as you need to ditch one or more of those conventions you'll be frustrated.

I have found the principle of least astonishment to be far more valuable than an automagic beginners' experience in the long run. This is especially true where asset processing in Rails is concerned. I want explicit control over my assets and I don't mind spending a small amount of time on configuration.

Getting started

Create a config file in the root of your project named .assets.rb.

The example below would take all of your stylesheets from one directory, modify them and then concatenate them into a single file in another directory.

input  'assets'                    # Where your unprocessed assets live.
output 'public'                    # Where your processed assets will live.

package :styles do
  input  'stylesheets'             # Relative to `assets`.
  assets '**/*.css'                # Glob, relative to `assets/stylesheets`.

  modify do |content, basename|    # Do something to the file content here.
    [quuxify(content), basename]   # Return an array of content and basename.
  end                              # This block is called once for each file.

  concat 'main.min.css'            # Concat into `public`.
end
$ pannier process

Your stylesheets from assets/stylesheets have now all been quuxified and concatenated into public/main.min.css.

Modifying assets

Modifiers are just Ruby callables; blocks, procs, lambdas, objects that respond to call. They are executed in order of specification. Here's a typical use case: assets are run through a couple of modifiers, then concatenated into one file, then finally that single file has a hash of its contents appended to its name.

require 'foo'
require 'bar'
require 'digest'
# ...

package :styles do
  # ...

  modify { |content, basename|  [foo(content), basename] }
  modify { |content, basename|  [bar(content), basename] }
  concat 'main'
  modify do |content, basename|
    [content, "#{basename}-#{Digest::MD5.hexdigest(content)}.min.css"]
  end
end

To understand further, you can browse the current features on relish.

Contributing

Yes, please contribute! Fork this repo, then send a pull request with a note that clearly explains your changes. If you're unsure or you're asking for a big change, just open an issue and we can chat about it first.

Credits

Built by Joe Corcoran. Thanks to the authors of rake-pipeline, a project which tried to address a similar problem.

License

MIT.