Integrating React with Google Web toolkit (GWT)

Aprajita
3 min readOct 21, 2021

--

Before you wonder “Isn’t GWT dead in 2021?” Let me answer, no it is not dead. It has survived and is still relevant. The latest release was published in May,2020 and it has pretty much survived Killed by Google scythe. Much to JavaScript developer pleasure it has been also in path to be able to integrate and coexist with modern JavaScript libraries.

The aspiration behind this write-up is the fact that there are still many huge legacy applications which have been developed using GWT. And there comes a situation when you want to use a modern library like React in these existing applications.

To be noted, I will consider both JSNI and JsInterop implementation. (JSNI has been removed from GWT 3 onward)

Also we are trying to find a way to integrate (not completely rewrite or replace) React into GWT.

We would be using global functions defined on windows scope to integrate/communicate between GWT and React

Step 1: Creating React application

create-react-app would be the best place to start with for creating a simple new single-page application using react with basic configuration.

For rendering an element into the DOM, we usually have a “root” DOM node inside which everything will be managed by React DOM.

You will find a code snippet like this inside your index.js

ReactDOM.render(<App />, document.getElementById(“root”)); ​

The “root” element would be defined inside index.html

In our case instead of attaching react element to the “root” defined inside index.html we would expect GWT to pass on the element inside which we would render react elements.

export default function renderReactComponent(selectorFromGwt) {
ReactDOM.render(<App />, document.getElementById(selectorFromGwt));
}
window.renderReactComponent = renderReactComponent;

Step 2: Build react application

To be able to use the created react component, build the application. In our case app is created using create-react-app so run following:

npm run build

It builds the app for production and publish inside the build folder.

Important note: Instead of using basic create-react-app we can use any other boilerplate, based upon the technology selection of your react app. (We went for express+react+typescript+webpack)

Step 3: Include react resources inside GWT

GWT provide multiple ways to include an external JS resource. Few options are listed below:

Using ScriptInjector.fromUrl()

Using JsniBundle

Placing script tag directly inside your index.html

In our case we used ScriptInjector.fromUrl() to load the JS bundle and CSS file generated by step 2.

Step 4: Creating a panel in GWT to render react component

Inside your GWT code you can create a panel which could be used to render react component as below (both JSNI and JSInterop ways are defined, choose either based upon version of GWT):

public class PanelForReactComponent extends Composite {
private static Binder uiBinder = GWT.create(Binder.class);

interface Binder extends UiBinder<Widget, PanelForReactComponent> {
}

@UiField
ScrollPanel content;

public PanelForReactComponent() {
initWidget(uiBinder.createAndBindUi(this));
content.getElement().setId(“root_for_react_component”);
}

@Override
protected void onLoad() {
super.onLoad();

//use either JSNI or JSInterop as shown below
renderReactComponent_JSNI(“root_for_react_component”);
renderReactComponent(“root_for_react_component”);
}

private native void renderReactComponent_JSNI(String root)/*-{
(function(root) {
$wnd.renderReactComponent(root);
})(root);
}-*/;

@JsMethod(namespace = JsPackage.GLOBAL) // this translates to JS method defined in window namespace
public static native void renderComponent(String panelId);
}

To enable communication between React and GWT, we can create functions with windows scope at both end.

Step 5:

At GWT side:

//Using JSInterop

@JsType(namespace = JsPackage.GLOBAL, name = “ReactGwtInterface”)
public class ReactGwtInterface {

/**
* To be called as window.ReactGwtInterface.fromReactToGWT(parameters);
*/
@JsMethod
public static void fromReactToGWT() {
}

/**
* Method defined inside react
*/
@JsMethod(namespace = JsPackage.GLOBAL)
public static native void fromGWTToReact();

}

//Using JSNI define a method to add/call functions defined in windows scope

private native void bootstrapReactComponent(String root)/*-{
(function(root) {
$wnd.fromReactToGWT = function(data) {
console.log(data);
};
$wnd.fromGWTToReact();
})(root);
}-*/;

At React side:

export function fromGWTToReact() {
}

window.fromGWTToReact = fromGWTToReact;

This is the simplest way we can integrate a React component into existing GWT application. While defining architecture it is important to maintain clear interfaces at both side. It is advisable to use JSInterop as it provide annotation based structure, but if that is not possible(in legacy application use JSNI).

--

--