Optimizing a GWT Application with Multiple EntryPoints
Building a GWT application is an easy way for Java Developers to write Ajax applications. However, it can be difficult to release a GWT application to production before it's finished. One of the most important things I've learned in Software Development is to get a new application into production as soon as possible. Not only does getting it from dev → qa → prod verify your process works, it also can do a lot to test the viability of the new application.
One of the biggest issues with GWT applications is size. The project I'm working on compiles Java to JavaScript and creates ~570K *.cache.html files (one for each modern browser). These files end up being around 180K gzipped. I believe this is an OK size for an entire application. However, if you're going to release early, release often with GWT, chances are you'll just want to release one feature at a time.
When the first feature was completed on my project, the *.cache.html files were around 300K. Rather than using branches to release to QA and UAT, bug fixes and new features were developed on trunk. Unfortunately, the QA and UAT process took several weeks longer than expected so by the time the feature was ready to release, the *.cache.html files had grown to around ~570K. The reason the file had grown so much was because it included all of the other features.
Earlier this week, while running to a dentist appointment, I thought of a solution to this problem. The basic idea was to optimize the compilation process so only the to-be-released feature was included. Even better, the solution didn't require more modularization. The results:
Before: *.cache.html -> 569K, gzipped 175K After: *.cache.html -> 314K, gzipped 100K
According to my calculations, that's a 56% reduction in size. How did I do it?
- Created a new
FeatureName.java
EntryPoint with only the to-be-released features imported. - Created a new
FeatureName.gwt.xml
that references the new EntryPoint. - Copied old (kitchen-sink) EntryPoint.html to
FeatureName.html
and changed the reference to the nocache.js file. - Created a Maven profile that allows using -PFeatureName to build a FeatureName-only module.
One downside to doing things this way is it's possible to create a WAR that has the same name and different features. Surely the Maven Overlords would frown upon this. Since this is just a temporary solution to release features incrementally, I'm not too worried about it. A possible workaround is to create different WAR names when a feature's profile is activated. I believe the true "Maven way" would be to make the "kitchen sink" application into a JAR and have several WAR modules with the different EntryPoints. Seems a bit complicated to me.
Other than this Maven publishing issue, the only other issue I can foresee is keeping the two EntryPoints and HTML files in synch. Then again, the separate files allow a feature to be customized for the release and can be deleted when its no longer needed.
What do you think? Do you know of a better way to compile a GWT application so it only contains certain features?
Posted by Matt Raible on March 26, 2009 at 07:36 PM MDT #
Matt,
Another thing I do is keep 2 copies of every module, and two Maven profiles, one for Development and one for Production (-P dev vs -P prod). The big difference is the following: -P dev refers to ModuleDev.gwt.xml instead of Module.gwt.xml, and ModuleDev.gwt.xml collapses all permutations down to one (<set-property> on everything, in my case, user.agent forced to safari, among others). Dev uses PRETTY whereas Prod uses OBF.
Even if you have multiple screens, you can still use multiple entry points, it's still a valid technique. You just create N entry points, each is which is a test harness for that screen, and a master entry point for the 'real' multi-screen application. That way, you can quickly recompile and launch a subsection of your application for testing, but still preserve the ability overall to built a complete application.
Posted by Ray Cromwell on March 26, 2009 at 10:45 PM MDT #
It would be great if you would have some about jQuery (and jQueryUI) since it made fantastic progress lately and it seems much simpler to use than Prototype et co.
Thanks,
Joseph.
Posted by Joseph S. on March 27, 2009 at 06:16 PM MDT #
Posted by Matt Raible on March 27, 2009 at 08:08 PM MDT #
Posted by Mark Beaty on March 30, 2009 at 12:14 AM MDT #
Posted by Matt Raible on March 30, 2009 at 05:01 PM MDT #
Matt:
The GWT is the easy part. I've almost drop kicked my server across my office several times. I wrote PHP for data services using URL's to localhost and then I switched to my domain because I started getting JSON errors. Then, I get all that worked out, now I'm having inside development vs. outside viewing issues. I can't surf to the outside address without setting my domain to a 192.168.1.x address in my macbook pro's /etc/host file.
I agree completely that any Java project you start should be deployed on a server immediately. That old "it works for me" excuse is history.
Also, I've found that you really need to think about how all this works while you're coding. Statics are important. And, this is an area where refactoring really pays off.
I haven't drop-kicked the server yet, but I keep running the mac compile script instead of the Ubuntu one after an "svn up".
Google Web Toolkit (GWT) ? I love it! :-)
Posted by David Whitehurst on April 02, 2009 at 04:06 PM MDT #
Posted by Amu on August 26, 2009 at 05:16 PM MDT #
Posted by Matt Raible on August 29, 2009 at 04:05 PM MDT #
Posted by 196.34.27.226 on August 31, 2009 at 08:11 AM MDT #
Hi, Interesting !
But I can't understand the different steps to do to optimized my applications.
Could you provide a sample application with old way and new way of coding GWT app ?
Thanks
Posted by Cyril Lakech on December 14, 2011 at 03:40 PM MST #
There is a simple (tricky) way to achieve this:
Make a simple Main class Your entry point.
Create this Main.java to work like a dispatcher:
Now the different classes Application, Admin and Install work like seperate units. Here is for example a simple Install class:
You don't need the Singleton stuff (getInstance), but it is very handy in big applications.
Now in the /war-directory create directories named 'install' and 'admin' and in every of them create an HTML page like this:
So when the user directs his Browser to http://www.example.com/install he will be redirected to http://www.example.com/index?install and index.html is bound to Main.java which will dispatch the request and load Install.java
Posted by Maximilian Eberl on December 14, 2011 at 03:41 PM MST #