Rails Performance: How To Load Images Faster

Recently, I ran into the problem that my image heavy website, patagoniaonabudget.com, was loading extremely slowly. In this post, I outline the steps I took to go from a 6 second load time to under 2 seconds, specifically focusing on image rendering. 

Page Load Time Chrome Extension

First, I installed the Page Load Time Chrome Extension. This provides a constant reminder of the page speed when working in both development and production environments. One thing to keep in mind is that you should flush the browser cache (Command-Shift-R on Mac) when evaluating load times multiple times in the same session. 

Precompile Assets 

The first step is a rather simple one: rails assets should be precompiled before deploying, enabling easy access for the asset pipeline. This is one of the biggest quick wins you can assign to any rails application. 

RAILS_ENV=production bundle exec rake assets:precompile

My site was much faster last year and I hadn't added much additional functionality, so I was really curious as to why it was loading slower. Turns out, you should run this command every time you add a new asset, otherwise it won't be in the precompiled version of the asset pipeline. 

It's also vital to run this with the RAILS_ENV=production tag, as that targets the production assets (totally different files from the development assets). 

This reduced my load time to about 4.5 seconds. Not too bad, but still not good enough for my taste.

Minify Images

The next step is a no-brainer for any image heavy website: minifying the images! By tracking the page load time using Chrome developer tools (just click on Network and then refresh the page), I was able to identify that some of my images were taking more than 2 or 3 seconds to load! 

This is especially crazy considering that this picture is never rendered larger than 500px by 500px. So, first I cropped the images to be significantly smaller, then I passed all of them through JPEGMini, a tool for (almost) lossless compression. 

At this point, I was under four seconds. Getting there! 

Move Static Assets To A CDN 

Most of the images on this site are static, so after doing some research I decided to migrate them to an Amazon Cloudfront CDN. The benefit of this approach over a normal S3 bucket is that Cloudfront is optimized for asset retrieval, whereas S3 is for uploading, storage, and retrieving. 

Heroku provides an excellent tutorial for implementing this functionality. Basically, you just need to setup the Cloudfront service, then navigate to config/environments/production.rb and add your new URL as the asset_host. 

config.action_controller.asset_host = "<YOUR DISTRIBUTION SUBDOMAIN>.cloudfront.net"

One thing you should keep in mind is that if you setup this section incorrectly, you'll lose access to all assets (CSS, Javascript, and images). It's best to test this functionality on an acceptance environment first if you've got an app that needs zero downtime. 

Once you've deployed everything to production, you can easily check if the CDN has been implemented by clicking on "View Page Source". Here, all of the images will now point to a Cloudfront URL, like so: 

<img src="http://d2wb183l8ikp47.cloudfront.net/assets/cover-min.jpg"/>

When I was finished with this implementation, my website was now loading at 1.9 seconds without cache. 

What's Next? 

In the process of evaluating the loading times, I was able to identify that even after these performance improvements the website still loads way too slowly on a poor connection. By throttling the data flow to a normal 3G connection, it now requires almost 10 seconds to load!

There's a lot more I can do to improve the performance of the website. I'd like to set up custom HTTP Cache Headers, identify and remove unused CSS, and maybe even create a special "lite version" that gets rendered when the connection is really bad. 

Do you have some more suggestions? Questions about the techniques in this post? Let me know in the comments below!