DEV Community

Ignacio Baca Moreno-Torres
Ignacio Baca Moreno-Torres

Posted on • Updated on

Modern GWT, first steps

The GWT context 💎

GWT is a powerful tool, but sometimes this power might get perceived as complexity.

Long unnecessary explanation here, if you just want to start with GWT jump to the guide itself.

I think this complexity can be divided into two causes; 1. big projects are complex, and when you try to explain how to solve a complex situation, then the explanation itself is complex. 2. GWT has a huge ecosystem, and there are various solutions for each problem. This forces you to make complex decisions.

But, how did we get there?

GWT was borns in 2006, the evolution of the web ecosystem has been amazing since then, even inside GWT itself there have been a lot of changes, alternatives, and third parties that have created amazing solutions to manage big client-side web APPs.

From 2006 to 2012 GWT was called "Google Web Toolkit", and it was an all-in-one solution. In June 2012, Google handed control to the steering committee and rename the project as "GWT". Since then, GWT has been evolving into a more open tool and most of the architectural solutions embedded into GWT itself have been overcome by third-party alternatives. Nowadays, the number of solutions is huge, and at this point, GWT is just the core, and it is not biased in how you should organize your code. So, GWT is no longer a web toolkit nor a client-side framework, it is just a transpiler with a giant ecosystem around it.

For example, nowadays if you want to choose a client architectural pattern, you must choose between gwt-activities, gwtp, errai, react4j, vue-gwt, nalu, and more! or if you are looking for a transport layer you should choose between gwt-rpc, request-factory, resty-gwt, gwtp-rest-dispatch, autorest, and more!

All this complexity (only justified for big projects with experienced java teams) and all these alternative architectural solutions (which is actually a good thing) make it a bit confusing to start with GWT.

Said all this, when should I use GWT? I think that you only should use GWT in a company project if you meet these two points.

  1. you have a senior Java team that already knows Java and Web development (HTML5, CSS3, ES6). To develop with GWT you must know browsers, you don't need to be a JavaScript expert, but you need to know a lot around the web world (MDN is your friend).
  2. you must want to share Java logic, libs, and tools that you are already using in Java (servers or Android) with the client-side or even iOS with J2ObjC). This is the whole point with GWT, sharing code between platforms. This is useful and it solves a logic-duplication, e.g. whenever you edit a field, you frequently validate it with some rules, but then this is sent to the server and should be validated again. This simple but common use case is beautifully solved with GWT. You write your validator code, and you use it exactly the same validation code on all platforms, giving you the responsiveness on the client-side and also the security of the server-side (cross-platform example).

If you already have various years of experience with GWT you can use it for a lot of things, even small APPs. But to justify the entry effort, you should satisfy those two points. But, eh! before a company project, you can just learn it for fun, and I hope you are here for that!

The starting guide ☝️

To make this guide easier, I'm going to focus on the client-side. Also, I'll make some personal decisions that I think are common and future-proof. But remember, GWT is much more than I'll explain here!. This is what I have chosen:

  1. create a micro client-only APP, so no transport and no view components. Frequently guides start with a client-server app, it is much more complex and when you start with GWT you tend to confuse the client and server sides as just one unique magic virtual machine. Although everything is java, and you can run the same java code in the client or on the server, both are independent runtime environments and this concept should be clear.

    Also, if you create a client-only APP the guide gets much smaller, and you can play with it easier. Even more, I strongly encourage you to find micro-games or micro-apps written in JS or TypeScript and migrate it to GWT. This is a pretty good exercise to get used to GWT. For example, this is a snake game migrated from a JS project rxsnake-gwt.

  2. it is managed with Maven, no IDE or plugin required, just java+maven. I'll use IntelliJ IDEA. We are not going to use any plugin, IntelliJ Ultimate has GWT support, and Eclipse has a super nice plugin, but I personally prefer not to depend on any of that. Also, the problem with those plugins is that the project configuration (classpath mostly) is not easy to keep exactly the same in the terminal or CI vs the IDE plugin. So with this solution, Maven solution, you will be able to run, test, and package your GWT in the same way in all those environments. IMO Maven is currently the easiest strategy to compile GWT.

