Archive for August 26th, 2008

A Grails UI Performance Plugin

Tuesday, August 26th, 2008

I wrote up some notes in my previous post about some recent work I’ve done implementing the Yahoo Performance Team’s 14 rules for UI Performance. We’d talked at work about making it a plugin, but I wasn’t sure if it was sufficiently different from the excellent Jawr plugin to justify it. So I took a look and I think that my approach has some benefits that do justify a second plugin.


One significant feature that I’m providing is versioning and far-future Expires headers and caching for images in addition to JavaScript and CSS. Of course images aren’t very compressible, so gzipping them doesn’t make much sense, but the image payload of most sites is going to be a lot larger than that of the .js and .css files, so it makes sense to try to get clients to cache those also.

Another is a taglib that helps keep javascript at the end of the page. Sitemesh gets in the way here – there can be a lot of code in your layout GSPs after the layoutBody call, so DependantJavascriptTagLib allows you to define one or more hidden JavaScript declarations in your GSPs and render them all from the layout at the end of the body (Sitemesh has “content” tags that support this but there’s a bug where script tags lose their opening bracket so I’m using a technique borrowed from here).

Finally there’s simplicity – this was designed as a Grails plugin, so it has a more focused feature set and has fewer moving parts, preferring convention over configuration.

Having said that, there are advantages and disadvantages of both approaches:

Reasons to use Jawr versus using this plugin:

  • a lot more features, e.g. I18n, DWR, and JSF support, choice of minification approach, etc.
  • more configurable, e.g. exclusion lists – I gzip/minify/version everything
  • it’s not Grails-specific, so the time you spend learning its features will be useful when you want to use it in non-Grails apps

Reasons to use this plugin versus using Jawr:

  • the bulk of the work is done during the build, so no temp files, everything is in the war and problems are caught during the build instead of after deployment
  • it versions and sets Expire on images, and rewrites inner urls in css files to point to versioned images
  • supports Sprites via a taglib
  • helps move JavaScript to the end of the body via a taglib
  • doesn’t use a servlet – only a few taglibs and a Filter, letting the container continue to serve static resources
  • less processing at the server – it only needs to check if client supports gzip when rendering <javascript>, <css>, and <img> tags in GSPs
  • more Grails-friendly – in development mode it does nothing, and is only enabled in production mode, so there’s no need to check for modifications since Grails doesn’t support that in production mode

So as you’ll see from the code, there’s not much to it:

  • the plugin script wires up a simple Filter that adds caching headers in production mode
  • an Events.groovy script hooks into the war building process and gzips/versions/minifies static resources before the war file is packaged
  • and five taglibs handle the work of inserting the correct version and paths for resources, choosing to render the path to the gzipped files if the client supports it

Downloading:

You can download an early version of the plugin here, and a sample app demonstrating its use here. I’m waiting on some feedback before I put it up at plugins.grails.org since it’s still got some rough edges. Note that they’re configured as Eclipse projects but I’ve removed the Grails classpath jar entries and replaced them with a User Library called ‘grails’ to simplify the classpath. Either create a similar User Library (just include everything in GRAILS_HOME/dist and GRAILS_HOME/lib) or just re-add those jars explicitly like you’d have in a regular app.

Testing it out:

First run “grails run-app” from the performance-test project. It’s a basic app with one domain class, but the point is to show that in development mode it functions just like an app without the plugin – it serves the files from the file system unchanged and with no extra headers.

But if you run “grails war” and deploy the war in a servlet container (I’ve only tested Tomcat 6.0.16) then you should be able to view the source and see that the .js and .css files, plus all images have versions embedded in the urls and the .js and .css are gzipped and minified, and that the appropriate caching headers are set. The source files are unchanged – you still get to develop with readable files, but when deployed in prod mode, the app is a lot more efficient.

Note that there are very few image files since most are rendered using sprite1.gif via CSS. Also check out http://localhost:8080/performance-test/sprite/index (and views/sprite/index.gsp) for an example of an inline image from a sprite, plus an example of deferred JavaScript.

To install the plugin in one of your apps run

grails install-plugin http://burtbeckwith.com/blog/files/68/grails-ui-performance-0.1.zip

Let me know about issues you find or questions you have.

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.