1 of 54

Beyond Dev Mode

New Tools for Debugging GWT Apps

Brian Slesinsky

December 2013

GWT.create conference

2 of 54

What's Development Mode?

3 of 54

What's Development Mode? (2)

Dev Mode JVM

GWT App

(Java)

Browser

GWT App (JavaScript)

Plugin

(C++)

Browser

Channel

Browser API's

4 of 54

What's Development Mode? (3)

IDE

Dev Mode JVM

GWT App

(Java)

Browser

GWT App (JavaScript)

Plugin

(C++)

Browser

Channel

Browser API's

Browser Debugger

(JavaScript, DOM, CSS)

Java Debugger

(GWT code, servlets)

5 of 54

Life of a button click (1)

IDE

Dev Mode JVM

GWT App

(Java)

Browser

GWT App

(JavaScript)

Browser

API's

public void onClick(ClickEvent event) {� elt.setInnerText("Clicked!");�}

IDE

6 of 54

Life of a button click (2)

IDE

Dev Mode JVM

GWT App

Browser

GWT App

API's

public void onClick(ClickEvent event) {� elt.setInnerText("Clicked!");�}

IDE

7 of 54

Life of a button click (3)

IDE

Dev Mode JVM

Browser

public void onClick(ClickEvent event) {� elt.setInnerText("Clicked!");�}

IDE

8 of 54

Stack view of a button click (1)

public void onClick(ClickEvent event) {� elt.setInnerText("Clicked!");�}

onClick()

onClick()

Plugin

BrowserChannel

Java

JavaScript

9 of 54

Stack view of a button click (2)

public void onClick(ClickEvent event) {� elt.setInnerText("Clicked!");�}

onClick()

setInnerText()

onClick()

Plugin

JSNI proxy

BrowserChannel

Java

JavaScript

10 of 54

Stack view of a button click (3)

public void onClick(ClickEvent event) {� elt.setInnerText("Clicked!");�}

onClick()

onClick()

Plugin

BrowserChannel

Java

JavaScript

11 of 54

Unfortunately...

"Developers will be able to update their existing NPAPI-based Apps and Extensions until May 2014 [...] In September 2014, all existing NPAPI-based Apps and Extensions will be unpublished."

http://blog.chromium.org/2013/09/saying-goodbye-to-our-old-friend-npapi.html

12 of 54

New plugin API is asynchronous

"The JavaScript does not wait for a reply from Native Client, thus avoiding bogging down the main JavaScript thread."

13 of 54

Meanwhile on Firefox...

14 of 54

DevMode Status

Safari

Stopped working in 5.1

(Plugin architecture changed)

Chrome

Will stop working this year

(Plugin architecture changed)

Firefox

Stops working with every release

