· Hugh Evans ¶
Asset Pipeline Tips
After speaking to a few of the attendees at Red Dot Ruby Conf a few weeks ago in Singapore I promised them I’d document the techniques we use at Icelab to get the most from Rails asset pipeline. So here it is.
If the gem does not have any functionality that needs to be run on the server then we place it in the assets group. I’m repeatedly seeing some of the below gems in the main group of gems in some people’s projects. This was likely because of bugs in earlier versions of the asset pipeline which don’t exist now.
group :assets do gem 'bootstrap-sass' gem 'coffee-rails' gem 'compass-rails' gem 'jquery-rails' gem 'sass-rails' gem 'uglifier' end
Just a note about compass-rails. If you’re upgrading this library from an older version you’ll be happy to know that a config file is no longer required for standard functionality.
By default there is a compiled
application.js and an
application.css. We typically expand on this in
application.rb to something like:
config.assets.precompile += [ 'admin.css', 'admin.js', 'fallback_jquery.js', 'modernizr.js' ]
We have the
admin.css files in
As you can see we first attempt to load jQuery from the Google CDN and if that fails to load in 3 seconds it requests the local fallback version. Because we have the jquery-rails gem all that is required inside the
//= require jquery
Why not just add
jquery to the list of precompiled files you ask? Because we simply wanted to be specific about it’s purpose. Which leads me onto the next point. Rename your vendor JS libs for consistency. Rather than just sticking
jQuery.whizbang-2.213.js in the vendor directory and doing
//= require jQuery.whizbang-2.213 call the file
jquery_whizbang.js and paste in the non-minified version that includes the headers/version information. Having the vendor files named in a consistent fashion to the rest of your Rails application makes things a lot tidier.
Sprocket Requiring Files
We tend to stick to the simple
//= require x command and not
require_tree as it pays to be specific about load order as it will inevitably bite you one day. We leave the application JS/CoffeeScript files in the root of
//= require admin/file. All the vendor JS libs get renamed for consistency and placed in
application.js, some in
admin.js and some in both.
Do not sprocket require CSS/SASS files. Only use SASS
@import. Any vendor CSS we wish to use we place in
vendor/assets/stylesheets, rename for consistency and add a
In most situations these days we use the fantastic
asset_sync gem to upload our assets up to S3. It is all pretty straight forward and the gem is very well documented, just be sure to enable gzip compression as it will make a big difference to the S3 download sizes.
In the next section I’m going to detail how we precompile assets locally and if you choose to go this route then you can place the asset_sync gem in the Gemfile’s
assets group as it needn’t run on the server. Then in the asset_sync config initializer you need to wrapper everything in an
“man, that rake assets:precompile is so speedy, especially when I’m deploying a hot fix” - nobody, ever.— Matt Allen (@mattallen) May 27, 2012
This seems to be the biggest grievance amongst the people I have talked to about the Rails asset pipeline. When pushing to Heroku either the precompilation of assets fails completely or it simply drives them insane with how long it takes to deploy. Especially so if they are only wanting to deploy a quick code fix as Matt alludes to in his tweet. The technique we have come up with, and we acknowledge it isn’t perfect, is to force git add the
pubic/assets/manifest.yml while still git ignoring the entire
public/assets directory, and then running
rake assets:precompile locally which uploads to S3 with the asset_sync gem. Next you will be required to commit any changes to the
manifest.yml and then you are good for a deploy. When pushing the code to Heroku it will detect the presence of the
manifest.yml file and will now not attempt to precompile the assets.
From our experience this workflow is much more reliable. It is however a bit of a pain remembering to precompile the assets and commit the changed
manifest.yml when you have been working on them. It is a huge win though for speeding up quickfix code deploys, so we think it is worth it.
These are the notes we throw into the Readme of every project where we use this technique:
## Asset Compiling Assets are precompiled locally and automatically uploaded to 3S with the `asset_sync` gem before deploying with the command: bundle exec rake assets:precompile For this to work you need in place: * The `config/config.yml` file with the AWS details (see `config/config.example.yml`) * A production database connection adapter (see `config/database.example.yml`) Following compilation the `public/assets/manifest.yml` will have changes in git which need committing before deployment. The compiled files will be in public/assets but they are git ignored. **Note:** when developing locally if there are files in `public/assets` they will get loaded so you won’t see your changes (not good). To fix this: bundle exec rake assets:clean && git checkout public/assets/manifest.yml When deploying/pushing to Heroku it detects the presence of the `manifest.yml` file and does not attempt to compile the assets itself. The `asset_host` has been set to the S3 domain in `production.rb`.
Feel free to copy it into yours.