How does gwt hosted mode observe changes?

174 views Asked by At

I am running gwt hosted mode through a proxy; debugging works, but it doesn't pick up changes to client code made in my IDE.

I am using the maven plugin to start hosted mode; configuration is as follows. The reason that webapp code is in /web is that the app is based on dropwizard, which can't server web assets out of root; thus I have src/main/webapp/web/* as my web assets.

So what's wrong with this maven config?

    <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>gwt-maven-plugin</artifactId>
            <version>2.5.1</version>
            <configuration>
                <webappDirectory>${project.build.outputDirectory}/web</webappDirectory>
                <hostedWebapp>${project.build.outputDirectory}/web</hostedWebapp>
                <!--<copyWebapp>true</copyWebapp>-->
                <module>com.flavor8.todo</module>
                <runTarget>index.htm</runTarget>
                <persistentunitcache>false</persistentunitcache>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test</goal>
                        <goal>resources</goal>
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>com.google.gwt</groupId>
                    <artifactId>gwt-user</artifactId>
                    <version>2.5.1</version>
                    <scope>provided</scope>
                </dependency>
                <dependency>
                    <groupId>com.google.gwt</groupId>
                    <artifactId>gwt-dev</artifactId>
                    <version>2.5.1</version>
                    <scope>provided</scope>
                </dependency>
                <dependency>
                    <groupId>com.google.gwt</groupId>
                    <artifactId>gwt-servlet</artifactId>
                    <version>2.5.1</version>
                    <scope>provided</scope>
                </dependency>
            </dependencies>
        </plugin>
1

There are 1 answers

2
Colin Alworth On BEST ANSWER

Multi-step answer, starting with the answer to the title, then explaining why your app isn't behaving:

When a GWT app is being debugged in Dev Mode, the page starts up the hosted.html file, which connects to the browser plugin, which then tries to read the code server running at (by default) localhost:9997. When that connection is made, dev mode finds the module file, and gets things going. A custom classloader, 'CompilingClassLoader' is used by dev mode to do the other work that is required:

  • At startup, all JavaScriptObject classes need to be found and merged into one giant type, JavaScriptObject$, so that you can freely cast from one JSO to another, and invoke any JSO method on any other JSO. This JavaScriptObject$ type is synthesized at module start up.

  • When any class is requested, this custom class loader picks up classes as needed from the filesystem or from any jar. It compiles them on the fly from the .java file, hence the name. This is done both to get a new instance of the class with un-initialized static fields, but also to find all JSNI methods and correctly wire them up to call into the browser and back again. This wiring is why you can make changes to any file and simply refresh the browser - Dev Mode will always try to load the file from the filesystem fresh and create the actual Java class as needed.

The compiling classloader reads from your classpath - of course if it can't find a file, then that class cannot be used, and likewise if there is more than one copy of a file, then only the first copy found will be used...


The problem is the line

<goal>resources</goal>

Assuming you are working on a war project and not lib, this line doesn't need to be there.

This line copies not only the .class files to your target/classes directory, but also any other resources that a GWT library would need to have in its jar. Since you aren't writing a library but an application, this isn't necessary to do here, and in fact it is causing problems. On the dev mode classpath, target/classes is the first entry, followed by your source directories, then each jar on your classpath.

Either when you start the project or when you ask maven to compile it, this gwt:resources goal is run, and all sources are moved. Then later when you edit a file from your IDE, the IDE's own compiler updates the .class file in target/classes, but doesn't know what gwt:resources is for, so doesn't re-run it. This means that while target/classes has the latest .class files, it has out of date .java files.

If you need your source files to actually be in target/classes, either make sure that gwt:resources runs with every resource change in your IDE, or another way to copy sources directly to the target/classes directory is to set up a <resource> entry in your pom.