Matt RaibleMatt Raible is a Java Champion and Developer Advocate at Okta. developer.okta.com

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.

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?

  1. Created a new FeatureName.java EntryPoint with only the to-be-released features imported.
  2. Created a new FeatureName.gwt.xml that references the new EntryPoint.
  3. Copied old (kitchen-sink) EntryPoint.html to FeatureName.html and changed the reference to the nocache.js file.
  4. 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 in Java at Mar 25 2009, 04:00:37 PM MDT 12 Comments
Comments:

If you have a large GWT application (10+ screens) and you only want to release 1 of them (say to replace a screen in an existing application), this post explains how to do that (by using multiple entry points). If you only planning on releasing your GWT app with all 10 screens, you probably don't need this.

Posted by Matt Raible on March 26, 2009 at 01: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 04:45 PM MDT #

Your articles are as usual fantastic (even if I'm not using GWT).
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 12:16 PM MDT #

@Joseph - I'd be happy to write about jQuery if I was using it. Currently, I am not.

Posted by Matt Raible on March 27, 2009 at 02:08 PM MDT #

Good post, Matt. How about another post on your GXT experiences/impressions? We're using it on a project at work (about 4 weeks in). I have to say that I've never spent more time working with an API trying to figure out how to do things that should be really basic. My impression is that the library is either really immature or just poorly designed in many areas. It seems if you deviate much beyond what their samples do, you will be spending a lot of time figuring things out. Do you have enough "material" for another GXT post, describing your level of usage in your application, as well as your experiences in using the library?

Posted by Mark Beaty on March 29, 2009 at 06:14 PM MDT #

@Mark - a couple of developers have experienced this on our project, particularly when working with the grid, data proxy and related classes. I haven't had to deal with this and therefore don't believe I have the knowledge to write the GXT post you're looking for.

Posted by Matt Raible on March 30, 2009 at 11:01 AM 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 10:06 AM MDT #

Hi Matt, I like your post. I have done a relatively small app using GXT. It has about 10 basic views. When I compile the application it come to about 3.3 megs uncompressed, and 2.9 zipped, which I believe to be way too big. I have noticed that having just a CenterLayout(GXT) variable in my app increases the size by about 300k. I need to know if size problems are common with GXT or if im posibly just doing something bad in my application. Please let me know if there are ways or good practices that can reduce the application size. Thank you very much, and any help is greatly appreciated. Amu

Posted by Amu on August 26, 2009 at 11:16 AM MDT #

@Amu - are you compiling with OBF to get the smallest possible size? In my experience, size is an issue with GXT. I'd only recommend using it if you're developing a new application and your users are willing to wait for the initial load time. If you're developing a public-facing, high-traffic application, I'd recommend raw GWT. That's what we did at Evite. I'm currently using GXT, but the application will be intranet-only.

Posted by Matt Raible on August 29, 2009 at 10:05 AM MDT #

Thanks Matt. I was not using OBF. Using OBF took the size down to 475k. I'm looking to optimize it further by using raw GWT components where I can. My application is public-facing and I want to get as small a size as I can. Thanks once again for your help.

Posted by 196.34.27.226 on August 31, 2009 at 02: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 09:40 AM MST #

There is a simple (tricky) way to achieve this:

Make a simple Main class Your entry point.

<module rename-to='gwt'>
  <inherits name='com.google.gwt.user.User'/>
  <entry-point class='com.example.client.Main'/>
  <source path='client'/>
  <source path='shared'/>
</module>

Create this Main.java to work like a dispatcher:

package com.example.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.RootPanel;

public class Main implements EntryPoint {

  public void onModuleLoad() {

    String url = Window.Location.getHref();
    if ( url.indexOf("?install")>-1 ) {
      Install install = Install.getInstance();
      RootPanel.get().add(install);
    else if ( url.indexOf("?admin")>-1 ) {
      Admin admin = Admin.getInstance();
      RootPanel.get().add(admin);
    } else {
      Application app = Application.getInstance();
      RootPanel.get().add(app);
    }
  }
}

Now the different classes Application, Admin and Install work like seperate units. Here is for example a simple Install class:

package comexample.client;

import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;

public class Install extends FlowPanel {

  /** Singleton stuff - to access Main from all subclasses! */  
  private static Install singelton;
  public static Install getInstance() {
    if (singelton == null) {singelton = new Install();}
    return singelton;
  }

  /** Constructor - called by Main.onModuleLoad() */
  private Install() {
    this.add(new HTML("<h1>Do whatever You have to do!</h1>"));
  }
}

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:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="0; URL=/index.html?install">
</head>
<body></body>
</html>

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 09:41 AM MST #

Post a Comment:
  • HTML Syntax: Allowed