(Plugin uses internal API's)

Internet Explorer

Works fine (no complaints?)

Mobile browsers

Never implemented

15 of 54

Lessons learned

  • Using nonpublic browser API's is a bad idea.
  • Synchronous browser API's are unlikely to last.

Maybe having two stacks is not a good idea.

How can we avoid this?

16 of 54

All-JavaScript Debugging

  • Invoking the compiler (workflow)
  • Speeding up the GWT compiler
  • Using the Chrome debugger
  • What's new with debuggers
  • When you don't have sourcemaps

17 of 54

Trying out Super Dev Mode

$ unzip ~/Downloads/gwt-2.6.0-rc3.zip

$ cd gwt-2.6.0-rc3/samples/Hello

$ ant gwtc

$ ant devmode

# in a different window

$ ant superdevmode

18 of 54

Running Super Dev Mode

19 of 54

Running Super Dev Mode (2)

20 of 54

Running Super Dev Mode (3)

21 of 54

Starting Super Dev Mode (In detail)

# production compile

CLASSPATH=$SDK/gwt-dev.jar:$SDK/gwt-user.jar:src \

java com.google.gwt.dev.Compiler \

com.google.gwt.sample.hello.Hello

# Super Dev Mode

CLASSPATH=$SDK/gwt-dev.jar:$SDK/gwt-user.jar:

$SDK/gwt-codeserver.jar:src \

java com.google.gwt.dev.codesever.CodeServer \

com.google.gwt.sample.hello.Hello

22 of 54

Your own compile button

function compile(module_name) {

window.__gwt_bookmarklet_params = {

server_url: 'http://127.0.0.1:9876/',

module_name: module_name,

};

var s = document.createElement('script');

s.src = 'http://127.0.0.1:9876/dev_mode_on.js';

document.getElementsByTagName('head')[0]

.appendChild(s);

}

compile('showcase');

23 of 54

Your own compile button (2)

native void compile(String module_name) /*-{

$wnd.__gwt_bookmarklet_params = {

server_url: 'http://127.0.0.1:9876/',

module_name: module_name,

};

var s =$doc.createElement('script');

s.src = 'http://127.0.0.1:9876/dev_mode_on.js';

$doc.getElementsByTagName('head')[0]

.appendChild(s);

}-*/;

compile("showcase");

24 of 54

Server-side compile request

$ RECOMPILE='http://127.0.0.1:9876/recompile/showcase'

$ curl "$RECOMPILE?locale=en&user.agent=safari&_callback=done"

done({"status":"ok","moduleNames":["showcase"]});

$

25 of 54

Super Dev Mode Browser Support

Chrome

Works!

Firefox

Works!

Safari

Works!

Internet Explorer

Works!

Mobile

Works, but requires extra setup because bookmarklets aren't available.

26 of 54

All-JavaScript Debugging

  • Invoking the compiler (workflow)
  • Speeding up the GWT compiler
  • Using the Chrome debugger
  • What's new with debuggers
  • When you don't have sourcemaps

27 of 54

More speed coming soon

Separate talk:

The GWT Java to JavaScript compiler:

present and future

28 of 54

Configure the compiler for speed

com.google.gwt.dev.Compiler -draftCompile …

<module>

...

<set-property name="user.agent" value="safari"/>

<set-property name="locale" value="en"/>

</module>

(Super Dev Mode does this for you.)

29 of 54

Remove module dependencies

<!-- faster -->

<module>

<inherits name="com.example.Util" />

</module>

30 of 54

All-JavaScript Debugging

  • Invoking the compiler (workflow)
  • Speeding up the GWT compiler
  • Using the Chrome debugger
  • What's new with debuggers
  • When you don't have sourcemaps

31 of 54

Source-level debugging

32 of 54

Source-level debugging

defineSeed(932, 1, makeCastMap([Q$ClickHandler, Q$EventHandler]), CwBasicButton$1_0);

_.onClick = function onClick_27(event_0){

alert_0(this.this$0.constants.cwBasicButtonClickMessage());

}

Button normalButton = new Button(

constants.cwBasicButtonNormal(), new ClickHandler() {

public void onClick(ClickEvent event) {

Window.alert(constants.cwBasicButtonClickMessage());

}

});

33 of 54

Source-level debugging

defineSeed(932, 1, makeCastMap([Q$ClickHandler, Q$EventHandler]), CwBasicButton$1_0);

_.onClick = function onClick_27(event_0){

alert_0(this.this$0.constants.cwBasicButtonClickMessage());

}

Button normalButton = new Button(

constants.cwBasicButtonNormal(), new ClickHandler() {

public void onClick(ClickEvent event) {

Window.alert(constants.cwBasicButtonClickMessage());

}

});

?

34 of 54

Source-level debugging

normalButton = new Button_2(this$static.constants.cwBasicButtonNormal(), new CwBasicButton$1_0(this$static));

$ensureDebugId(normalButton, 'cwBasicButton-normal');

Button normalButton = new Button(

constants.cwBasicButtonNormal(), new ClickHandler() {

public void onClick(ClickEvent event) {

Window.alert(constants.cwBasicButtonClickMessage());

}

});

normalButton.ensureDebugId("cwBasicButton-normal");

35 of 54

Workarounds for breakpoint quirks

  • Try setting the breakpoint earlier or later
  • Pay attention to the breakpoint list
  • If the Java doesn't display at first, try clicking on the method in the call stack.
  • If all else fails: add GWT.debugger() and recompile.

36 of 54

TODO: better sourcemaps

  • Split up JavaScript statements

expr1, expr2; expr1; expr2;

var a=1, b=2; var a=1; var b=2;

  • Merge adjacent sourcemap ranges

37 of 54

All-JavaScript Debugging

  • Invoking the compiler (workflow)
  • Speeding up the GWT compiler
  • Using the Chrome debugger
  • What's new with debuggers
  • When you don't have sourcemaps

38 of 54

Firefox

39 of 54

IntelliJ IDEA

40 of 54

IntelliJ IDEA (2)

41 of 54

Debugger support for GWT

Chrome

Works now.

IDEA 13.x + Chrome

Demoable but not released yet. (Coming soon!)

Firefox 26

Demoable, but slow to load and sometimes hangs.

Safari 7

Very slow; sourcemaps load on gwtproject.org but not Super Dev Mode. Breakpoints skipped.

Internet Explorer

No sourcemap support. (Typescript uses sourcemaps, so we can hope.)

42 of 54

All-JavaScript Debugging

  • Invoking the compiler (workflow)
  • Speeding up the GWT compiler
  • Using the Chrome debugger
  • What's new with debuggers
  • When you don't have sourcemaps

43 of 54

Substitute for a breakpoint

void someMethod(int a, String b) {

GWT.debugger();

...

}

44 of 54

Conditional breakpoint

void someMethod(int a, String b) {

if (a<0) GWT.debugger();

...

}

45 of 54

Conditional breakpoint (2)

void someMethod(int a, String b) {

assert a>=0; # use -ea or SuperDevMode

...

}

46 of 54

Watching a variable

void someMethod(int a, String b) {

GWT.log("someMethod: " + a); # see console

...

}

47 of 54

How to prepare

  • Try out Super Dev Mode

  • Learn how to use JavaScript debuggers

48 of 54

Questions?

49 of 54

Backup slides

50 of 54

Starting Super Dev Mode

Browser

Server

Super Dev Mode Server

HTML

nocache.js

nocache.js

cache.js

51 of 54

Seeing which code is used

52 of 54

Seeing which code is used (2)

53 of 54

Filter out unused source files

<!-- default -->

<module>

<source path="client" />

</module>

<!-- faster -->

<module>

<source path="client/*.java"

excludes="client/android" />

</module>

54 of 54

TODO: emit nicer JavaScript

When in -draftCompile:

  • Behave more like Java: better null pointer checks and range checks

  • Reduce the number of global symbols

  • Make JavaScript more readable