I have written before about GWT code splitting, a cool feature available in GWT.  While I am definitely no expert, it seems to be different that options offered by other, comparable web toolkits.  Just doing a quick survey (thanks, Ajaxian!), there seems to be a lot of code compilation happening.  Some of it is at deployment, pruning unused library code (like here, and here).  Some of it is aimed at making whatever javascript you write, better (like this and this).  There’s even tools aiming to document (in json) all javascript features supported by browsers, so that you can intelligently target user agents.

GWT code splitting is different from all of that.  It is developer determined split points in javascript code.  A developer says, essentially, all code after ‘this call’ should be downloaded and made accessible to the runtime when ‘this call’ is made.  More at the canonical reference; you should read this multiple times if you want to really understand code splitting.

As the document above mentions, “effective code splitting requires iteration”.  I’ve spent a fair bit of time in the last week doing some code splitting, and wanted to share my punch list (and build on my previous code splitting post).

First, understand the three major types of chunks your code will be split into.

  • Initial download
  • Leftover code
  • Exclusive fragments

The document above has a great diagram, which also includes other types of code which I have not run into.   The important thing to realize is that minimizing the initial download is important, but if any of the exclusive fragments are download, the leftover fragment will be downloaded.  Therefore, a better goal is to maximize the exclusive fragment size.

Here are places places to put split points, in order of preference

  • subsystems easily isolated (encryption library, etc).  Consider using the AsyncProxy, which is a great way to hide a subsystem
  • user actions (onclick events, etc).  Be aware of latency when toe code is downloaded and executed
  • when enabling spans are present

Use GWT.runAsync directly.  I tried to get all fancy with commands and abstracting it away, and didn’t have much success.  You can surround it with a timer, though, and that
may make sense when you are using an enabling span.

if (span is present) {
Timer t = new Timer() {

@Override
public void run() {
GWT.runAsync(new RunAsyncCallback() {
public void onFailure(Throwable caught) {
// handle error
}

public void onSuccess() {
foo();
}
});
}
};
t.schedule(150); // wait 150 ms before trying to download this code
}

You will spend a lot of time compiling, so only target a few browsers for compilation.  When I added the -compileReport option, the compile time for the main module went from 2 minutes to 8 minutes.  However, once you have the url for the compile report (something like /extras/modulename/soycReport/compile-report/SoycDashboard-0-index.html) you can actually see the results about a minute in.  At that point, you can stop the compile process.

Method call hunting will make you love your IDE java method search (control-H in eclipse–here’s a useful cheat sheet)

Watch out for constants and static methods.  In fact, I end up pulling out my constants to a class shared between GWT and my java server so that I can name spans like this
<div id="<%=Constants.SCROLL_ANCHOR_ID%>"></div> and be assured that GWT components will always be able to attach to those spans.

If module A is called by module B, C and D, avoid putting the GWT.runAsync calls in modules B, C and D.  This would force module A into the leftover code chunk, increases the number of split points, compilation time, and memory needs.  Instead, put the GWT.runAsync calls into module A, which pushes all that code into an exclusive chunk.  If you have a bunch of small splits points in your compile report, look at it carefully, especially if they are in the same class and see if you can push the split points back into the common code.

Code splitting failures (onFailure) should be dealt with the same way any remote access failure is dealt with in your application.  I haven’t found a more intelligent method than informing the user that the operation failed, however.

Set goals for splitting and try to avoid getting sucked in.  Because it is an iterative process, you can end up spending a lot of time with this.  Sometimes changes can have counter intuitive side effects, so make sure you track both total, initial and leftover code chunk sizes.

This post was based on a system with total obfuscated code size of approx 750kb, compiled using GWT 2.1.1.


© Moore Consulting, 2003-2019