1. Maven basic archetype 💩

First, we create a minimal maven project. You might follow this guide or execute this command if you have maven already installed.



› mvn archetype:generate \
    -DarchetypeRepository=https://repo.maven.apache.org/maven2 \
    -DarchetypeGroupId=org.apache.maven.archetypes \
    -DarchetypeArtifactId=maven-archetype-quickstart \
    -DarchetypeVersion=1.4 -DinteractiveMode=false \
    -DgroupId=me -DartifactId=hello-app -Dversion=HEAD-SNAPSHOT


Enter fullscreen mode Exit fullscreen mode

I hope you know something about maven. But, if not, note that you can compile, test, and package your app using mvn verify. Run it now! 😉

You can now open the created project in IntelliJ, just click open and go to the folder. IntelliJ detect maven automatically, and it will use the maven configurations to configure your project. I have reformated and removed comments, change the target/source java version to 11 (fun 🥳, we can use var), and update maven-compiler-plugin to 3.8.1, maven-surefire-plugin to 2.22.1 and junit to 4.13.2. Whenever you change something in the POM IntelliJ will ask you to "import changes", and click it to update the project configuration. This is what it should look like:
Step 1: IDE layout

Try again the mvn verify but this time use the IntelliJ maven menu. Any JDK ≥11 should work, but if you have any problem, just use JDK 11.
Step 1: Configure JDK11

I start from this basic maven archetype because I want to remark that the GWT project uses the whole Java ecosystem, and it uses similar patterns but is applied to front-end development.

Step 1 diff.

2. GWTify it 🌈

First, modify the pom.xml to add the GWT dependencies and the GWT Maven plugin that will add some useful goals to compile and run GWT. Add this to the dependencies section:



<dependency>
  <groupId>com.google.gwt</groupId>
  <artifactId>gwt-user</artifactId>
  <version>2.9.0</version>
</dependency>
<dependency>
  <groupId>com.google.gwt</groupId>
  <artifactId>gwt-dev</artifactId>
  <version>2.9.0</version>
</dependency>


Enter fullscreen mode Exit fullscreen mode

Those are the minimal GWT dependencies. The gwt-user contains client-side java utilities, for example, the EntryPoint interface that is used in GWT as a static void main(args) equivalent (more on that later). And gwt-dev contains the compiler and other development tools requirements.

Then, you need to configure the GWT plugin and define the project as a gwt-app. Add this to the build section:



<plugins>
  <plugin>
    <groupId>net.ltgt.gwt.maven</groupId>
    <artifactId>gwt-maven-plugin</artifactId>
    <version>1.0.1</version>
    <extensions>true</extensions>
    <configuration>
      <moduleName>me.App</moduleName>
      <skipModule>true</skipModule>
    </configuration>
  </plugin>
</plugins>


Enter fullscreen mode Exit fullscreen mode

And this is at the beginning, after the artifactId and the version elements:



<packaging>gwt-app</packaging>


Enter fullscreen mode Exit fullscreen mode

This will extend maven adding the GWT specific executions to the maven lifecycle. So for example, after adding this if you run again the mvn package you will notice that there are various new steps, the most important one is the one that runs the GWT compiler including our project source code, and outputs the final JS. Note that this doesn't work right now, because we haven't updated the java source code! There are 2 configs, the moduleName points to the main gwt.xml file (explained later) and skipModule is used to avoid a nice but a bit "magically" utility from this plugin that will generate the gwt.xml file for you, for now, I prefer to create it manually in the next step, so I just set the plugin to not generate this file for me.

Update the IntelliJ project so the dependencies get downloaded and added to the project classpath.

Now, we will update the current App class that runs in the JVM to make it run on the client-side. Make App implements com.google.gwt.core.client.EntryPoint, remove the static main method and implement the onModuleLoad with the equivalent code. Simple, right? It is almost the same, main for the JVM and onModuleLoad for GWT. Your class content should be:



