Code splitting is one of the features of GWT that make it worth your while. See, using GWT is really a choice–do you want to use one of the lightweight javascript libraries like jquery, with all the agility that implies, or do you want to use GWT which lets you leverage all kinds of java tools and optimizations, but saddles you with a compile cycle?
I’ve talked before about the situations that I think are good fits for GWT. I just re-read that post and don’t feel that things have changed too much in the past 3 years, though I might argue with point 4 of that post. Code splitting is an optimization that would be hard to do with a more normal javascript library (dojo has something like it, but it looks like you are responsible for maintaining dependencies).
I talked before about code splitting, and how it is a great fit for the widget based html enhancing GWT development that I’ve done a lot of recently. I wanted to talk a bit more about my process for finding code to split.
With code splitting, the main goal is “never have the user download javascript that isn’t used”.
The first thing to do is run your GWT compile with the -compileReport option, as outlined here. This will show you your module code, and therefore let you focus your effort where it makes sense.
The second thing to do is to find code dependencies. The compile report shows you that in a text format if you navigate all the way down to the class level in a class that is downloaded in the inital fragment via the “see why” link. I had a hard time understanding those dependency lists, so I went looking for a tool to help. After trying a number of open source dependency analyzers, I stumbled on the Class Dependency Analyzer (CDA) which is free as in beer, not as in speech. The key difference between this tool and others was its included dependency graphs. You should set CDA up to ignore all the google code, as well as any third party tools you have. More documentation on CDA here. (This is another example of leveraging java’s tool set.)
Using CDA, you can see which packages (since modules are grouped in a java package) have dependencies on others. Packages that don’t have dependencies on any of your other packages are great candidates for code splitting, as well as packages that depend on other packages that are code split. However, if your packages depend on utility classes, especially those that share business logic between client and server side code, that’s OK. (This exercise can also help in general code quality.)
Now you have a number of candidate modules. The next thing to do is dive into the code and see if these modules execute on every page. If they do, then doing code splitting is not a win. All you’ve done is forced GWT to make an extra network call. If, on the other hand, this code only executes when someone clicks a button or takes some other action, then you have a great candidate for code splitting. And if the module only executes on certain pages (perhaps using a DOM element to signal whether it should execute or not), you have a good candidate–because with splitting that code will never be download on pages where it is not used.
Now, add the following code around the candidates:
GWT.runAsync(new RunAsyncCallback() { public void onFailure(Throwable caught) { // handle error } public void onSuccess() { // do something } }
I actually added this code block to my eclipse templates ( more on templates here) so it is super easy to set up a split point. Note that I haven’t found a generic good action to take on failure. For most widgets providing enhanced functionality, a safe fallback might be to just let the HTML execute. A custom message display might be ignored, and using Window.alert
can confuse your users (and lock up a browser for a time if all of your code or the network suddenly becomes unavailable).
The next step is to run the compile report again and see if the GWT compiler agrees with you that your candidate code is not reachable by any other path. If it does, you should see split points show up underneath the permutations menu. (BTW, the -compileReport flag easily doubles or triples the time it takes to compile GWT–I’d recommend focusing on one user-agent and doing other things to speed up your compile, as outlined here.) You can also test this by just compiling your GWT without the -compileReport switch and looking under the deferredjs directory; it is quicker but doesn’t help you determine which modules are being downloaded. Firebug also lets you see the files downloaded on demand.
I was able to decrease the initial download size of a project I’m working on by 20%.
I’ve mentioned the caveats before but they are worth mentioning again.
- The XS linker is not supported, so if any of your XS modules depend on a module which has code splitting, you’ll find out when your GWT does not compile. However, there is hope–code splitting support for the XS linker is apparently coming with GWT 2.1. If you need this functionality, vote for the bug. There are some work arounds in the meantime, but they involve a fair bit of hoop jumping so I’m going to avoid documenting them.
- Events that happen before code is asynchronously downloaded are not propagated to that code.
Given the second issue, it’s important to test your code and make sure that the behavior is unchanged. That’s the final step.
I hope this was a useful tour of the GWT code splitting process.