Using Far-Future Expires for Static Resources

Creating a high-performance website can be tough, especially if you have a lot of resources (CSS, images, and JS) on your site. Seller’s Market’s home page weighs in at a hefty 992.56KB right now, but if the page is refreshed, only the HTML document needs to be downloaded again (at 17.60KB); 98% of the resources used to make up the home page are kept in the browser’s cache. In this post, I’ll dive into the implementation details behind what makes this possible.

Yahoo’s “Add Expires or Cache-Control Header” recommendation is the driving force behind what makes this possible. The recommendation suggests adding an Expires or Cache-Control header to responses to tell the browser how long a resource can be cached. If you tell a browser that it can cache a resource for ten years, it probably won’t need to download the resource again if it’s in the cache. This is exactly what’s happening on Seller’s Market; each resource can be cached for up to ten years, so subsequent reloads or going to a different page can reuse items in the cache (and since multiple resources are used across pages, this means less needs to be loaded for subsequent page loads).

The big catch to this is invalidating the browser’s cache; if it has a cached version of “/home.css” that it can use, it’ll use it. If you update home.css, you’ll need to make sure the browser downloads the new version.

In the interest of keeping things simple, the easiest way to do this is to change the URL of a resource when the resource changes. For example, the “/home.css” file might be called “/home-1.css” and change to “/home-2.css” when it’s updated. Since the URL changed, the browser won’t have a copy in cache and will download the updated resource.

I went through a few ways of doing this, but I settled on the following method: whenever a resource changes, a script is run to minify any changed resources (with Minify), the minified resources are then saved to disk with a hash of the resource’s contents appended to the filename, and a manifest is created that contains all of the original URLs and all of the versioned URLs. I’ve found this solution optimal because it allows each resource to be versioned separately, it lowers the dependencies for serving the files (a simple HTTP server is all that’s required), and the manifest file allows the original URLs to be used in code.

The manifest file is used in any code that needs the URL to a resource. I can simply look up the current versioned URL (e.g. “/home-3.css”) by supplying the original URL (e.g. “/home.css”), so I don’t have to change any URLs when the resources are updated.

The end result is that each resource gets served with an Expires header with a long time and the browser can hold onto the resource for as long as its cache can handle it. If there’s a change, a simple recompile will update all of the appropriate resources, and only the changed files will be downloaded by the browser, creating a better experience for your users.

0 Responses to “Using Far-Future Expires for Static Resources”


  • No Comments

Leave a Reply