Sprockets: Rack-based asset packaging

Sprockets is a Ruby library for compiling and serving web assets.
It features declarative dependency management for JavaScript and CSS
assets, as well as a powerful preprocessor pipeline that allows you to
write assets in languages like CoffeeScript, Sass and SCSS.

Installation

Install Sprockets from RubyGems:

$ gem install sprockets

Or include it in your project’s Gemfile with Bundler:

gem 'sprockets', '~> 3.0'

Using Sprockets

For most people interested in using Sprockets, you will want to see End User Asset Generation guide. This contains information about Sprockets’ directive syntax and default processing behavior.

If you are a framework developer that is using Sprockets, see Building an Asset Processing Framework.

If you are a library developer who is extending the functionality of Sprockets, see Extending Sprockets.

Below is a disjointed mix of documentation for all three of these roles. Eventually they will be moved to an appropriate guide, but for now, the recommended way to consume this documentation is to view the appropriate guide first and then supplement with docs from the README.

Behavior

Index files are proxies for folders

In Sprockets, index files such as index.js or index.css inside of a folder will generate a file with the folder’s name. So if you have a file named foo/index.js, it will compile down to foo.js. This is similar to Node.js’s behavior of using folders as modules. It is also somewhat similar to the way that a file in public/my_folder/index.html can be reached by a request to /my_folder. This means that you cannot directly use an index file. For example this would not work:

<%= asset_path("foo/index.js") %>

Instead you would need to use:

<%= asset_path("foo.js") %>

Why would you want to use this behavior? It is common behavior where you might want to include an entire directory of files in a top level javascript. You can do this in Sprockets using require_tree .

//= require_tree .

This has the problem that files are required alphabetically. If your directory has jquery-ui.js and jquery.min.js, then Sprockets will require jquery-ui.js before jquery is required, which won’t work (because jquery-ui depends on jquery). Previously the only way to get the correct ordering would be to rename your files, something like 0-jquery-ui.js. Instead of doing that you can use an index file.

For example, if you have an application.js and want all the files in the foo/ folder you could do this:

//= require foo.js

Then create a file foo/index.js that requires all the files in that folder in any order you want:

//= require ./foo.min.js
//= require ./foo-ui.js

Now, your application.js will correctly load the foo.min.js before foo-ui.js. If you used require_tree it would not work correctly.

Understanding the Sprockets Environment

You’ll need an instance of the Sprockets::Environment class to
access and serve assets from your application. Under Rails 4.0 and
later, YourApp::Application.assets is a preconfigured
Sprockets::Environment instance. For Rack-based applications, create
an instance in config.ru.

The Sprockets Environment has methods for retrieving and serving
assets, manipulating the load path, and registering processors. It is
also a Rack application that can be mounted at a URL to serve assets
over HTTP.

The Load Path

The load path is an ordered list of directories that Sprockets uses
to search for assets.

In the simplest case, a Sprockets environment’s load path will consist
of a single directory containing your application’s asset source
files. When mounted, the environment will serve assets from this
directory as if they were static files in your public root.

The power of the load path is that it lets you organize your source
files into multiple directories – even directories that live outside
your application – and combine those directories into a single
virtual filesystem. That means you can easily bundle JavaScript, CSS
and images into a Ruby library or Bower package and import them into your application.

Manipulating the Load Path

To add a directory to your environment’s load path, use the
append_path and prepend_path methods. Directories at the beginning
of the load path have precedence over subsequent directories.

environment = Sprockets::Environment.new
environment.append_path 'app/assets/javascripts'
environment.append_path 'lib/assets/javascripts'
environment.append_path 'vendor/assets/bower_components'

In general, you should append to the path by default and reserve
prepending for cases where you need to override existing assets.

Accessing Assets

Once you’ve set up your environment’s load path, you can mount the
environment as a Rack server and request assets via HTTP. You can also
access assets programmatically from within your application.

Logical Paths

Assets in Sprockets are always referenced by their logical path.

The logical path is the path of the asset source file relative to its
containing directory in the load path. For example, if your load path
contains the directory app/assets/javascripts:

Asset source file
Logical path

app/assets/javascripts/application.js
application.js

app/assets/javascripts/models/project.js
models/project.js

In this way, all directories in the load path are merged to create a
virtual filesystem whose entries are logical paths.

Serving Assets Over HTTP

When you mount an environment, all of its assets are accessible as
logical paths underneath the mount point. For example, if you mount
your environment at /assets and request the URL
/assets/application.js, Sprockets will search your load path for the
file named application.js and serve it.

