490 likes | 738 Views
Cute and Cuddly UIs with GWT. What is the Google Web Toolkit?. Official Definition: “Google Web Toolkit (GWT) is a development toolkit for building and optimizing complex browser-based applications." boring definition! Real Definition: GWT is a compiler, plus a few frameworks
E N D
What is the Google Web Toolkit? • Official Definition: • “Google Web Toolkit (GWT) is a development toolkit for building and optimizing complex browser-based applications." • boring definition! • Real Definition: • GWT is a compiler, plus a few frameworks • It compiles java into optimized javascript • does quite a bit more too
The Basic GWT app • Consists of: • An entry HTML page • This is what the browser loads when it first hits the website • A gwt.xml file, named <Module Name>.gwt.xml • Contains: • what browsers to compile for • java class containing the entry point • what other modules are inherited (e.g. third-party toolkits like Gin, or gwttime) • Some java source files written using the GWT toolkit
<?xml version="1.0" encoding="UTF-8"?> <module rename-to='library'> <inherits name='com.google.gwt.user.User'/> <inherits name='com.google.gwt.user.theme.standard.Standard'/> <inherits name="org.gwttime.Time"/> <!-- Specify the app entry point class. --> <entry-point class='org.me.library.client.Library'/> <set-property name="user.agent" value="ie6,ie8,gecko1_8,safari, opera"/> </module> Sample Module.gwt.xml
Major parts of GWT • UI Framework • Remote Procedure Call(RPC) structure • the GWT compiler
UI Frameworks • GWT's UI toolkit includes: • Widgets • Event system • Resource management
GWT Widgets • Includes widgets for pretty much all the common HTML/Javascript widgets • Button/PushButton • TextBox, TextArea • Password box • etc.
Layout Widgets • Also includes widgets for doing layouts • Lay out vertically/horizontally in a row • FlowPanel, HorizonalPanel • Lay out in the center, with Borders • DockLayoutPanel, DockPanel • With a splitter between two widgets • SplitLayoutPanel, SplitPanel • With HTML • HTMLPanel
DockLayoutPanel p = new DockLayoutPanel(Unit.EM); p.addNorth(new HTML("north"), 2); p.addSouth(new Button("Hello", 2); p.addEast(new TextArea("Some text!"), 2); p.addWest(new HTML("west"), 2); p.add(buildMyBigWidgetList()); //add it to the HTML document RootLayoutPanel rp = RootLayoutPanel.get(); rp.add(p); Laying out content
Diversion about Standards Mode • Standards Mode • put <!Doctype html> on topof your html page to be in standards mode • Some layout widgets in GWT only work in Standards Mode • FlowLayout • DockLayoutPanel • SplitLayoutPanel
GWT Events • Events handle most all user-level interactions in GWT • Mouse clicks • Key presses • Events also can be used to send information from one widget to another • much like PropertyChangeListener in Swing • Instead of a PropertyChangeListener, use subclass of ValueChangedEvent<T>
Button myButton = new Button("Do stuff"); myButton.addClickHandler(new ClickHandler(){ @Override public void onClick(ClickEvent ce){ //react to button } }); ValueChangeEvent.fire(this, new MyValueChangeEvent()); Add an event listener
UiBinder • In GWT, you can layout your pages programatically • new FlowLayout().add(MyWidget), etc. • Can also lay out pages using html, css, and xml • The UiBinder is a way of doing layouts with xml, html, and css, instead of java. • This is actually doing layouts with html/css, instead of javascript
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"> <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:u="urn:import:com.google.gwt.user.cellview.client"> <ui:style> .important { font-weight: bold;} </ui:style> <g:HTMLPanel> <div class="{style.important}">Here's an interesting element!</div> <div id="tableDiv"><u:CellTable ui:field="cellTable" /></div> </g:HTMLPanel> </ui:UiBinder> Sample UiBinder
UiBinder(Continued) • Why use UiBinder instead of programmatic layouts? • Separates layout and aesthetic logic from functional logic • easier to change layout without affecting functionality • easier to apply CSS styles (especially with ClientBundle) • Faster • programmatic logic is compiled to more javascript than html • UiBinder is compiled to more html than javascript
ClientBundle • ClientBundle is a way of optimizing how the browser gets static resources • Images (ImageResource) • CSS (CssResource) • Text (TextResource) • Groups together resources to make better use of the browser cache • moves resources from "never cache" category to the "cache forever" category
Without a ClientBundle... • Make a change to an image, or css • do your users see it right away? • maybe • depends on their browser cache
With a Client Bundle... • You add an ImageResource • GWT compiler gives the image a unique hash • you change the image later.. • GWT compiler assigns new image a new hash • browsers now looking for a different image • changes show up right away
More ClientBundle • Not just for Images • also for Css, static Text • TextResource • compiles in static text as a cached resource • compiler can also easily internationalize the text from properties files • can be configured to download large text resources from the server as needed • allows rapid updates without a recompile/redeploy of the website
Server Stuff • Question: How do you make server calls in javascript land?
Don't • Don't ever, ever, ever use the internet. It's just a fad, it'll pass.
Refresh the entire page • It seems awfully lonely in here, without any users...
GWT RPC • GWT defines an AJAX-based Remote Procedure Call mechanism • Define your Service interface • Define your Service's Asynchronouscompanion interface • Implement your Service interface server side • call your Asynchronous interface client side
GWT RPC(Continued) • The GWT compiler will automatically generate implementations of your Asynchronous interface that uses AJAX to make the calls. • No Such Thing as a synchronous server call • GWT team decided that synchronous server calls are A Bad Idea(TM), and so they aren't available • They were right
public interface BeanServiceAsync{ void countBeans(String beanCounter, AsyncCallback<Integer> beanCallback); public interface BeanService{ int countBeans(String beanCounter); public static class App { private static final BeanServiceAsync ourInstance; //some static initialization stuff here public static BillingDataServiceAsync getInstance() { return ourInstance; } } }
void countMyBeans(){ AsyncCallback<Integer>callback = newAsyncCallback<Integer>(){ void onFailure(Throwable t){ handleFailure(t); } void onSuccess(Integer beanCount){ dealWithBeanCount(beanCount) } } BeanService.App.getInstance().countBeans("myName",callback); } Using BeanServiceAsync
GWT RPC(continued) • It is very easy to make an asynchronous server call in GWT • Good: • your UIs are more responsive than with synchronous calls • less effort necessary • Bad: • It's easy to just make a server call whenever you want • Sometimes you may bring back more data than you expect
Make too many RPC calls... • Browser limits how many run concurrently • the rest wait • the page becomes unresponsive • Users hate you
Ask for too much data... • Browser locks your page while processing the javascript • page becomes unresponsive • Users hate you
GWT Compiler • GWT is a compiler, plus frameworks(Already mentioned this, right?) • ......and?? • ....So what does the compiler do for me?
GWT Compiler(Continued) • Does all kinds of things • optimizes your java source code • converts java source to javascript • optimizes javascript • including ClientBundles, UiBinder, embedded css, etc. • optimizes javascript for different browsers
Permutations • Compiler compiles for each browser independently • called Permutations of the compile • If IE does a certain task in one way, and Chrome does it another... • IE permutation is compiled to use IE way, and never use Chrome's way • Chrome permutation always uses Chrome's way, and never IE's • Can even replace entire implementations specific to each Browser
Steps in the GWT compile • Steps in the GWT compile: • optimize java source • translate to javascript specific for each browser • optimize resulting javascript • perform code splitting(we'll get there)
Java optimization stage • Optimizes Java source • Dead code elimination • removed unused code blocks • replaces if(somethingTrue()&&anotherTrue()) with if(true) • staticifies non-overridden methods • If method A is never overridden, then method A becomes static • inlines method calls • not as aggressive here as the HotSpot compiler • get too aggressive, it makes javascript bigger
Javascript stage • Javascript optimizations • Basically the same to the interpreted javascript as what happens to the java • static evaluation (same as Dead code elimination, but cooler sounding) • method inlining • much more aggressive here since it only makes code smaller • global namespace mangling • turns "Foo.bar()" into "f.b()"--if you're lucky • global css namespace mangling • code splitting
Codesplitting • If you have a very big application... • downloading app to webpage takes a long time • javascript evaluation takes a long time • your users get bored and leave before your site loads • a solution.. • don't bring every piece of javascript down initially • bring down only what you need, as you need it
Codesplitting(Continued) • The compiler will separate out the javascript for you • IF you tell it to • Surround blocks of code which don't need to be downloaded initially with GWT.runAsync() • Compiler will recognize this • moves everything which is connected to that point into a different .js file which is downloaded later • only stuff which is directly connected to the entry point (no GWT.runAsync()) will be downloaded initially • sometimes this can be surprising
public void runSomeCodeAsync(){ GWT.runAsync(new RunAsyncCallback(){ void onFailure(Throwable t){ //your javascript failed to load! } void onSuccess(){ runMyAppCode(); } } } Codesplit
Story of your Compile • It's often confusing to determine what pieces of code are brought down in what split • GWT compiler can generate a summary • called the Story of Your Compile(SOYC) • Tells you where code has been split • what code is included in that split • what code is in the initial download • what code is "left over" • code is left over if it fits in no split entirely • this is downloaded initially.
Caveats about GWT Compiler • GWT compiler is slooooow • Each permutation takes time • the compiler does a lot, and it does it repetitively • permutations are easy to add • add a new browser • add a new language to compile for • Codesplitting is nontrivial • tends to add quite a bit of build time • Not unusual to see full builds take 30 minutes, 1 hour, or more
Caveats(Continued) • You can speed up the compile • Compile fewer permutations • use the -draftCompile command line argument • Distributed Compiler • not really all the way there--you have to write some glue code
Development mode • Obviously can't develop very effectively like that • GWT team introduced Development Mode to make up for this • Development Mode skips the compile stage and goes straight to the browser
Development mode(Continued) • Includes an embedded jetty server to run server code • puts wrappers into javascript instead of actual code • when you interact with the page... • each action you take is sent to the embedded server • that server compiles enough javascript to perform that action, and sends it back • Can use debuggers with development mode for client-side javascript debugging • to make a UI change take effect, only need to refresh, not rebuild.
Development Mode(Continued) • However... • Development mode is not exactly the same as production mode • some bugs exist only in development • some bugs exist only in production • development mode is much slower than production
Best practices • Use UiBinder • Use ClientBundle • Use codesplitting • you would be amazed how much faster your app feels • avoid excessive javascript • javascript is usually slower than HTML • Don't make too many server calls • Remember your Java Best practices • Be kind to your users
Third party tools • Gin(http://code.google.com/p/google-gin/) • like guice, but for GWT • no interceptors though • gwttime(http://code.google.com/p/gwt-time • port of joda-time to GWT • not perfect (kinda big) • better than nothing • needs to be revamped • gwt-log(http://code.google.com/p/gwt-log/) • log4j-style client side logging • can be sent to the server!
Contact Twitter: @scottfines Email: scottfines@gmail.com LinkedIn