Bundling Javascript and CSS resources with Jawr

On the surface, Jawr is a resource bundling library for Java web-apps with an incredibly confusing name (try saying “Put the Jawr JAR in the lib dir” a few times out loud…). The project website has this to say about it:

Jawr is a tunable packaging solution for Javascript and CSS which allows for rapid development of resources in separate module files. Developers can work with a large set of split javascript files in development mode, then Jawr bundles all together into one or several files in a configurable way.

Jawr allows you to keep your Javascript and CSS files separated and organized within a project, while still taking advantage of resource minification, concatenation, compression and caching (ie. bundling).

But why should I bundle my resources anyway?

Because for every shiny presentation effect there’s an HTTP request, and sometimes those requests are BIG. I’ve been recently working on a project that pulls in a number of Javascript data visualization libraries, none of which come cheap. The project is behind authentication and not exactly intended for public consumption, but here are some screenshots I pulled from Firebug’s net tab.

First the CSS:

Uncompressed CSS: 5 requests @ 40k

5 resources weighing in at 40k. Not terrible, but that’s a lot of requests for just the CSS. Every single one adds overhead that stands between the report and its intended viewer. Since this is a screenshot from my development environment, the timeline may be a bit misleading, but in this case loading these resources probably won’t take up enough time to be any real concern.

The Javascript on the other hand…

Uncompressed Javascript: 6 requests @ 340k

6 resources and 340k! Even on a fast connection this is going to take a few seconds to come down the wire. These requests are intentionally made after the rest of the page has loaded, but a good chunk of the functionality relies on these scripts; until they load the visitor is going to be staring at a sweet-looking UI without any real way to interact with it. Worse still, as the project grows so grows the resources; bundling just became important.

Jawr to the rescue

There are plenty of ways to manage the size of your resources:

  • Concatenation, or smooshing all of your resources into a single massive file.
  • Minification, aka “hope you weren’t planning to make any changes to that script”.
  • Compression, which often means run-time decompression. I’m talking Packer, not GZip (which is awesome).

For the most part these are fantastic in a production environment, but while I don’t have the benefit of your own experience to draw upon, in my experience the only kind of project that isn’t constantly being reworked and redeployed is a dead one. While Jawr is one of many ways to achieve the best of both worlds &mdash& a clean development environment and compact production resources — I really appreciate how simple it is to configure and maintain.

Configuring the servlets

Every CSS and Javascript request needs to go through Jawr in order to take advantage of bundling. When a request is made, Jawr will decide (with help from your config file) whether to respond directly with the resource, or to perform an operation on it first.


  JavascriptServlet
  net.jawr.web.servlet.JawrServlet
  
    configLocation
    /jawr.properties
  
  1

 

  CSSServlet
  net.jawr.web.servlet.JawrServlet
  
    configLocation
    /jawr.properties
  
  
    type
    css
  
  1

 

  JavascriptServlet
  *.js

 

  CSSServlet
  *.css

Configuring jawr.properties

You can set up as many bundles as you need here, eg. a core bundle that is used throughout your project and a few context-specific bundles if you need them. Jawr lets you make considerations for which resources should be bundled in which order and which resources should be spared the compression algoritm. Depending on how complicated your bundles are, this file can get pretty hairy. For clarity, the following shows only the configuration for my project’s core Javascript bundle. There’s plenty of documentation to follow at http://jawr.java.net/docs/custom_bundles.html.

One thing to note is that every request for a bundle will be routed here. When debugging in your development environment, it’s best to flip the jawr.debug.on property to true. Jawr will then serve up all of the uncompressed resources that would have appeared in the bundle.

# Common properties
jawr.debug.on = false
jawr.gzip.on = true
jawr.gzip.ie6.on = false
jawr.charset.name = UTF-8

# This is the root dir for all our javascript resources.
jawr.js.bundle.basedir = /js

# Define the core set of scripts for use across the platform.
jawr.js.bundle.core.id = /bundles/core.js
jawr.js.bundle.core.composite = true
jawr.js.bundle.core.global = true
jawr.js.bundle.core.child.names = jquery,dependencies

# No need to compress pre-compressed scripts, just add them to the bundle.
jawr.js.bundle.jquery.mappings = /js/libs/jquery-1.4.4.min.js,\
                   /js/libs/jquery-ui-1.8.9.custom.min.js
jawr.js.bundle.jquery.bundlepostprocessors = none

# These guys are part of the core bundle too...
jawr.js.bundle.dependencies.mappings = /js/libs/OpenAjaxManagedHub-core.js,\
                   /js/libs/IntelReports/IntelReports.js

Adding Jawr to the JSPs

Jawr comes with a small taglib for use inside of an application’s JSP files. The jwr:script and jwr:style tags will interpret Expression Language natively, and simply refer to a bundle definition within jawr.properties before handling the request.

<@ taglib uri="http://jawr.net/tags" prefix="jwr" %>

The payoff!

With bundling enabled, the application sees a dramatic benefit.

Compressed CSS: 2 requests @ 6k

CSS Just under 6k! It wasn’t huge before, but it’s certainly not causing any trouble now. In fact this same project is using sprites that come in larger than the CSS that drives them. Maybe something to investigate another time!

And the Javascript?

Compressed Javascript: 2 requests @ 60k

60k is certainly a reasonable size for some pretty large libraries, and represents an incredible more than 80% savings over the uncompressed example. Jawr does allow you to specify which minification method to use, and it’s certainly worthwhile to play around and see which options work best for your project. These figures came from a quick default integration, and I couldn’t be happier with the way things turned out.