Trying to optimize a Touchkit Widgetset

I took an example Touchkit application and started trying things with it, writing an app for my daughter’s wedding. It uses NavigationViews with buttons to move to other NavigationViews, essentially.

I’ve got it running on Tomcat, both locally and on a friend’s server. But on the server, with a lower bandwidth, the app takes 20-60 seconds to load the first page. I looked at HTTP traffic (using Fiddler) on my own server, and there’s 2-3 Megabytes of information that gets transferred to the phone before it displays the first page.

I am trying to GZIP the download, but even if that cuts the time in half it’s really too long. So I’ve been trying to figure out how to “Optimize the widgetset”. I understand the concept – the JavaScript that is output by the compiler does not by default know which widgets are used in the program, so there is (evidently) a way to list them and limit the widgetset compilation to only those widgets.

But I haven’t found an explanation of how this works, only an example. So I looked at the two files I understand to be relevant in the Parking App example – ParkingWidgetset.gwt.xml and WidgetLoaderFactory. I ended up with the following two files, first the gwt.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.5.0//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.5.0/distro-source/core/src/gwt-module.dtd">
<module>
    <!--
        This file is automatically updated based on new dependencies by the
        goal "vaadin:update-widgetset".
    -->

    <!-- Inherit DefaultWidgetSet -->
    <inherits name="com.vaadin.DefaultWidgetSet" />

    <inherits name="com.vaadin.addon.touchkit.gwt.TouchKitWidgetSet" />
    
    <generate-with class="rc.wedding.ui.WidgetLoaderFactory">
        <when-type-assignable class="com.vaadin.client.metadata.ConnectorBundleLoader" />
    </generate-with>

</module>

Then the WidgetLoaderFactory:

package rc.wedding.ui;

import java.util.ArrayList;
import java.util.Collection;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.vaadin.addon.touchkit.gwt.TouchKitBundleLoaderFactory;
import com.vaadin.addon.touchkit.gwt.client.vcom.DatePickerConnector;
import com.vaadin.addon.touchkit.gwt.client.vcom.EmailFieldConnector;
import com.vaadin.addon.touchkit.gwt.client.vcom.GeolocatorConnector;
import com.vaadin.addon.touchkit.gwt.client.vcom.TabBarConnector;
import com.vaadin.addon.touchkit.gwt.client.vcom.VerticalComponentGroupConnector;
import com.vaadin.addon.touchkit.gwt.client.vcom.navigation.NavigationBarConnector;
import com.vaadin.addon.touchkit.gwt.client.vcom.navigation.NavigationButtonConnector;
import com.vaadin.addon.touchkit.gwt.client.vcom.navigation.NavigationManagerConnector;
import com.vaadin.addon.touchkit.gwt.client.vcom.navigation.NavigationViewConnector;
import com.vaadin.addon.touchkit.gwt.client.vcom.popover.PopoverConnector;
import com.vaadin.client.extensions.ResponsiveConnector;
import com.vaadin.client.extensions.javascriptmanager.JavaScriptManagerConnector;
import com.vaadin.client.ui.button.ButtonConnector;
import com.vaadin.client.ui.csslayout.CssLayoutConnector;
import com.vaadin.client.ui.form.FormConnector;
import com.vaadin.client.ui.formlayout.FormLayoutConnector;
import com.vaadin.client.ui.image.ImageConnector;
import com.vaadin.client.ui.label.LabelConnector;
import com.vaadin.client.ui.link.LinkConnector;
import com.vaadin.client.ui.nativeselect.NativeSelectConnector;
import com.vaadin.client.ui.optiongroup.OptionGroupConnector;
import com.vaadin.client.ui.table.TableConnector;
import com.vaadin.client.ui.textfield.TextFieldConnector;
import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.client.ui.upload.UploadConnector;
import com.vaadin.client.ui.window.WindowConnector;
import com.vaadin.shared.ui.Connect.LoadStyle;

public class WidgetLoaderFactory extends TouchKitBundleLoaderFactory
{
  private final ArrayList<String> usedConnectors = new ArrayList<>();
  