package me.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Text;
import com.google.gwt.user.client.ui.RootPanel;

public class App implements EntryPoint {

    @Override
    public void onModuleLoad() {
        Text textNode = Document.get().createTextNode("Hello World!");
        RootPanel.getBodyElement().appendChild(textNode);
    }
}


Enter fullscreen mode Exit fullscreen mode

I think the code is self-explanatory, but… yep, getBodyElement returns the body of the web page so we can add the Hello World! and see it on our page.

Just one more thing about the App class, move it inside client package (probably your IDE has already complained about that if you have copy&pasted the previous code). This makes it a bit easier. Note that GWT apps are all about sharing code, so you probably end up with a server, shared, and client packages in your project. And although this is a minimal client only example, we will follow this convention, so move it to the client package (warn: if you are using IntelliJ it can change the pom.xml <moduleName> from me.App to me.client.App after moving the App.java to the client package, but it should be me.App so check it out, sometimes IntelliJ is too smart).

Next, create the gwt.xml file called App.gwt.xml (create it in the me package, NOT in the client). This name should match the package and name that we have configured in the gwt-maven-plugin moduleName configuration. Create the file with this content:



<module>
  <inherits name="com.google.gwt.user.User"/>
  <entry-point class="me.client.App"/>
  <!--<source path="client"/>-->
  <!--<public path="public"/>-->
</module>


Enter fullscreen mode Exit fullscreen mode

This file is called a GWT module file. It is required so the GWT compiler knows which sources should be compiled, i.e. GWT does NOT compile everything that is in the classpath, it only compiles the sources indicated in the source tag. It is commented because the module adds those 2 lines implicitly. The source path="client" indicates that all java classes inside the package {module-package}.client will be included, and this is why we have moved App inside the client package. The inherits module is a dependency, this module depends on the gwt.user.User module and User source will depend on other modules recursively. The second line entry-point specifies an entry point. So when the GWT final compilation is loaded on the web page, those entry points will be called. This is the onModuleLoad that we have created in the App class. This is the equivalent to the Main-Class manifest property for a jar file.

Finally, create an index.html file in me.public package with this content:



<!DOCTYPE html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>GWT • Hello App</title>
<script type="text/javascript" src="me.App.nocache.js"></script>


Enter fullscreen mode Exit fullscreen mode

The first 2 lines are a "strong" recommendation, title is optional, and the unique actual interesting line is the script. This will bootstrap the GWT transpiled code, and after some steps, it will end up calling your onModuleLoad entry point! yeah! As you can see, the name of the file is {moduleName}.nocache.js. The nocache is just an easy convention in GWT, the compiler generates various files, and some of them contain .nocache. and others contain .cache.. Files with .nocache. should NEVER be cached and .cache. can be cached FOREVER. This makes it trivial to add filters to the server to add cache headers, this is called GWT perfect caching™.

Note, this public/index.html is a utility that is configured in the GWT module file, but similar to the <source path="client"/> convention, all modules contain an implicit <public path="public"/> line. And, GWT compiler will copy everything from all modules public paths to the final compiler output. BUT, my recommendation is that you try to add as less as possible to public folders. GWT has a lot of options to add managed resources to your project, the public folder is just a drop-in that GWT copies blindly. I don't want to lose you here with explanations, but, believe me, if you add too many things into a public folder, it might be considered a code smell. At that point, ask for help (at the end of this post I'll explain where is the best place to ask for help).

Step 2 diff.

3. Package, Run, and Debug 🔥

GWT transpiles code to JS and to see the result you will need to open it in your browser. But first, you need to compile and package the project. Run:



mvn package


Enter fullscreen mode Exit fullscreen mode

This will generate the required files and put them in the project target folder. Then, after success, open the result, in mac, you can use open target/hello-app-HEAD-SNAPSHOT/me.App/index.html in the terminal. Otherwise, open that file in your browser or drag the file into the browser window. You should see Hello World! in your browser.

