Serving Compressed Assets With Heroku and Rack-Zippy
Share
It’s often a little known fact that Heroku does by default , NOT serve the compressed version of your assets to the client browser.
Often it’s all too easy to get lost in the magic that is Heroku slug compilation and the simplicity of a “git push heroku master” code deploy that we forget the basics of web development and end up serving our clients bloated CSS and JavaScript files, often at ridiculous sizes.
This is especially prominent of late with the rise of the “do it all” frameworks like Bootstrap, Foundation, AngularJS, Backbone JS etc.
Chances are, if you use any of these frameworks, you’re sending hundreds of kilobytes of code down to the browser on every request that is never even used, forcing your users to download the lot each time.
Heroku states clearly in their HTTP Routing docs:
Since requests to Cedar apps are made directly to the application server – not proxied through an HTTP server like nginx – any compression of responses must be done within your application.
So, let’s see what that looks like to the end user.
File: application.css
Size: 70KB
Time: 595ms
Here’s a typical application.css from a Rails app coming down from Heroku. We can see that the file was 70KB coming down the wire and took a total of 595ms. (The top figure is the one we’re interested in)
The fact that the 2 numbers regarding the file size are almost the same means that there is no compression or caching happening.
The top number represents the size of the file downloaded, and the bottom represents the actual size of the file. In this case the file is 70KB and the client had to download the full 70KB.
Consider how big the standard Bootstrap CSS framework is, together with an accompanying JavaScript MVC framework bundled with your own custom CSS and JS and you can begin to see how this can get out of control.
If we browse the public directory on one of our Heroku Dyno’s we can see that the compressed version of our assets are there already, pre generated by the assets pre-compilation on your last deploy, they’re just simply not being served to the browser.
Rack-Zippy
Fortunately, serving these compressed assets is pretty simple with the help of a gem called Rack-Zippy. https://github.com/eliotsykes/rack-zippy
Rack zippy is Rack middleware that serves up these compressed assets instead of the full uncompressed version, dramatically improving client download times.
To quote from the github gem page:
rack-zippy replaces the ActionDispatch::Static middleware used by Rails, which is not capable of serving the gzipped assets created by the
rake assets:precompile
task. rack-zippy will serve non-gzipped assets where they are not available or not supported by the requesting client.
Installation is simple,
Add to your Gemfile
gem 'rack-zippy'
Then from the command line
bundle install
Add this line to config/application.rb
config.middleware.swap(ActionDispatch::Static, Rack::Zippy::AssetServer)
Push to Heroku and you’re done.
Now let’s take another look at the file sizes
File: application.css
Size: 12.3KB
Time: 180ms
That’s a pretty drastic improvement. From 70KB down to 12.3KB, and this is only taking into account a single CSS file, your JavaScript will also show similar improvements.
So, before you start obsessing over excess code or removing images that enhance the appearance of your website in an attempt to increase client response times, I would first ensure you’re serving up compressed assets, it’s probably the easiest thing you can do that yields a performance gain this high.
Other Options
Another option for serving compressed assets is to modify your config.ru file to use Rack::Deflater.
I have not tested this method, but I hear it’s also another viable option.
More info can be found here: http://www.gaurishsharma.com/2012/04/enable-gzip-compression-for-rails-3-2-on-heroku-cedar.html