The asset pipeline is implemented by the sprockets-rails
gem, and is enabled by default.
You can disable it while creating a new application by passing the --skip-sprockets
option. This will generate a config/application.rb
with a require to sprockets commented out.
- Concatenate assets into master (.js, .css) files and name them with a SHA256 hash to keep tracking of content changes, improving browser caching management.
- Minification or compression.
- Preprocessing: SASS->CSS, CoffeScript->Javascript, ERB for both.
Assets placed in app/assets
will be served thru sprockets, except in production, where assets are precompiled to public/assets
to be served as static files.
Assets placed directly in public
will be served by the app as static files (not processed) when config.public_file_server.enabled = true
. In production this setting is set to false
because it's the web server (not the app) that should serve static files.
Disable it with:
config.generators do |g|
g.assets false
end
-
app/assets stores assets owned by your application.
-
lib/assets stores your own libraries' code that doesn't really fit into the scope of the application or those libraries which are shared across applications.
-
vendor/assets is for assets that are owned by outside entities, such as code for JavaScript plugins and CSS frameworks. Keep in mind that third party code with references to other files also processed by the asset Pipeline (images, stylesheets, etc.), will need to be rewritten to use helpers like
asset_path
.
When a file is referenced from a manifest or a helper, Sprockets searches any direct subdirectory of all 3 assets
directories (default directories are images
, javascripts
and stylesheets
).
//= require home # => app/assets/javascripts/home.js
//= require moovinator # => lib/assets/javascripts/moovinator.js
//= require slider # => vendor/assets/javascripts/slider.js
//= require phonebox # => vendor/assets/somepackage/phonebox.js
Subdirectories can be found with:
//= require sub/hello # => vendor/assets/javascripts/sub/hello.js
You can view the search path by inspecting Rails.application.config.assets.paths
in the Rails console.
Paths can be added (fully qualified) to this search path with something like:
config.assets.paths << Rails.root.join('lib', 'videoplayer', 'flash')
The paths are searched in order, meaning that by default app/assets
will override lib/assets
and vendor/assets
counterparts.
Files referenced outside a manifest must be added to the precompile array or they will not be available in the production environment.
Sprockets handles index files as manifest files. Example: lib/assets/javascripts/library_name/index.js
serves as the manifest for all files of library_name
lib (folder). This file could include a list of all the required files in order, or a simple require_tree
directive. Then the library can be referenced as:
//= require library_name
favicon_link_tag 'myicon.ico' # => <link href="/assets/myicon.ico" rel="shortcut icon" type="image/x-icon" />
image_tag("icon.png") # => <img src="/assets/icon.png" alt="Icon" />
image_tag("icons/icon.png") # => <img src="/assets/icons/icon.png" alt="Icon" />
image_tag("/custom_root/icon.png", alt: "Edit entry") # => <img src="/custom_root/icon.png" alt="Edit entry" />
javascript_include_tag "lib" # => <script src="/assets/lib.js"></script>
javascript_include_tag "lib", "/elsewhere/hello"
# => <script src="/assets/lib.js"></script>
# <script src="/elsewhere/hello.js"></script>
javascript_include_tag "http://abc.com/no_ext" # => <script src="http://abc.com/no_ext"></script>
javascript_include_tag "http://abc.com/ext.js" # => <script src="http://abc.com/ext.js"></script>
stylesheet_link_tag "style" # => <link href="/assets/style.css" media="screen" rel="stylesheet" />
stylesheet_link_tag "http://abc.com/style.css" # => <link href="http://abc.com/style.css" ... />
stylesheet_link_tag "style", "/css/stylish"
# => <link href="/assets/style.css" ... />
# <link href="/css/stylish.css" ... />
asset_path("app.js") # => "/assets/app.js"
asset_path("foo/bg.png") # => "/assets/foo/bg.png"
asset_path("/foo.css") # => "/foo.css"
asset_path("/foo") # => "/foo"
asset_path("http://abc.com/js/xmlhr.js") # => "http://abc.com/js/xmlhr.js"
asset_url 'app.js' # => http://example.com/assets/app.js
asset_url 'app.js', host: "http://cdn.com" # => http://cdn.com/assets/app.js
If you add an erb
extension to a CSS asset file, then helpers like asset_path
are available:
# style.css.erb
.class { background-image: url(<%= asset_path 'image.png' %>) }
sass-rails
provides -url
and -path
helpers (hyphenated):
# style.scss
asset-url("rails.png") # => url(/assets/rails.png)
asset-path("rails.png") # => "/assets/rails.png"
# application.js.erb
$('#logo').attr({ src: "<%= asset_path('logo.png') %>" });
These are files containing directives - instructions that begin with =
that tell Sprockets which files to require in order to build (load, process, concatenate and compress) a single CSS or JavaScript file.
Examples:
# app/assets/javascripts/application.js
// ...
//= require jquery
//= require jquery_ujs
//= require_tree .
# app/assets/stylesheets/application.css
/* ...
*= require_self
*= require_tree .
*/
Extensions are optional and assumed from the manifest file extension. Paths are relative to manifest file. Files are loaded once even if targeted in multiple directives.
//= require foo
requires a single file
//= require_directory bar
requires all files in a single directory (no recursive)
//= require_tree .
requires all files in current directory and subdirectories (recursive)
//= require_self
requires any content within the file (if any) at the precise location of the require_self
call.
For Sass is recommended to use
@import
rule instead of sprockets directives, since the latter will make mixins and variables not available outside the files they were defined in.
@import "mixins/*"
is equivalent torequire_directory mixins
@import "mixins/**/*"
is equivalent torequire_tree mixins
Any valid ruby glob may be used. The imports are sorted alphabetically.
The following settings can be configured in config/environments/development.rb
When enabled (default), Sprockets assets are served as separate files in the order they are specified in the manifest file. Example:
# app/assets/javascripts/application.js:
//= require core
//= require projects
//= require tickets
would generate this HTML:
<script src="/assets/core.js?body=1"></script>
<script src="/assets/projects.js?body=1"></script>
<script src="/assets/tickets.js?body=1"></script>
The body
param is required by Sprockets.
Disabling asset debugging will replace detailed asset exception pages with a much terser error or a runtime Javascript exception, but it'll greatly improve local requests speed by using local asset caching that will still pick up new changes. So, it is recommended to enable it only when needed.
When enabled (default), the asset pipeline will check if all the assets loaded in your application are included in the config.assets.precompile
list.
When enabled (default), the path will be output instead and no error is raised. When disabled, an error will be raised when an asset cannot be found.
When enabled (default), digests will be generated for asset URLs.
Precompiling assets in development provides the fastest asset responses in local since it processes assets once and servers static files in subsequent requests, but at the cost of having to precompile each time a change is done in them, so it's recommended when not working with them. Just make sure to run rake assets:clobber
before committing to avoid adding those precompiled assets to your repository.
By default Rails assumes assets have been precompiled and will be served as static assets by your web server.
Rails has the following task to compile the asset manifests and other files in the pipeline:
RAILS_ENV=production bin/rails assets:precompile
Files meeting any of the following conditions will be precompiled automatically:
- File is named
application.css
orapplication.js
- File is under
app/assets
directory (the one in your app and those from gems) with extension different to.js
or.css
(images, fonts, etc).
These conditions are applied to final compiled file names. This means anything that compiles to JS/CSS is excluded, as well as raw JS/CSS files; for example, .coffee
and .scss
files are not automatically included as they compile to JS/CSS.
Manifests (other than the main application ones) or individual stylesheets and JavaScript files can be added to the precompile array in config/initializers/assets.rb
:
Rails.application.config.assets.precompile += %w( admin.js admin.css )
Always specify an expected compiled filename that ends with .js
or .css
, even if you want to add Sass or CoffeeScript files to the precompile array.
Local compilation allows you to commit the compiled files into source control, and deploy as normal in cases like:
- You may not have write access to your production file system.
- You may be deploying to more than one server, and want to avoid duplication of work.
- You may be doing frequent deploys that do not include asset changes.
config.assets.compile = true
In this mode all requests for assets in the pipeline are handled by Sprockets directly, compiled and cached on the first request, and the manifest names used in the helpers are altered to include the MD5 hash.
This mode uses more memory, performs more poorly than the default and is not recommended.
To use a CDN, you need to set config.action_controller.asset_host
in config/environments/production.rb
. Using an environment variable is recommended.
config.action_controller.asset_host = ENV['CDN_HOST']
You can also override the host for a specific asset by using the host
option in a helper:
<%= asset_path 'image.png', host: 'mycdnsubdomain.fictional-cdn.com' %>
This can be configured by using the config.assets.css_compressor
. Possible values are:
:yui
(yui-compressor
gem):sass
(sass-rails
gem)
This configuration setting is config.assets.js_compressor
. Possible values are:
:uglifier
(uglifier
gem) [default].:clousre
(closure-compiler
gem):yui
(yui-compressor
gem)
By default, Sprockets caches assets in tmp/cache/assets
in development and production environments. To disable it:
config.assets.configure do |env|
env.cache = ActiveSupport::Cache.lookup_store(:null_store)
end