A pattern for GWT code splitting


(5 comments)
May 3rd 2011


When building large applications with GWT, code splitting is a must – otherwise, the entire application (i.e. Javascript bundle) is downloaded in one chunk on the initial load of the application, which is a good recipe for frustrated users! Fortunately, the folks at Google have made the code splitting mechanism extremely simple, and have provided a really handy tool for analyzing and debugging to boot.

Even still, implementing code splitting can be a bit tricky, especially deciding where in your framework to build it in. There are some helpful constructs and patterns out there (e.g. AsyncProxy, Async Provider, etc.), but it’s still not really clear if there is a definitive best practice for code splitting in large applications using GWT MVP. So…for the purpose of (hopefully!) sparking some conversation on this topic, here’s a solution we came up with on a recent project. Please feel free to share your solutions…or any thoughts/criticism you have. Here goes…

Scenario – Application with multiple “Sections”

Imagine an application that has multiple distinct “sections”, where each section contains lots of “things” (places, dialogs, widgets, etc.), and further that a “thing” can only live in one section. For example, consider a simple app with three sections “A”, “B”, and “C”.


simpleapp

Again, anything that is one section cannot be programmatically referenced by something in another section. In other words, the package dependencies should look like this:


packages


If an application can be segmented in this way, then the “section” could be a good boundary line for code splitting – in other words the application could be chunked in four pieces: main, A, B, and C. When the user first loads the application, only the main chunk is downloaded. When he navigates to any place within section A, for example, then all of section A is downloaded, and similarly for sections B and C.

Now sections may not always be good split points (perhaps they are too big, or there are inherent, un-refactorable dependencies from one section to another), but if they are, here’s how it can work…

Place Subclass

Create a subclass of the GWT Place, from which all places in the application are extended. This base class has a reference to a custom enum “Section”, which defines the different sections in the application (e.g. “A”, “B”, “C”). In psuedo-code it looks like this (though note there’s a lot missing from the MyPlace class):

 
public enum Section { 
    A, B, C;
}

public class MyPlace extends Place { 
    private Section section;
    ...
}

Again, since all places have a section, the URL for a specific place might look something like “#someplace:section=A”.


Composite and Section ActivityMappers

Now each section will have it’s own ActivityMapper (e.g. AActivityMapper, BActivityMapper, etc.) which instantiates the individual Activities within its section. Splitting up into separate ActivityMappers like this ensures that there is no one master ActivityMapper that has dependencies to all Activities in all sections (thereby breaking the dependency arrows, and thus code splitting).



activitymapper

These section-based ActivityMappers are glued together using a new, custom “composite” ActivityMapper, which, onPlaceChange, inspects the Section of the Place, and then delegates to the appropriate custom section-based ActivityMapper.

 
public class CompositeActivityMapper extends ActivityMapper { 
    private final HashMap mappers = 
               new HashMap();

    public Activity getActivity(Place place) { 
        MyPlace myPlace = (MyPlace) place;
        return mappers.get(myPlace.getSection()).getActivity(myPlace);
    }

    public void addActivityMapper(Section section, ActivityMapper activityMapper) { 
      mappers.put(section, activityMapper);
    }
}


Custom PlaceController

Finally, and this is the crux (!), the PlaceController is sub-classed, and loads the appropriate section’s ActivityMapper in the runAsync, thereby drawing the split-point boundary around the entire section. Essentially, the first time the user navigates to any place within a given section, the PlaceController will load that section (i.e. send down that section’s Javascript code bundle).

 
    public MyPlaceController extends PlaceController { 
   
        private CompositeActivityMapper compositeActivityMapper = new CompositeActivityMapper();

        private HashMap activityMappers = 
                  new HashMap();

        public MyPlaceController(CompositeActivityMapper compositeActivityMapper) { 
            this.compositeActivityMapper = compositeActivityMapper;
        }

        public void goTo(Place place) { 
            MyPlace myPlace = (MyPlace) place;

            switch (myPlace.getSection()) { 
                case A:
                    GWT.runAsync(new RunAsyncCallback() {
                        public void onSuccess() {
                            if(activityMappers.get(A) == null) { 
                                activityMappers.put(A, new AActivityMapper());
                                compositeActivityMapper.addActivityMapper(Section.A, activityMappers.get(A));
                            }
                            parentGoTo(myPlace);
                        }
                        public void onFailure(Throwable t) { 
                            // handle somehow
                        }
                    }
                    break;
                 case B:
                     ...
            }
        }

        public void parentGoTo(AdminPlace place) {
            super.goTo(place);
        }
    }


Conclusion and Caveats

Obviously, this is a high-level description, but hopefully you get the idea. Through the creation of a few custom infrastructure classes (e.g. Place, ActivityMapper, PlaceController, etc.), code splitting can be managed at a section level relatively seamlessly to the end developer – i.e. as long as the developer doesn’t break the dependency structure, it will work.

Finally, here are a few quick caveats:

Anyway, I’d love to hear other strategies for code splitting in MVP-based GWT apps – please share. Thanks!

I'm an "old" programmer who has been blogging for almost 20 years now. In 2017, I started Highline Solutions, a consulting company that helps with software architecture and full-stack development. I have two degrees from Carnegie Mellon University, one practical (Information and Decision Systems) and one not so much (Philosophy - thesis here). Pittsburgh, PA is my home where I live with my wife and 3 energetic boys.
I recently released a web app called TechRez, a "better resume for tech". The idea is that instead of sending out the same-old static PDF resume that's jam packed with buzz words and spans multiple pages, you can create a TechRez, which is modern, visual, and interactive. Try it out for free!
Got a Comment?
Comments (5)
Jorge Lee
May 03, 2011
There is an open ticket to GWT about how to combine code splitting with the new MVP framework: http://code.google.com/p/google-web-toolkit/issues/detail?id=5129
The ActivityProxy idea is a very elegant solution – it takes advantages of the current framework and it is not very intrusive (especially when combined with Gin). I hope to see this solution in the next versions of GWT. Note that Ray Ryan is part of the discussion.
Ashton
May 10, 2011
Thanks Ben!
easy question for someone who has used Code Splitting.
How does GWT handle:
A
–A1
–A2
–A3
–A4
B
–B1
–B2
Let’s say I want B1 and B2 to be behind split points. A1 references B1 via Async Provider and A2 references B2.
However B1 (behind a split point) needs to reference A3 and A4
So the main modules A1 & A2 share dependencies with the code split B1 & B2
Does this break the code splitting? If I have widgets in A3 & A4 that are common throughout the app, will it break?
I am currently looking into this now, but some experience always help uncover many answers :)
Thanks!
Ben
May 10, 2011
Jorge – thanks! Great comment. Thanks for the heads-up on the open ticket.
Ashton – no…if I understand correctly, I don’t think this would break code splitting. If A3 and A4 are widgets that are depended on by both widgets A1/A2 ad B1/B2, this should be fine, so long as the dependencies are one way (i.e. not back from A3 or A4 to A1, A2, B1, or B2).
I hope I’m understanding correctly, but the absolute best way to determine what gets split is to use the compile report:
http://code.google.com/webtoolkit/doc/latest/DevGuideCompileReport.html
Ashton
May 10, 2011
Great! Thanks for the quick response :)
I organized my project into different Modules (so basically different applications) where each module would act as the split points int eh example you described. So I face the problem that each of the modules is still too big so I am trying to build split points that have similar dependencies as a described above (the code behind split points reference widgets used in non split code).
As always, Thanks very much!
Nouman
July 11, 2011
hi, very nice article, can you please add some code splitting running example.