Skip to content

Instantly share code, notes, and snippets.

@kevcha
Created September 3, 2018 07:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevcha/f5c45954f6e6196c5f08fff417779d7e to your computer and use it in GitHub Desktop.
Save kevcha/f5c45954f6e6196c5f08fff417779d7e to your computer and use it in GitHub Desktop.
Assets in rails

How assets are handled in Rails

What's assets ? Assets are all javascripts, css, and images files. They are stored in app/assets and app/javascripts.

The directory app/assets is handled by a tool called sprockets that we want to change in future. The directory app/javascripts is handled by another tool called webpack.

Why we have 2 directories with differents tools ?

Historically, we used only the directory app/assets for all javascripts, css and images files. Sprockets was used to apply some transformation on all those files.

We can consider sprockets as a "pipeline tool", so the thing is that all assets go through a pipeline in which we apply some treatments

For example, in production, the javascripts are handled this way : All Javascripts files present in app/assets/javascripts are first merged in one big file, then minimification treatment is applied (removing all comments, all blank lines, whitespace, etc). Then uglification is applied to this file (uglification in javascript consists in renaming all variables and fonction with a shorter name, usually only one letter). The ouput of the whole pipeline is only one javascript file, that is lighter (is term of size) than input files. Last thing, this javascript file is linked into app/layouts/application.html.erb with this line :

<%= javascript_include_tag 'application' %>

Today, sprokets is not a good tool to do that. It's not really maintened anymore, and the really bad thing with sprokets is that it does not handle es6 for javascript. So if you write es6 in app/assets/javascripts, it will break for some treatments of the sprokets pipeline.

So, the new tool that is really good for today javascripts is webpack. It's just another tool that we can use to create a pipeline with some treatment. For example, in webpack, we can apply a treatment using another tool called babel. Babel is used to transform es6 to es5. Also, even without babel, webpack handle nicely es6.

So, you shouldn't write es6 in app/assets/javascripts, but in app/javascripts, because this directory is handled by webpack, not by sprokets.

The output of the webpack pipeline is linked into our application in the layout with the line :

<%= javascript_pack_tag 'application' %>

For our css, we write scss files in app/assets/stylesheets, and those files are handled by sprockets, and are transformed in real css, not scss, to be able to be read by the navigator (it doesn't read scss).

Envrionments

The thing is that we want to have 2 differents behavior in production and development

Development

In development, we want javascripts to be easily debbugable. Then, we don't want merge / minification / uglification treatments to be applied in dev, to be able to have the correct line number in the correct javascript file when an error is trigged.

It's the same thing for css.

In development, sprockets and webpack generates the output file on the fly, for each request. It for this reason that when we update some scss and reload the page, it needs some time to re transform scss to css.

Production

In production, we want to link only the minimum amount of file in our app, to avoid the navigator to have to make too much HTTP requests to get all assets linked to our app. Also, we want the files we link to be as small as possible (thanks to minification and uglification). In production, we're not debbugging anymore, so no need to have correct line number for example.

And in production, we're not changing scss and javascripts files, so we don't need an on-the-fly generation, but we need to generate one time corresponding javascript and css files, and link it in our layout.

When we deploy, on heroku automatically launch the command rake assets:precompile. The job of this command is to generate one Javascript file and one css file from all our assets, using either sprokets or webpack pipelines. The resulting files are stored in public/assets directory. And the links in our layout are pointing to this files.

Then, if you write some es6 in app/assets/javascripts, then this command might fail, and you should see in heroku logs something like assets precompilation failed.

To debug that, you can launch this command in your local environment. Then, to cleanup generated files, you have to run rake assets:clobber. If you forget to remove the compiled files after have launched a rake assets:precompile, the compiled files will have priority compared to on-the-fly generation, so the changes that you can do in your scss files won't be reflected, so don't forget to remove compiled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment