Google Web Toolkit (GWT) compilation duration under control
Join the DZone community and get the full member experience.
Join For FreeNow, 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.
Opinions expressed by DZone contributors are their own.
Comments