In my last blog post I described the new DependencyHandler service that has recently been added to Spring Surf. Whilst its primary purpose was for appending checksums to JavaScript and CSS dependency requests to ensure that browsers did not use stale cached data, it does have another interesting capability.
Enhancing the performance of web applications has become increasingly important as they have become increasingly complex. Ultimately most of these performance enhancements boil down to either reducing the amount of data required to render a page or reducing the number of HTTP requests required to download that data. Minifying text based resources and the use of GZIP on the server are obvious examples of reducing bandwidth and whilst minifying images is not an option (beyond regular compression) you can reduce the number of HTTP requests required by using CSS sprites. This is all well and good if you’re starting a new web application from scratch and can make sure you adhere to all the best practices from the start, it’s not always so easy to retroactively apply these practices to a mature project. Share makes good use of minification but there is scope to improve the number of HTTP requests made for resources.
One of the big advantages of Share is how easily it can be customized to satisfy requirements but the disadvantage of this is that we need to do our best to support all the various customizations that exist out in the wild. So whilst we could spend a long time converting all of our individual images into one giant CSS sprite there’s a very good chance we could break a lot of other developers customizations.
Another option that is available is to actually embed the data for each image into the CSS files that reference them. Whilst not wanting to get involved in the various discussions about which approach is better, based on our requirements it is clearly the better choice for us.
Surf can now automatically produce CSS data images by simply adding the following line to its configuration file (for Share this is located at this can be found in the “webapps/share/WEB-INF/surf.xml”)
<web-framework>
…
<generate-css-data-images>true</generate-css-data-images>
…
</web-framework>
Providing that checksum dependencies are also enabled then all images reference by CSS files will be embedded as data within those CSS files. This offers the additional benefit on top of the reduced number of HTTP requests in that when an image changes, the CSS checksum will change so it will not be possible for the browser to use stale cached images. The DependencyHandler service defers some of this work to a dedicated 'CssDataImage' service which can be overridden in the Spring application context if required. All images are cached for the life-cycle of the server so that performance is not impeded when requesting the same image multiple times.
The following screenshot shows the Chrome Web Developer Tools displaying some images from a page in Share with CSS data images enabled:
The main limitation as far as Share is concerned is that we haven’t used CSS styles throughout the application. There are still some uses of the <img> HTML element which won’t be affected. However, at the end of the day there will be less HTTP requests than before so hopefully performance should be improved as a result. The only other limitation is that CSS data images are not supported by Internet Explorer versions 6 and 7 (but then if you're still using either of those then this will be the least of your performance concerns!) so Surf will check the user-agent data though and not perform the conversion for those browsers.
More information on CSS Data Images can be found here: