Josh McArthur

Dynamically Serving Inline Images with Rack

04 Mar 2011

Following an insanely interesting presentation by Steve Souders at Webstock, I began thinking about ways to simplify (i.e. automate) certain processes to optimize performance of sites. Something that immediately jumped out at me from early on in Steve’s workshop (So early, I was able to start coding in the halfway break), was that inline images were an ideal candidate for something that is relatively easy to do, but could have a significant effect on overall page load speed. The concept of inline images has been around for a while, and basically involves embedding Base64-encoded image data within the image tag like so:

So, what impact does this have on performance vs. the normal technique? Well, the normal technique involves several more requests - one per image, in fact. As Steve pointed out in his workshop, server response time is only a small part of the problem - the reality is that it doesn’t make a huge difference how fast a piece of content is processed on the server - unless you are doing something really wrong, of course. Where you can really hit performance bottlenecks is actually in the request-response transaction - waiting for data to be transmitted, received, processed, assembled, and rendered on screen. Using inline images can improve web performance when used appropriately, but as with any other performance technique, it has it’s drawbacks. First of all, because the images are actually embedded into the page, caching is affected - browsers may cache images longer than static pages, and if your web server is not set up correctly, dynamic pages may not be cached at all. Next, the relative file size of the page is not equal to the page size without images plus the combined images file size. The encoding process tends to result in about a 30% increase in size. Notice above I have said when used appropriately - this means that, despite the drawbacks above, it really can help web performance. The key to not overusing this technique is to carefully consider the boundaries of what images should be embedded - the best candidates are small to medium sized images that do not generally change much - especially if there are quite a few of them on the page and the server is slow - this means that your page load speed might be slower, but there will also be no need to make several requests once the page has loaded to draw in all of these assets. Large images, on the other hand, should not generally be encoded. There is a fine balance between embedding images into a page to save on requests, and overloading the page with embedded images and ending up with a 2 or 3 megabyte page for the client to load. Large images will shove up this page size, and in addition to this, they are usually particular files that you want to apply a different caching policy to anyway. In order to help out and generally feel good about my contributions to web performance and open source, I have actually translated what I’ve written down here into a piece of Rack middleware that creates inline images (Since I’ve come across rack-pagespeed since then, this middleware is probably superseded), and embeds them into a page. This technique was nice because a) It gave me a chance to learn how Rack middleware works with a practical project, and b) because when myself or others wish to use it, all that needs to be done is to drop the Gem into my Gemfile, run bundle install, and register the middleware in my Application’s configuration - from there on, the middleware will automatically parse responses from the Rails (Or any Rack-compatible application, actually), and replace the with encoded data. Overall, this technique is not perfect - it’s definitely not something to be overused, but with careful consideration and appropriate selection of images it’s a good stepping stone to improved web performance.