1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
|
# Building an Asset Processing Framework
This guide is for using a Sprockets::Environment to process assets. You would use this class directly if you were building a feature similar to Rail's asset pipeline. If you aren't building an asset processing frameworks, you will want to refer to the [Readme](../README.md). For a reference use of `Sprockets::Environment` see [sprockets-rails](http://github.com/rails/Sprockets-rails).
## 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, `Rails.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](http://bower.io) 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.
``` ruby
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.
## Precompile Files
In addition to providing a path, you'll need to give sprockets an entry point to start precompiling files for production deployment. This is usually done via the `Sprockets::Manifest` class like:
```
SprocketsManifest#find(config.assets.precompile).map(&:logical_path).to_set
```
You can see an example in [sprockets-rails](https://github.com/rails/sprockets-rails/blob/49bf8022c8d3e1d7348b3fe2e0931b2e448f1f58/lib/sprockets/railtie.rb#L50).
### 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`:
<table>
<tr>
<th>Logical path</th>
<th>Source file on disk</th>
</tr>
<tr>
<td>application.js</td>
<td>app/assets/javascripts/application.js</td>
</tr>
<tr>
<td>models/project.js</td>
<td>app/assets/javascripts/models/project.js</td>
</tr>
<tr>
<td>hello.js</td>
<td>app/assets/javascripts/hello.coffee</td>
</tr>
</table>
> Note: For assets that are compiled or transpiled, you want to specify the extension that you want, not the extension on disk. For example we specified `hello.js` even if the file on disk is a coffeescript file, since the asset it will generate is javascript.
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`:
``` ruby
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:
``` ruby
environment['application.js']
# => #<Sprockets::Asset ...>
```
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*.
### 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](lib/sprockets/context.rb) 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.
``` js
//= 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:
``` css
/* Multi-line comment blocks (CSS, SCSS, JavaScript)
*= require foo
*/
```
``` js
// Single-line comment blocks (SCSS, JavaScript)
//= require foo
```
``` coffee
# Single-line comment blocks (CoffeeScript)
#= require foo
```
## Processor Interface
Sprockets 2.x was originally designed around [Tilt](https://github.com/rtomayko/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`](https://github.com/rails/sprockets/blob/master/lib/sprockets/processor_utils.rb) for public helper methods.
## Gzip
By default when Sprockets generates a compiled asset file it will also produce a gzipped copy of that file. Sprockets only gzips non-binary files such as CSS, JavaScript, and SVG files.
For example if Sprockets is generating
```
application-12345.css
```
Then it will also generate a compressed copy in
```
application-12345.css.gz
```
You can disable this behavior `Sprockets::Environment#gzip=` to something falsey for example:
```ruby
env = Sprockets::Environment.new(".")
env.gzip = false
```
By default Sprockets uses zlib to generate the compiled asset, you can use zopfli by installing the zopfli gem and then telling Sprockets to compile assets with it:
```ruby
env = Sprockets::Environment.new(".")
env.gzip = :zopfli
```
Setting to any other truthy value will enable zlib compression.
## WIP
This guide is a work in progress. There are many different groups of people who interact with Sprockets. Some only need to know directive syntax to put in their asset files, some are building features like the Rails asset pipeline, and some are plugging into Sprockets and writing things like preprocessors. The goal of these guides are to provide task specific guidance to make the expected behavior explicit. If you are using Sprockets and you find missing information in these guides, please consider submitting a pull request with updated information.
These guides live in [guides](/guides).
|