An example project demonstrating how to render both vanilla Thymeleaf templates and ReactJS components together.
The server side rendering of the JS React components is made possible by using GraalVM.
yarn install
yarn dev
./gradlew bootRun
Then navigate to http://localhost:8080/
- Java 11 (necessary for GraalVM integration)
The project can broadly be grouped into three distinct parts:
./components-src
This is where the frontend JS React templates live.
For each component type there is a *-server and *-client file which represents the code which will be executed on the server and client, respectively.
The server side file uses the standard ReactDOMServer.renderToString function and passes some values onto the window object
for the client side to pick up.
The client side file will attach to the root component dom element generated by the server (using some convention of component names to
for a known id value). It will use the standard ReactDOM.hydrate function to client side render the same component.
This example demonstrates rendering a selection of components from different sources, ranging in complexity. The build
process (using webpack) will take these sources, minify / transpile them etc and output to ./src/main/resources/public/generated
See the following for the most basic example: https://github.com/davehancock/sample-react-component
./src/main/resources/templates
This contains a few thymeleaf templates for the layout and content. Fairly standard overall, but does refer to and expect
the output client templates produced by webpack to be present at the ./src/main/resources/public/generated location.
The server side rendered templates are referred to through the use of a ModelAttribute (effectively it will be an inline string but used as if it were its own template)
./src/main/java/**
Fairly typical Spring Boot MVC application. The AppController will delegate to a TemplateRenderer (passing some initial derived
state), and expect a single string in response. This string will then be added to a ModelAttribute, able to be referenced from
a Thymeleaf template.
The inclusion and registration of a StringTemplateResolver means that the raw string can be treated as a template to then be
rendered like any other Thymeleaf template.
The TemplateRenderer is simply a thin abstraction on top of GraalVMs polyglot library. This allows for the execution of
JS from a Java based process.
Some conventions for the components are used here, together with some base path to read from the FS. In short, it reads the
raw contents of the component *-server files and renders these to a string (using some thin html template file ./src/main/resources/ssr-template.html).
Some polyfill functions are supplied to allow for the execution of these components which may expect some browser only built-in functions to be declared.
Running yarn dev starts webpack with --watch enabled. This means that the client component files can be changed and the contents
will be automatically copied across to the location which the Thymeleaf templates expect. In short, this means development changes can
be made without restarting or rerunning any other commands.
(N.B By default Spring Boot + devtools won't cache thymeleaf templates when ran locally)
This project demonstrates the ability to render JS server side together with using Thymeleaf templates in almost a "worst case" scenario. The generated JS components are large, not optimized and there is no caching present at all on the server side.
Obvious caches to be added include on the template engine render function itself, as well as on each of the clients responsible for fetching the server side state.