  public WidgetLoaderFactory()
  {
    addClass(ButtonConnector.class);
    addClass(CssLayoutConnector.class);
    addClass(DatePickerConnector.class);
    addClass(EmailFieldConnector.class);
    addClass(ImageConnector.class);
    addClass(FormConnector.class);
    addClass(FormLayoutConnector.class);
    addClass(GeolocatorConnector.class);
    addClass(LabelConnector.class);
    addClass(LinkConnector.class);
    addClass(NativeSelectConnector.class);
    addClass(NavigationBarConnector.class);
    addClass(NavigationButtonConnector.class);
    addClass(NavigationManagerConnector.class);
    addClass(NavigationViewConnector.class);
    addClass(OptionGroupConnector.class);
    addClass(PopoverConnector.class);
    addClass(TabBarConnector.class);
    addClass(TableConnector.class);
    addClass(TextFieldConnector.class);
    addClass(UIConnector.class);
    addClass(UploadConnector.class);
    addClass(VerticalComponentGroupConnector.class);
    addClass(WindowConnector.class);
    addClass(ResponsiveConnector.class);
    addClass(JavaScriptManagerConnector.class);
  }
  
  private void addClass(Class<?> c) { usedConnectors.add(c.getName()); }
  
  @Override
  protected Collection<JClassType> getConnectorsForWidgetset(TreeLogger logger, TypeOracle typeOracle)
    throws UnableToCompleteException
  {
    Collection<JClassType> connectorsForWidgetset
      = super.getConnectorsForWidgetset(logger, typeOracle);
    ArrayList<JClassType> arrayList = new ArrayList<>();
    for (JClassType jClassType : connectorsForWidgetset)
    {
      String qualifiedSourceName = jClassType.getQualifiedSourceName();
      if (usedConnectors.contains(qualifiedSourceName))
      {
        arrayList.add(jClassType);
      }
    }
    return arrayList;
  }
  
  @Override protected LoadStyle getLoadStyle(JClassType connectorType)
  {
    return LoadStyle.EAGER;
  }
}

And let me just say a word about compiling a Touchkit application – once you’ve messed with anything connected to the Widgetset (and I have not yet figured out everything that does), you are in for a treat. Some combination of the following will work, in some order, lots of the time:

  1. stop the server
  2. remove the app from the server
  3. clean the server
  4. clean the work directory of the server
  5. maven clean
  6. maven install
  7. maven compile
  8. add the app to the server
  9. start the server

I can usually count on doing most of these at least twice before the app will start again.

However, with the above two files in the project, the app doesn’t start – I get the “You seem to be using a desktop application” when I’m on my PC, but the page afterwards is just blank.

I don’t know where any log messages would be, or any other way to figure out what’s wrong. Can someone tell me if I’m missing something?

I think I have connectors for all my components, but if I’m missing one I don’t know how to find out. There was a suggestion in one of the articles to use a debugger on a class that had a list of all the components that had been used so far, but I couldn’t find the class in eclipse, either source or class.

Hi,

The best way to collect the list of used connectors is to use the debug dialog (opened by appending “?debug” to the URL). Then navigate throught the apps features and after that click the “magic” button on the third tab of the debug dialog to see the “default” instructions to create the optimized widgetset. You’ll see the list there, I think the touchkit documentation originates from era when that feature was not there in the debug dialog. But otherwise I think you should follow the official documentation:

https://vaadin.com/docs/-/part/touchkit/mobile-optimization.html

Your startup time seem so slow that you should probably also verify where the real bottleneck really is. Maybe your app is doing some expensive db operation in the beginning. You can get hints of this form the debug dialog as well. Also maybe inspect the app using browsers debugging tools to see what is taking long.

Latest Vaadin versions use GWTs pre-compressing of static resources, so enabling GZIP with other mechanisms probably don’t help that much, it will only enable gzip of the actual UI state, the client side engine should already be compressed.

But, something is definitely taking too long for you, especially if also the subsequant app loads takes long. TouchKit should generate you “cache manifest” and not load anything by the initial UI state on subsequent calls. If you can’t figure it out yourself, contact our experts via
pro support
and they’ll figure out what is wrong. If you can share a link to you app here on forum, me or somebody else from the community can probably also give additional hints.

cheers,
matti