What is happening here? The index.html in me.App folder is the one that we have written previously in the public package. So this is not generated by GWT, it is blindly copied from our public resources. This file points to me.App.nocache.js that are placed in the same folder by the GWT compiler. This file is the GWT bootstrapper. It is responsible for choosing the final client permutation. It is called permutation because GWT defines a special type of compile property that can be used to choose between different "implementations", and it can use to generate specific final compilation results for all possible combinations of all those properties, each of these combinations is called a permutation (ex. chrome+es is a permutation for the browser chrome and language Spanish).

If you can see the Hello World! that means that all those steps have happened successfully. I suggest opening the dev tools console in your browser and checking the network panel, you can see that the browser loads the nocache file, and then it loads a weird {hash}.cache.js file which is the actual permutation. You can try out another browser to see that this permutation file is different because by default GWT will generate a specific permutation per browser. This is configurable, but I'll omit it in this guide. Between version, the unique file that should be checked is the nocache, because if something change, it will point to newly hashed files (this is why cache files can be cached forever).

Step 3: Local run

This is nice, but this is not so nice if you need to debug or re-load with small changes. During development, you will use a special GWT feature called codeserver. The codeserver is a server that will compile and serve the code on the fly. You can run the codeserver using mvn gwt:codeserver, but we are going to use in this case the goal mvn gwt:devmode. Ok, sorry, this is a bit confusing, but this will run 2 servers, the codeserver and another jetty just to open the index.html. I don't want to explain this, because it is a bit confusing and requires a long explanation. But for now, just keep in mind that what we are using is the codeserver, and we use devmode only to be able to open the index.html (all this will make more sense in a future tutorial about the server-side). So, please run mvn gwt:devmode. In IntelliJ, you can simply double-click in the gwt:devmode goal in the maven panel, super handy!

Step 3: Run codeserver

If you inspect the log carefully you can see both servers, the codeserver at port 9876 and the second jetty server at 8888. Start with the codeserver. Open it in your browser. For now only check that in the second point, where there is a list of modules, you see your me.App module. Hope you see it! Then, open the other server at port 8888 (both can be opened like localhost:9876 or localhost:8888 in any browser). When you open the jetty server, you will see your module directory, click on me.App/ to open that folder. This will end up opening our index.html, then it will fetch the me.App.nocache.js file but this time (and this is a bit of devmode magic) it will use a special nocache.js file that will detect the permutation and also it will communicate with the codeserver, compile the code on the fly and sent the permutation plus source codes to your browser. During a few seconds, you should notice a "Compiling me.App" dialog that will disappear on success. You can change the hello world message, e.g. remove the world part, and reload the page. This will fire the compilation again. This is the standard development lifecycle, edit and reload.

Now, I will ask you to move to chrome. You can do this in any browser, but easier to explain with one specific browser. Go to the devtools and open the Sources tab. Now find a resource (shortcut ctr+p or cmd+p) and write App to find our entry point class. You should see the Java file in the browser, this is because the codeserver generate JS source maps automatically, and chrome resolve that mapped Java sources and shows it in the devtools. Click on the RootPanel.getBodyElement line number to add a breakpoint, it should turn blue indicating an active breakpoint. Then, reload the page. If you have done it correctly, the debugger should stop in that line, you should be seeing something like this:

Step 3: debug

This is all you need to debug GWT code. But, note that you can write a lot of code in pure Java, this code, especially if you avoid the UI final layer, is trivial to run in JVM or to test using JUnit. GWT is all about sharing, and about using Java tooling, so if you are developing tools like for example a spatial-index, it is much easier and faster to test, run and debug it using plain Java. And then use it on the client-side.

4. Spice it up 🌮

And this is where the personal touch gets crazy. Now I'm going to explain how to add 2 libs, a "pure" JS lib (Elemental2), and a "pure" Java lib (RxJava). I have chosen both libraries on purpose as opposite extreme cases. Using the "pure" JS libraries you should see how you can access native JS code in GWT and how easy and lightweight it is. And using the "pure" Java lib you'll see that in GWT you can use classic pure Java libraries in the browser. But, we are not going to depend directly on those 2 libs, instead, we will use this dependency graph:

