Vlad has posted 1 posts at DZone. View Full User Profile

Google Web Toolkit (GWT) compilation duration under control

03.21.2011
| 11886 views |
  • submit to reddit
If you’ve been doing some serious GWT development, then, sooner or later you’ll face a problem of GWT taking more and more time to compile your project up to the point where it becomes not reasonable. But you are not at the end of your project development yet, and there’s more and more functionality to implement to meet deadlines.

Now, if you face compilation time issues in a big project, I assume you know GWT basics. So this article is not a GWT tutorial. We'll concentrate on ways to improve GWT compilation performance to speed-up development.

You have, probably, already did your research and know how to compile your project for just one browser and one locale, you also tried compiler options like -draftCompile and some other tweaks already, but what if that is still not enough?

Separating the application in multiple GWT modules somehow lets you solve the issue, but takes away a lot of flexibility out of your architecture, requires more maintenance, complicates navigation between modules, and, after all, Code Splitting introduced in GWT 2 is much better and flexible alternative to solve JavaScript code size issue. With Code Splitting one can develop really big applications without the need to upload the whole JavaScript code to the browser at once in order for application to run. The only problem with Code Splitting – it takes even more time to compile…

The application I’m working on has close to a hundred of different screens and I do see a lot of new ones coming in.

So, here’s the solution I came to. This allows you to take GWT compilation time under control. The idea is simple. Your application has 100 screens, but during development you only need to compile the screen(s) you are actually working on, plus some number of related screens that you need to access while navigating to the screen(s), or, use them in connection with the screen(s) you are working on. Rest of the screens you do not access – so their compilation just takes your precious time away. Just the same way as unneeded locales and unused browser permutations do.

So, it would be really great to be able to exclude Java classes you do not need to access during particular development cycle from GWT compilation process. To make it easy to manage I subdivide Java classes in related groups. If I’m working on a class from group A – I compile group A’s classes, but exclude group B, C, and D classes, so this should reduce compilation time for me and make me more productive. I use term Group, to avoid using the word Module as it has some different meaning in GWT technology.

Let’s assume you develop a Web Notepad program. It’s easy to divide the application into Groups based on the top level menus – File, Edit, Format, View and Help.

Here’s what I would do.

First I create a new GWT project using Eclipse IDE with GWT plug-in which I will call Notepad. This will create the following default project in the workspace:

See "eclipse project" in article attachments. (sorry, couldn't figure how to embed the image in post's body)

This will also create the following module XML:

See "Notepad.gwt.xml" in article attachments.

Note that in order for GWT to include Java classes in conversion into JavaScript, i.e. – compilation process, they have to be contained in packages mentioned in "source path=" tags. So this way we can actually include or exclude such packages or Groups in or out of compilation process. Let’s create respective packages for each of our groups:

See "project packages" in article attachments.

Note, that these packages will not be compiled until included in module XML, so let's add them:

See "Notepad.gwt.xml.new" in article attachments.

What we want to achieve is being able to exclude either of our group sources, but be able to work with those that are still included. To achieve this we need to organize the project the way that groups do not contain compile time references to each other. Also, GWT Entry point (Notepad.java class in our case) should not have direct references to group's classes either.

To be able to do this, I create the following interface:

 

package com.careature.notepad.shared;
public interface NotepadController {
public boolean switchToScreen(String menuId, Object parameter);
}

 

See also "NotepadController.java" in article attachments.

This interface should connect application menu items (menu in this simple case could be part of com.careature.notepad.client.Notepad.java GWT entry point) with particular Group’s Java classes through menu ids i.e. – String constant.

Let’s implement some classes to show what it all means:

See "project classes" in article attachments.

As you see I implemented NotepadControllers for Edit and File groups. NotepadEditUndo, NoteadFileNew and NotepadFileOpen are java classes that do something on response to the menu action. In your application those could be just Panels that need to be placed in main application layout. Navigation controller’s code is something straightforward like this:

 

package com.careature.notepad.file;
import com.careature.notepad.client.Notepad;
import com.careature.notepad.shared.NotepadController;
public class NotepadFileController implements NotepadController {
public boolean switchToScreen(String menuId, Object parameter) {
if ("New".equals(menuId)) {
Notepad.setCurrentContext(new NotepadFileNew());
return true;
} else if ("Open".equals(menuId)) {
Notepad.setCurrentContext(new NotepadFileOpen());
return true;
} // else if (....) {
// ......
// }
return false;
}
}

 

Also see "NotepadFileController.java" in article attachments.

Then, Notepad’s entry point Notepad class’ relevant code might look like this:

 

	
private List<NotepadController> controllers = new ArrayList<NotepadController>();
private void setupControllers() {
controllers.add(new NotepadEditController());
controllers.add(new NotepadFileController());
}
private void processMenuAction(String menuId, Object parameter) {
for (NotepadController c : controllers) {
if (c.switchToScreen(menuId, parameter)) {
return;
}
}
}
public static void setCurrentContext(Object context) {
/**
* Do whatever you need to do
*/
}

 

Also See "NotepadEntryPoint.java" in article attachments.

Now, if I comment out the line with respective Group's source path in the XML, and corresponding line in Notepad.java (with its respective import):

 

// import com.careature.notepad.file.NotepadFileController; 

 

/* controllers.add(new NotepadFileController()); */

 

This will effectively exclude File group of files from GWT compilation, thus, bringing its time down. The application will work, except, when you pick one of the File menu items, - no corresponding activity will be involved. Just nothing will happen as none of controllers will respond to that menu Id.

But if you are going to concentrate on Edit menu items for some time, - that shouldn’t bother you. Just like FireFox permutation if you develop against Safari, or French locale if you develop in English.

Yes, there's a single reference to group's controller in the Notepad.java class, but that's small price to pay for. Enjoy, but do not forget that special care needs to be taken in order not to check-in such code before production deployment :).

After organizing your project according to this pattern, your GWT compilation time will not grow proportionally to the number of classes you have. Not at the development time. You have flexibility to include what you need and exclude what you do not need.

Every developer in the team may configure local project environment according to his\her specific needs at the moment and move forward. Also, exclusion from GWT compilation does not exclude the Group from java compilations and Eclipse refactoring facilities. So, there's no risk in excluded group's files to become outdated.

I hope GWT compilation performance will improve in the future, or, at least there will be more options to deal with that will let us adjust toolkit's compilation speed.

For those of you who prefers GWT development in hosted mode - this solution accelerates GWT hosted mode as well.

Legacy
Published at DZone with permission of its author, Vlad Sayenko.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Ankur Gupta replied on Mon, 2011/03/21 - 8:58pm

Nice Article. Good Ideas, I was looking for something on the same lines in recent days. Although we have done similar separation based on functions and everyone kind off agreed but wanted to get an opinion if this is a viable option (small price paid for quick dev turn around and also enhanced maintenance turnaround after transitioning the app to Support team).

Geoffrey De Smet replied on Tue, 2011/03/22 - 3:29am

Do you experience the same compilation duration problem when running your project in Eclipse or IntelliJ (so in hosted mode)?

We do experience a long compilation when we do a clean, full build with maven, but not in Eclipse or IntelliJ. To solve the former, we've configured maven to do draftCompile and do to 1 permutation in the default profile and to do it the normal way in the "full" profile.

Vlad Sayenko replied on Tue, 2011/03/22 - 10:30am in response to: Geoffrey De Smet

We are using Eclipse with draftCompile and 1 permutation, GWT 2.2, no Maven. But as I mentioned - the project is big and growing.

GWT 2.0.3 compiles faster than 2.2 mostly because in draftCompile it doesn't do code splitting. 2.2 does code splitting even with draftCompile option.

Hosted mode is an option, but in our case it is slow, and we use it only in cases we need  to debug the code.

Vlad Sayenko replied on Tue, 2011/03/22 - 12:03pm in response to: Ankur Gupta

Thanks :) I got this idea a while ago, but there were a lot of "if"s, which were not easy to answer until you actually try.

I had to do some serious project refactoring to comply with the pattern, but the effort was worth it.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.