Skip to main content

New site for Dart news and articles

For the latest Dart news, visit our new blog at  https://medium.com/dartlang .

From GWT to AngularDart: a case study with source code

Lots of interesting articles about Dart have been cropping up on Medium.com lately. We've decided to cross post them here so that followers of this blog won't miss out on them. We'll start by Istvan Soos's GWT-to-Dart case study, published on Friday. — Filip Hracek


Earlier this year I was asked if there’s a good way to compare developing web UIs in Google Web Toolkit (GWT) vs. Dart, specifically AngularDart. Having worked with both GWT and Dart, I had a good idea of the differences, but as I thought more, I started to wonder how hard it would be to migrate a GWT application to AngularDart. This article describes what I’ve found while doing just that.

The GWT Mail Sample was an ideal place to start: it’s much more than a trivial example, with diverse features and complex UI interactions, yet it’s still manageable in size.

If you’re in a hurry, take a look at the working demo and the source code, or scroll to the bottom for the conclusions.

Screenshot of the demo.

The method of migration

I’ve done the migration without any automated compiler. While it may be possible to write a tool to automatically convert the GWT templates to Angular, or the backing Java code to Dart, I wouldn’t suggest doing it that way. Chances are that the template, the styling, or the Java code uses patterns that are better served with new approaches. I’ll list a couple of these new approaches in the next section.

My process was very simple. I put the GWT and the AngularDart code in the same git repository and did the following cycle:

  1. Select a small or medium-sized chunk of the GWT codebase. Usually this was a single widget, or a smaller part of a complex widget.
  2. Carefully explore the features and edge cases that are in the code. Most of a proprietary codebase will be some kind of edge case that somebody stuffed in it. If there are more than 5 edge cases, it is a good indication that the task is too large and needs to be split into multiple chunks.
  3. Implement the selected part in AngularDart. This sounds simple, because it is simple. :-)
  4. Delete the selected part from the GWT codebase. The GWT application will no longer build, but you can easily track the parts that you haven’t migrated yet.

You can check my progress and individual steps either by observing the commit history, or by looking at the log.md file that I was writing along as I was doing the changes. One interesting observation: writing down the changes took much more time than implementing the code in AngularDart.

Old solutions vs. new ones

The bulk of the migration is straightforward: simple templates and styles can be mapped to their Angular counterparts easily. I won’t waste your time with minute details; instead I’ll just talk about the parts that differ.

The first and most obvious difference is the design: the Angular version uses material widgets from the angular2_components package. The package has a lot of useful components, if you are starting with AngularDart, you should try to go with that. While both stacks have a great selection of ready-to-use components, and most of them have 1:1 mappings with regard to features and settings, sometimes you need to use your judgement on which to use or select.

Watch the new version alongside the old one. AngularDart Components make it easy to have nice animations and consistent component views.

I missed a few things that aren’t available yet in AngularDart Components, like a table and tree component. However, as you can see in the log, it was really easy to implement them with Angular’s *ngFor templates. For example, the list of mail items is handled by the following template, which is much simpler than GWT’s table initialization in MailList.java:

<div *ngFor="let item of items"
     class="row"
     (click)="selectRow(item)"
     [class.selected]="isSelectedRow(item)">
  <div class="col sender">{{item.sender}}</div>
  <div class="col email">{{item.email}}</div>
  <div class="col subject">{{item.subject}}</div>
  <material-ripple></material-ripple>
</div>

I was told that team is working on open sourcing more components; fingers crossed that a more complex table will be included soon.

Less intriguing, but an important difference is the lack of static variables and the handling of singleton instances. In the GWT version, the list of email messages is stored in a static field in MailItems.java. In the Dart version, the same (and much more) functionality is handled by MailService, which is injected and better for unit testing.

I’ve started with a mock implementation for easier development (also to match the GWT version), while later on it is easy to plug in a real API behind the web client. For example, configuring the injection is as simple as the following code. Switching to a real implementation would be just changing the useValue: part of it.

Change to real implementation when ready.

On a more subjective note, I find the separation of code, HTML template, and CSS styles much better in AngularDart than in GWT. The GWT codebase allowed sprinkling the Java code with both styling details and template construction, and those parts were the hardest to migrate to a cleaner version.

End result by the numbers

While the AngularDart version has more features, and I’ve implemented custom components like the tree, overall I needed to write less code than what was needed for the GWT original. Depending on how you count, code size is down by 30%.

I was developing the application using Dartium, so I didn’t need to compile the Dart code to JavaScript; everything was done with a low-latency type-save-refresh cycle. However, the end result needed to be compiled to JS, and it may provide value to compare the numbers. On my Macbook Pro, the GWT applications’ compile times were:

  • 26 seconds for 1 permutations,
  • 11 seconds if the Java source code was already compiled, and
  • 40 seconds for all 5 permutations.

The Dart version took about 15–20 seconds to compile to cross-browser ES5. That is not blazing-fast, but it is faster than the GWT compiler.

Compile times (in seconds)

Last, a few notes about the output JavaScript’s size. The GWT compiler produces different JS version for each permutation (target browser), while the Dart compiler emits only a single compiled version. GWT’s output was roughly 207 KB / permutation (1M total for all 5, 84 KB/permutation when compressed), while the AngularDart version resulted in 689 KB (178 KB compressed).

Considering that the application logic is more complex (for example: diverse widgets, ripples, more detailed mail item handling), the larger JS size is not a surprise, although I hoped it would be smaller. Fortunately for us, a huge part of it is “fixed cost”, and additional components increase the size only a little (proportional to their complexity).

Conclusions

Both technologies originate from Google and both are capable of supporting larger team sizes, but they represent two very different eras. I have found the GWT code harder to read and reason about; the AngularDart version is more compact and easier for me. But don’t trust my point of view blindly. I strongly suggest that you try out the application and check the source codefor yourself.

I have also found the material components refreshing, and most of the time they were out of my way. Compared to that, styling and customizing GWT components is harder, requiring time that would be better spent on the application itself.

If you are looking to migrate your GWT app to a newer technology, AngularDart is a viable option. After all, Google is doing the same thing: they are migrating their critical apps from GWT to Dart (see their AdSenseand AdWords interviews).

— István Soós, March 10, 2017, canonical link