GWT code split is awesome

For the past few days, I’ve been working on code splitting our existing GWT application. The application is fairly big with about 20k loc (excluding javadoc, comments and tests). The download size (with obfuscated mode) is about 1.5M, and with pretty mode, is a whooping 10+M. Obviously this is not acceptable.

GWT2 provides developer guided code splitting feature. It sounds complicated and under the hood, it may very well be (involves a lot of graph theories to figure out dependencies and so on) but from the user’s point of view, it’s very easy. You just have to wrap your potentially big operations in a GWT.runAsync() call.

However, since our application is using GWT best practices (dependency injection, MVP pattern), it’s not as straightforward as GWT doc describes. A bit of digging on the internet leads me to this page http://code.google.com/p/google-gin/issues/detail?id=61

Gin patch

Someone contributed a patch to gin, which made split points transparent to the user of gin. The presenters that aren’t needed initially can be wrapped in an AsyncProvider<T> instance – which by the blessing of deferred binding, translates into a GWT.runAsync call in the generated code. The patch hasn’t been accepted into gin’s trunk yet, but it’s fairly easy to apply the patch and rebuild. A huge thanks to fazal.asim who hacked and contributed this patch.

Results

The result of code splitting is encouraging – with very little structural change, we’re able to reduce the initial download size to 29% of the total size:

Changes

I mentioned we needed very little structural change, but we did have to change something around. This is because with code splitting, the presenters that are split out from the initial download are not instantiated until they’re used/downloaded. This means you cannot put logic in their constructors, and responding to place change has to be initiated by the container presenters.

Improvements

Code splitting is awesome. However, if I’m allowed to voice a complaint, the report compiling time is just excruciating! For our application, it usually takes about 10 minutes to compile SOYC report – maybe a few minutes too long given the specs of my machine isn’t too bad (Quad Core, 3G memory). Also, the compiled SOYC report takes up 600M of hard disk space! Ouch! Maybe instead of emitting HTML pages, they can make SOYC report a JS application, with data being encoded in JSON format?

Anyway, this doesn’t take anything away from the awesome job GWT team has done for developers.

Follow-up

Thanks to AsyncProxy, which provides a blocking (synchronous) interface while utilizing GWT.runAsync. This way, I’m able to build a view proxy that implements the same interface while keeping the real view components out of the initial call graph. The result of this, is a further reduction of the initial download size.

The initial download size is 13.77% of the total code size! Sweet!

Setting up GWT2 project with gwt-maven-plugin

GWT2 offers a lot of exciting new features: OOPHM, SOYC, code splitting, declarative UI, to name a few. This evening, I experimented setting up a GWT2 project using Codehaus’s gwt-maven-plugin.

I’m using Eclipse, so obviously, you need m2eclipse and Google Eclipse Plugin. First step is creating a Maven project:
File->New->Project…->Maven Project

In the archetype selection dialog, select org.codehaus.mojo.gwt-maven-plugin:1.1.

We choose this to create an archetype but 1.1 doesn’t work with GWT2. Later on, we will modify pom.xml to use another version of the plugin.

Enter your project’s GroupId, ArtifactId, Version, and Package -> Finish

The plugin generates an archetype of GWT 1.6 project. In Eclipse, open pom.xml. As stated earlier, gwt-maven-plugin 1.1 doesn’t work with GWT2. You need 1.2, but since 1.2 hasn’t been released, we will use the snapshot version. The snapshot version is hosted on codehaus’s snapshot repository, so we need to add the repository first.

Id: codehaus-snapshot-repository
Name: (anything you like)
URL: http://snapshots.repository.codehaus.org

Then, change the version of gwt-maven-plugin from 1.1 to 1.2-SNAPSHOT

Also, you need to specify the module and runTarget in the configuration of the plugin, something similar to the following:

		<plugins>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>gwt-maven-plugin</artifactId>
				<version>1.2-SNAPSHOT</version>
				<executions>
					<execution>
						<goals>
							<goal>compile</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<module>com.mycomp.demo.mygwt2.Application</module>
					<runTarget>com.mycomp.demo.mygwt2.Application/Application.html</runTarget>
				</configuration>
			</plugin>
  </plugins>

Save the pom. Eclipse will be busy fetching the dependencies and building the project.

After it’s done, it’s time to create launchers.

Right click on pom.xml, Run As->Maven Build…, in the Run Configurations dialog, put “gwt:compile gwt:run” as the goals.

Hit “run”, GWT Development Mode application will appear.

The final missing piece is the debug mode. One of the advantages of using GWT is developing AJAX application with existing Java tooling. So let’s go ahead and set it up.
Right click on pom.xml->Run As->Maven build…
In the following dialog, enter “gwt:debug” as goals, save it.

Click on the dropdown of the debug button on the toolbar, select “Debug Configurations”.
In the left panel, find “Remote Java Application”, select it and click the icon for “New launch configuration” (top left corner). Accept defaults, save, and close.

Put a breakpoint at Application.onModuleLoad(), start the debug server by running the debug launcher we just created. (the one with goal gwt:debug). When you see “Listening for transport dt_socket at address: 8000” in the console output, run the attach launcher we just created (the remote debugger). The GWT Development Mode app pops up. Because GWT2 uses OOPHM (Out Of Process Hosted Mode), you need to copy the start URL and paste it in a browser (I’m using FF). If it’s the first time you run hosted mode like that, you will be asked to install a Firefox plugin. After it’s installed, paste the URL into the address bar. If everything goes well, your breakpoint will be hit.

There you have it. A sample mavenized GWT2 project. Enjoy the goodies offered by both GWT2 and Maven!