Step 4: dependencies

Elemental2 is a Google library that exposes the whole Browser API in Java. The unique minor problem with this library is that in some cases the API is not javaish enough, specifically, events and element creation requires casts which is not common in the Java world. So, although we will use this library behind scenes, we are going to depend directly on a super small RedHat library called Elemento that adds those missing parts. This library is a handcrafted API for elements and events, a beautiful library that gives us the power of JS with the type-safety of Java.

RxGWT is a set of utilities to use RxJava in GWT, i.e. same as RxAndroid but for GWT. RxGWT depends on RxJava GWT, a thin GWT adapter library over RxJava. Yep, ok, you cannot depend directly on RxJava, but if you go to the repo you will see that there are just a few minor changes and configurations to make it work in GWT, almost all of the actual RxJava source-code is the same.

Remember my recommendation; the idea with those 2 libraries is that you get able to find JS+RxJS projects and migrate to Java+RxJava with GWT using your Java knowledge! This is an awesome way to get used to GWT and there are a lot of fun micro reactive projects that can be improved!

To add this dependencies update the pom.xml with:



<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>me</groupId>
  <artifactId>hello-app</artifactId>
  <version>HEAD-SNAPSHOT</version>
  <packaging>gwt-app</packaging>
  <name>hello-app</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.google.gwt</groupId>
        <artifactId>gwt</artifactId>
        <version>2.9.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-user</artifactId>
    </dependency>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-dev</artifactId>
    </dependency>
    <dependency>
      <groupId>org.jboss.elemento</groupId>
      <artifactId>elemento-core</artifactId>
      <version>1.0.0-rc3</version>
    </dependency>
    <dependency>
      <groupId>com.intendia.gwt.rxgwt2</groupId>
      <artifactId>rxgwt</artifactId>
      <version>2.3</version>
    </dependency>
    <dependency>
      <groupId>com.intendia.gwt</groupId>
      <artifactId>rxjava2-gwt</artifactId>
      <version>2.2.20-gwt1</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>net.ltgt.gwt.maven</groupId>
        <artifactId>gwt-maven-plugin</artifactId>
        <version>1.0.1</version>
        <extensions>true</extensions>
        <configuration>
          <moduleName>me.App</moduleName>
          <skipModule>true</skipModule>
        </configuration>
      </plugin>
    </plugins>
    <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.1</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>


Enter fullscreen mode Exit fullscreen mode

We have added a special dependency of type pom and scope import called BOM. This is a utility dependency that asserts that all dependencies defined in the BOM will be of the version specified in the BOM itself. This is useful because we can end up with various gwt-xxx libs with various versions and this might be a problem, so this BOM asserts that all GWT core dependencies are at the same version.

Alos, we have added 3 new explicit dependencies, elemento-core, rxgwt and rxjava-gwt.

Then, go to your App.gwt.xml module file and add this 2 dependencies:



<inherits name="com.intendia.rxgwt2.RxElemento"/>
<inherits name="org.jboss.gwt.elemento.Core"/>


Enter fullscreen mode Exit fullscreen mode

If you still have the gwt:devmode running you will need to restart. There are new maven dependencies, and as those dependencies should be added to the classpath, you will get forced to restart it. It is just a few seconds, so no problem. Stop it and run mvn gwt:devmode again. Open localhost:8888 and go to app.App and check that you still see the Hello World! in your browser.

Now, update the content of App.java with:



package me.client;

import com.google.gwt.core.client.EntryPoint;
import org.jboss.elemento.Elements;

public class App implements EntryPoint {

    @Override
    public void onModuleLoad() {
        Elements.body().add("Hello World!");
    }
}


Enter fullscreen mode Exit fullscreen mode

Cool, this is much less verbose. Elements is an elemento utility, it contains all those user-friendly type-safe element APIs. Most of the types of the Elements methods return builders which are wrappers around the actual elemental2 type. You can extract the elemental2 type calling get(). At that point, you are accessing the browser API almost directly. GWT will transpile the Java source-code to JS but a line of code like this DomGlobal.document.body.background = "red"; will gets translated to document.bod.background = 'red';, almost the same. TIP: Navigating through the elemental2 source code is a good strategy to learn how to map native API in Java GWT.