Under Rails 4.0 and later, your Sprockets environment is automatically
mounted at /assets. If you are using Sprockets with a Rack
application, you will need to mount the environment yourself. A good
way to do this is with the map method in config.ru:

require 'sprockets'
map '/assets' do
  environment = Sprockets::Environment.new
  environment.append_path 'app/assets/javascripts'
  environment.append_path 'app/assets/stylesheets'
  run environment
end

map '/' do
  run YourRackApp
end

Accessing Assets Programmatically

You can use the find_asset method (aliased as []) to retrieve an
asset from a Sprockets environment. Pass it a logical path and you’ll
get a Sprockets::Asset instance back:

environment['application.js']
# => #

Call to_s on the resulting asset to access its contents, length to
get its length in bytes, mtime to query its last-modified time, and
filename to get its full path on the filesystem.

Using Processors

Asset source files can be written in another format, like SCSS or CoffeeScript,
and automatically compiled to CSS or JavaScript by Sprockets. Processors that
convert a file from one format to another are called transformers.

Minifying Assets

Several JavaScript and CSS minifiers are available through shorthand.

environment.js_compressor  = :uglify
environment.css_compressor = :scss

If you are using Sprockets directly with a Rack app, don’t forget to add
the uglifier and sass gems to your Gemfile when using above options.

Styling with Sass and SCSS

Sass is a language that compiles to CSS and
adds features like nested rules, variables, mixins and selector
inheritance.

If the sass gem is available to your application, you can use Sass
to write CSS assets in Sprockets.

Sprockets supports both Sass syntaxes. For the original
whitespace-sensitive syntax, use the extension .sass. For the
new SCSS syntax, use the extension .scss.

Scripting with CoffeeScript

CoffeeScript is a
language that compiles to the “good parts” of JavaScript, featuring a
cleaner syntax with array comprehensions, classes, and function
binding.

If the coffee-script gem is available to your application, you can
use CoffeeScript to write JavaScript assets in Sprockets. Note that
the CoffeeScript compiler is written in JavaScript, and you will need
an ExecJS-supported runtime
on your system to invoke it.

To write JavaScript assets with CoffeeScript, use the extension
.coffee.

JavaScript Templating with EJS and Eco

Sprockets supports JavaScript templates for client-side rendering of
strings or markup. JavaScript templates have the special format
extension .jst and are compiled to JavaScript functions.

When loaded, a JavaScript template function can be accessed by its
logical path as a property on the global JST object. Invoke a
template function to render the template as a string. The resulting
string can then be inserted into the DOM.

<div>Hello, <span>&lt;%= name %&gt;</span>!</div>

// application.js
//= require templates/hello
$("#hello").html(JST["templates/hello"]({ name: "Sam" }));

Sprockets supports two JavaScript template languages:
EJS, for embedded
JavaScript, and Eco, for
embedded CoffeeScript. Both languages use the familiar &lt;% … %&gt;
syntax for embedding logic in templates.

If the ejs gem is available to your application, you can use EJS
templates in Sprockets. EJS templates have the extension .jst.ejs.

If the eco gem is available to your application, you can use Eco
templates
in Sprockets. Eco
templates have the extension .jst.eco. Note that the eco gem
depends on the CoffeeScript compiler, so the same caveats apply as
outlined above for the CoffeeScript engine.

Invoking Ruby with ERB

Sprockets provides an ERB engine for preprocessing assets using
embedded Ruby code. Append .erb to a CSS or JavaScript asset’s
filename to enable the ERB engine.

Ruby code embedded in an asset is evaluated in the context of a
Sprockets::Context instance for the given asset. Common uses for ERB
include:

  • embedding another asset as a Base64-encoded data: URI with the asset_data_uri helper
  • inserting the URL to another asset, such as with the asset_path helper provided by the Sprockets Rails plugin
  • embedding other application resources, such as a localized string database, in a JavaScript asset via JSON
  • embedding version constants loaded from another file

See the Helper Methods section for more information about
interacting with Sprockets::Context instances via ERB.

Managing and Bundling Dependencies

You can create asset bundles – ordered concatenations of asset
source files – by specifying dependencies in a special comment syntax
at the top of each source file.

Sprockets reads these comments, called directives, and processes
them to recursively build a dependency graph. When you request an
asset with dependencies, the dependencies will be included in order at
the top of the file.

The Directive Processor

Sprockets runs the directive processor on each CSS and JavaScript
source file. The directive processor scans for comment lines beginning
with = in comment blocks at the top of the file.

//= require jquery
//= require jquery-ui
//= require backbone
//= require_tree .

