Skip to content

Latest commit

 

History

History
272 lines (219 loc) · 8.99 KB

asset-pipeline.adoc

File metadata and controls

272 lines (219 loc) · 8.99 KB

Asset Pipeline

The asset pipeline offers the Rails developer the opportunity of delivering CSS, JavaScript and image files to the browser more optimally. Depending on the type this can be a compression or a file name fingerprint. Different CSS files are combined into one big file. The fingerprinting enables the browser and any proxy in between to optimally cache the data, so the browser can load these files more quickly on subsequent visits.

Note
When running your webserver on HTTP/2 it might be a good idea to break up this flow into smaller chunks to optimize HTTP-Caching. But that depends on the specifics of your web application.

Within the asset pipeline, you can program CSS, SASS, JavaScript and CoffeeScript extensively and clearly, in order to let them be delivered later as automatically compressed CSS and JavaScript files.

As an example we use once more our web shop with a product scaffold:

$ rails new webshop
  [...]
$ cd webshop
$ rails generate scaffold product name 'price:decimal{7,2}'
  [...]
$ rails db:migrate
  [...]

In the directory app/assets you will then find the following files:

app/assets/
├── config
│   └── manifest.js
├── images
├── javascripts
│   ├── application.js
│   ├── cable.js
│   ├── channels
│   └── products.coffee
└── stylesheets
    ├── application.css
    ├── products.scss
    └── scaffolds.scss

The files app/assets/javascripts/application.js and app/assets/stylesheets/application.css are what is referred to as manifest files. They automatically include the other files in the relevant directory.

application.js

The file app/assets/javascripts/application.js has the following content:

app/assets/javascripts/application.js
// [...]
//
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require_tree .

This file and all sub files (which are integrated via required_tree) are merged into on file and the asset pipeline optimizes it. The not yet optimized version can be downloaded in the development environment with this URL: http://localhost:3000/assets/application.js

application.css

The file app/assets/stylesheets/application.css has the following content:

app/assets/stylesheets/application.css
/*
 * [...]
 *
 *= require_tree .
 *= require_self
 */

With the command require_tree . all files in this directory are automatically integrated.

The not yet optimized CSS can be downloaded with the URL: http://localhost:3000/assets/application.css

rails assets:precompile

When using the asset pipeline, you need to remember that you have to precompile the assets before starting the Rails server in the production environment. This happens via the command rails assets:precompile with a prefixed RAILS_ENV=production for the production environment.

$ RAILS_ENV=production bin/rails assets:precompile
Yarn executable was not detected in the system.
Download Yarn at https://yarnpkg.com/en/docs/install
I, [2018-01-27T17:56:51.650389 #8573]  INFO -- : Writing /.../public/assets/application-9eca361cfc054d474ebb4c8c6b16465dd4cd42664fe474b8d9a52573c1e2d2e3.js
I, [2018-01-27T17:56:51.656011 #8573]  INFO -- : Writing /.../public/assets/application-9eca361cfc054d474ebb4c8c6b16465dd4cd42664fe474b8d9a52573c1e2d2e3.js.gz
I, [2018-01-27T17:56:51.700670 #8573]  INFO -- : Writing /.../public/assets/application-35729bfbaf9967f119234595ed222f7ab14859f304ab0acc5451afb387f637fa.css
I, [2018-01-27T17:56:51.700920 #8573]  INFO -- : Writing /.../public/assets/application-35729bfbaf9967f119234595ed222f7ab14859f304ab0acc5451afb387f637fa.css.gz

If you forget to do this, you will find the following error message in the log:

ActionView::Template::Error (application.css isn't precompiled)

The files created by rails assets:precompile appear in the directory public/assets

public/assets/
├── application-35729bfbaf9967f119234595ed222f7ab14859f304ab0acc5451afb387f637fa.css
├── application-35729bfbaf9967f119234595ed222f7ab14859f304ab0acc5451afb387f637fa.css.gz
├── application-443bf66d6410ac6de6fd02a73fd8279e83ae0baee64d3832cc67a0909e8329d9.css
├── application-443bf66d6410ac6de6fd02a73fd8279e83ae0baee64d3832cc67a0909e8329d9.css.gz
├── application-9eca361cfc054d474ebb4c8c6b16465dd4cd42664fe474b8d9a52573c1e2d2e3.js
├── application-9eca361cfc054d474ebb4c8c6b16465dd4cd42664fe474b8d9a52573c1e2d2e3.js.gz
├── application-b59f735b008e94c6f72a3b7c43cf31aea2ab324386b7a378482d17887e683a61.js
└── application-b59f735b008e94c6f72a3b7c43cf31aea2ab324386b7a378482d17887e683a61.js.gz

Go ahead and use your favorite editor to have a look at the created css and js files. You will find minimized and optimized code. If the web server supports it, the zipped gz files are delivered directly, which speeds things up a bit more.

The difference in file size is enormous. The file application.js created in the development environment has a file size of 80 KB. The file js.gz created by rails assets:precompile is only 20 KB. Users of cellphones in particular will be grateful for smaller file sizes.

The speed advantage incidentally lies not just in the file size, but also in the fact that only one file is downloaded, not several. The HTTP/1.1 overhead for loading multiple files is time-consuming. Things are changing with HTTP/2 but that is beyond the scope of this book.

Note
jQuery used to be an essential part of the JavaScript world in the Ruby on Rails world. Since Rails version 5.1 jQuery it no longer needed. Most people will still use it but you don’t have to.

The Fingerprint

The fingerprint in the file name consists of a hash sum generated from the content of the relevant file. This fingerprint ensures optimal caching and prevents an old cache being used if any changes are made to the content. A simple but very effective method.

All files below the directory app/assets are delivered in normal form by the Rails server. For example, you can go to the URL http://localhost:3000/assets/rails.png to view the Rails logo saved under app/assets/images/rails.png and to http://localhost:3000/assets/application.js to view the content of app/assets/javascripts/application.js. The Rails image rails.png is delivered 1:1 and the file application.js is first created by the asset pipeline.

But you should never enter these files as hard-wired in a view. To make the most of the asset pipeline, you must use the helpers described here.

You want to save all images in the directory app/assets/images/. The asset pipeline will search for them there. To actually use them in your erb code you can use the image_tag helper. Assumed we have a file app/assets/images/rails.png we can recreate an <img> element with this code:

<%= image_tag "rails.png", alt: "Rails Logo" %>

In development mode, the following HTML code results from this:

<img alt="Rails Logo" src="/assets/rails.png" />

In production mode, you get an HTML code that points to a precompiled file with fingerprint:

<img alt="Rails Logo" src="/assets/rails-be...as0.png" />

You can use the helper javascript_include_tag to retrieve a JavaScript file compiled by the asset pipeline. This is what it would look like in the view for the file app/assets/javascripts/application.js:

<%= javascript_include_tag "application" %>

Normaly you don’t have to care about this because the default app/views/layouts/application.html.erb takes care of it.

A stylesheet compiled by the asset pipeline can be retrieved via the helper stylesheet_link_tag. In the view, it would look like this for the file app/assets/stylesheets/application.css:

<%= stylesheet_link_tag "application" %>

Normaly you don’t have to care about this because the default app/views/layouts/application.html.erb takes care of it.

Defaults in the application.html.erb

Incidentally, the file app/views/layouts/application.html.erb that the scaffold generator creates by default already contains the coding links for these JavaScript and stylesheet files:

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Webshop</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>