Now we are going to apply RxJava, and update the content of App.java to:



package me.client;

import com.google.gwt.core.client.EntryPoint;
import com.intendia.rxgwt2.elemento.RxElemento;
import elemental2.dom.HTMLElement;
import org.jboss.elemento.Elements;

import static elemental2.dom.DomGlobal.document;
import static org.jboss.elemento.EventType.mousemove;

public class App implements EntryPoint {

    @Override
    public void onModuleLoad() {
        HTMLElement el = Elements.span().style("font-weight: bold;").element();
        Elements.body().add("mouse position: ").add(el);
        RxElemento.fromEvent(document, mousemove)
                .subscribe(ev -> el.textContent = ev.clientX + ", " + ev.clientY);
    }
}


Enter fullscreen mode Exit fullscreen mode

We have replaced the hello world with a mouse position text, a span, and an event listener for mousemove events in the page document. This is a pretty simple code, but with lots of nice things! Elements.span() is an elemento builder, see how easy is to set the style and to get the element using its fluent API. HTMLElement is an elemental2 type, which is almost like using the browser API directly. RxElemento.fromEvent is a RxGWT utility that combines the elemento type-safe events with RxJava. This is the actual type Observable<MouseEvent> returned by fromEvent, i.e. it is an Observable of the concrete event type. This observable will add a new event listener to each subscription and will remove it on unsubscribe. The last line is the actual subscription that will update the el span element with the mouse client coordinates.

In this micro example, we are mixing a pure Java lib to subscribe and compose events with a browser-native API. It's so simple that might not impress, but this is pretty awesome and powerful if you think about it 🤯! Actually, if you are an android developer and you have a lot of experience with UI, MVP, Dagger, RxJava, and all those fancy things to manage your UI state then this should be your starting point to start applying all this knowledge to create web-based UI applications!

Step 4 diff.

Conclusion 👋

Disclaimer; no big conclusions here BUT I hope you liked it and made you curious enough to keep digging into GWT. GWT is a super powerful transpiler. We have not even talked about how it can manage resources (JS, CSS, HTML, translations, images, and more) and embed it all into one single JS file. It is huge, but even ignoring all those extra utilities, just as a "simple" transpiler, it is more than enough to be useful for all those Java experts that want to write browser code.

If you like this intro, I'll try to make some client-server tutorials. I really think that client-only APPs are the best starting point, but yep, people love the idea of writing the client and server in the same language, and probably almost everyone using GWT is using it with this goal in mind. But, of course, this tutorial will be a pretty biased one too 😬.

There is a project to start with GWT using a spring boot approach. I personally prefer a manual approach as explained in this guide because the spring boot approach adds many dependencies and makes you feel a bit like you have loose control. But if you like it, then you will love this project gwt-boot-samples and it is even easier to start with. Anyway, this project has various modern popular solutions, so even if you don't use the dependencies themselves, you can get inspired and configure it manually.

Finally, my recommendation about asking for help:

  • stackoverflow gwt - pretty obvious, but yep, the best place to standard problems
  • gitter gwt - gitter chat, this is pretty active, if you have no idea or have a quick question this is the best place
  • groups gwt - contains a lot of old questions, also there are various specific groups for contributors, the steering committee, various classic GWT libs, and more

Those 3 places should be enough. But, if you want to find more things, maybe some surprise, then go to awesome gwt where there is an infinite list of useful GWT resources, tutorials, libs, videos, blogs, and more!

Top comments (5)

Collapse
 
tbroyer profile image
Thomas Broyer

Great intro to GWT !

Two small notes :

  1. you talk about sharing code with the server, but being Java you can also just as easily share it with an Android app, and with J2ObjC with an iOS app.

  2. out of curiosity, why are you using skipModule and src/main/java/me/App.gwt.xml, vs src/main/module.gwt.xml?