The first word immediately following = specifies the directive
name. Any words following the directive name are treated as
arguments. Arguments may be placed in single or double quotes if they
contain spaces, similar to commands in the Unix shell.

Note: Non-directive comment lines will be preserved in the final
asset, but directive comments are stripped after
processing. Sprockets will not look for directives in comment blocks
that occur after the first line of code.

Supported Comment Types

The directive processor understands comment blocks in three formats:

/* Multi-line comment blocks (CSS, SCSS, JavaScript)
 *= require foo
 */
// Single-line comment blocks (SCSS, JavaScript)
//= require foo
# Single-line comment blocks (CoffeeScript)
#= require foo

Sprockets Directives

You can use the following directives to declare dependencies in asset
source files.

For directives that take a path argument, you may specify either a
logical path or a relative path. Relative paths begin with ./ and
reference files relative to the location of the current file.

The require Directive

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

The require_directory Directive

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

The require_tree Directive

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

The require_self Directive

require_self tells Sprockets to insert the body of the current
source file before any subsequent require directives.

The link Directive

link path declares a dependency on the target path and adds it to a list
of subdependencies to automatically be compiled when the asset is written out to
disk.

For an example, in a CSS file you might reference an external image that always
needs to be compiled along with the css file.

/*= link "logo.png" */
.logo {
  background-image: url(logo.png)
}

However, if you use a asset-path or asset-url SCSS helper, these links will
automatically be defined for you.

.logo {
  background-image: asset-url("logo.png")
}

The link_directory Directive

link_directory path links all the files inside the directory specified by the path

The link_tree Directive

link_tree path works like link_directory, but operates
recursively to link all files in all subdirectories of the
directory specified by path.

The depend_on Directive

depend_on path declares a dependency on the given path without
including it in the bundle. This is useful when you need to expire an
asset’s cache in response to a change in another file.

The depend_on_asset Directive

depend_on_asset path works like depend_on, but operates
recursively reading the file and following the directives found. This is automatically implied if you use link, so consider if it just makes sense using link instead of depend_on_asset.

The stub Directive

stub path excludes that asset and its dependencies from the asset bundle.
The path must be a valid asset and may or may not already be part
of the bundle. stub should only be used at the top level bundle, not
within any subdependencies.

Processor Interface

Sprockets 2.x was originally designed around Tilt’s engine interface. However, starting with 3.x, a new interface has been introduced deprecating Tilt.

Similar to Rack, a processor is any “callable” (an object that responds to call). This may be a simple Proc or a full class that defines a def self.call(input) method. The call method accepts an input Hash and returns a Hash of metadata.

Also see Sprockets::ProcessorUtils for public helper methods.

Input Hash

The input Hash defines the following public fields.

  • :data - String asset contents.
  • :environment - Current Sprockets::Environment instance.
  • :cache - A Sprockets::Cache instance. See Sprockets::Cache#fetch.
  • :uri - String Asset URI.
  • :load_path - String current load path for filename.
  • :name - String logical path for filename.
  • :content_type - String content type of the output asset.
  • :metadata - Hash of processor metadata.
def self.call(input)
  input[:cache].fetch("my:cache:key:v1") do
    # Remove all semicolons from source
    input[:data].gsub(";", "")
  end
end

return Hash

The processor should return metadata Hash. With the exception of the :data key, the processor can store arbitrary valid JSON values in this Hash. The data will be stored and exposed on Asset#metadata.

The returned :data replaces the assets input[:data] to the next processor in the chain. Returning a String is shorthand for returning { data: str }. And returning nil is shorthand for a no-op where the input data is not transformed, { data: input[:data] }.

metadata

The metadata Hash provides an open format for processors to extend the pipeline processor. Internally, built-in processors use it for passing data to each other.

  • :required - A Set of String Asset URIs that the Bundle processor should concatenate together.
  • :stubbed - A Set of String Asset URIs that will be omitted from the :required set.
  • :links - A Set of String Asset URIs that should be compiled along with this asset.
  • :dependencies - A Set of String Cache URIs that should be monitored for caching.
  • :map - An Array of source maps for the asset.
  • :charset - The mime charset for an asset.
def self.call(input)
  # Any metadata may start off as nil, so initialize it the value
  required = Set.new(input[:metadata][:required])

  # Manually add "foo.js" asset uri to our bundle
  required &lt;&lt; input[:environment].resolve("foo.js")

  { required: required }
end

Contributing to Sprockets

Sprockets is the work of hundreds of contributors. You’re encouraged to submit pull requests, propose
features and discuss issues.

See CONTRIBUTING.

Version History

Please see the CHANGELOG

License

Sprockets is released under the MIT License.