An example application that uses a Spring Java backend with a React frontend and can perform server-side rendering (SSR).
Yes, but with Java. It's inspired by the spring-react-isomorphic project, but at this point has been largely rebuilt from the ground up. The frontend is build on create-react-app (CRA), though it was necessary to "eject" from CRA in order to apply some changes for server.
The project also uses:
You also get:
JSON.stringify
, meaning it can't be used to serialise the Redux state.
Without this you'll have a bad time trying to use your Java objects in
your Redux state.polyfills.js
has been changed to be SSR-friendlyDEBUG
environment variable (see below).render
functionWe implement a custom render function for Spring to call. The source code
is in src/main/js/react-render/renderer.js
, and is compiled to ES5 syntax
during the Maven build. The build process also pulls in polyfills, to allow
React etc to work, and also the frontend's JSON manifest, in order to
locate the frontend's built assets. See the build.sh
in the same
directory for how the final render code is assembled.
Execute mvn
if you have Maven already installed, or ./mvnw
if you
don't. You'll need Java8
installed
either way at a MINIMUM version of 1.8.0_65
. Older versions have a bug
that makes rendering brutally slow. Note that since React is not
thread-safe, Spring is configured to use a script engine per thread, and
each one will have to load the bundle when first initialises. You may want
to force refresh the website several times to make sure all the threads are
initialised, particular if you intend to measure performance.
To run the frontend in hot-module reloading mode, switch to another terminal and execute:
cd src/main/app
yarn start
Your browser should automatically open
http://localhost:3000. Now when you edit your
files, the changes will be loaded in your browser automatically and, where
possible, be applied without losing the application's current state thanks
to react-hot-loader
!
Controllers that render views are suffixed with Controller
. REST endpoints are
suffixed with Resource
and handle requests under /api
.
In order to preempt runtime errors with Nashorn loading the bundle, a test
script is executed by Maven during the test-compile
phase, located at
src/test/js/react-renderer/test.js
. If this script fails, you can diagnose the problem
by running:
DEBUG=true mvn test-compile
This will rebuild the webpack bundle without minification, which should make the cause of any error clearer.
It's easy to create a bundle that's broken on the server by including code that
expects a DOM - and that includes the Webpack style loader. This is the root of
most problems. You should note that server-side rendering does not require a
DOM - which is why src/main/js/react-renderer/polyfill.js
doesn't provide
any window
or document
stubs.
This isn't necessarily the best way to write a React application or a Spring application. Pull requests welcome!