(I won't start a flamewar about putting the index.html and App.gwt.xml inside src/main/java or src/main/resources 😉 should we add a src/main/gwt?)

Collapse
 
ibaca profile image
Ignacio Baca Moreno-Torres • Edited

Oh, I missed this comment. As always, thank you very much for reading and proposing improvements! I have updated a bit changing "share between client and server" with "sharing cross-platform code (JVM, Android, web, and ios)". I need to review it a bit.

About using skipModule, I commented about that many years ago. Although I think it is a pretty good idea, in practice (and IMO) it just add more confusion to how GWT works and how to create a GWT project. I still think this is a perfect approach to be enforced in GWT3 plugins, but using it in the super slow and confusing GWT2 world was a bad idea. If I was used it I'll need to explain that GWT works using App.gwt.xml, but that if and only if you use the tbroyer maven plugin you can auto-generate it, then I need to explain the gwt-lib type (used to auto-add inherits), that is not the same that gwt-lib package, and that you need to put it in a different folder... etc.

About index.html and App.gwt.xml; yep, this might not be the best suggestion for a beginner. But I really don't like what happens if you put it in the resource folder, it gets duplicated into the target/classes folder, then if you modify it in the resources folder, it might not be updated by your IDE in the target folder, causing a confusing situation for them. So, I just leave it there for this minimal starting guide. But yep, in a library project, I won't do that for sure! The src/main/gwt, please, leave it for the gradle version 😉

Collapse
 
tbroyer profile image
Thomas Broyer

There are basically two approaches to learn things:

  • bottom-up: explain the concepts of GWT modules, what are the GWT tools and what their inputs are, say what needs to be done, then finally how it can be done with Maven, and in that final step you can say that the module is generated from src/main/module.gwt.xml and <moduleName>
  • top-down: explain how things are done with Maven and what commands to use when (create a src/main/module.xml, choose a package name and configure <moduleName> from it by appending a simple name, e.g. .App, and put your code in a .client subpackage; also configure the moduleShortName which will be used to compute the name of the output JS files), then progressively (not necessarily in the same article) explain what happens under the hood (e.g. "actually, GWT needs a module as input that needs to live in a package; the Maven plugin will rename your src/main/module.gwt.xml based on the <moduleName>, and will inject a rename-to attribute with the <moduleShortName>")

You can choose either approach, but IMO you should stick to the one you chose.

It should also be clear whether the target audience are people new to GWT, or people who already used Maven to build GWT apps. For the first group of people, you need to put apart your own feelings about migrating from Mojo's plugin to mine; for the second group you'll likely want to explain how to convert their project, or at least what the differences are between their old approach and the "modern" one (your own term)

But well, this is your article, not mine; and (disclaimer) I haven't re-read it (just skimmed through).

Collapse
 
magallo profile image
Magallo

Very nice article! You suggested me to try experimenting using GWT with VS Code (using the MAven pluign): I followed you article and was able to do everything step by step using VS Code instead of IntelliJ. Very nice! I would be intereseted in a second article regarding also the server part. How can I add a server part to this simple sample project explained here? What 'mvn' command should I run to start also server side code? My final goal is to be able to fully create and manage (edit, run, test, debug) a maven gwt project inside VS Code. Are you going to pusblish a new articole on this? Could you answer to my questions and doubts? It would be very nice. Thanks.

Collapse
 
ibaca profile image
Ignacio Baca Moreno-Torres

Our approach to managing the server-side is quite straightforward and has proven effective for many years. Essentially, we use embedded servers and programmatically run them via a Java main method. You can see an example of this approach here. This method involves running or debugging a plain Java executable, which is highly compatible across different environments.

Although it's possible to compile GWT and integrate it on the server side to make it accessible through the same server, we have moved away from this method. Currently, if you're utilizing Docker, you can set up an httpd or nginx server in just a few lines. Additionally, configuring the GWT perfect cache requires only a few extra lines. This method is more straightforward, offers better performance, and provides the flexibility to update the client side or maintain multiple client-side versions. For an example of a Docker configuration that achieves this, check this docker config.