How to combine a UI with a backend

Sean Franklin
4 min readApr 15, 2019

--

This guide will walk you through the step-by-step process on how to create a modular monolith by combining a frontend UI with a Spring Boot Gradle backend. Check out my previous article on why monoliths are making a comeback and it is not necessarily a bad thing.

This Github repository was created to provide a working example of a combined Spring backend and UI application. The commits have been segmented to correlate to specific steps that show the code and config changes required for those steps.

Prerequisites:
- An existing or newly created Spring Boot application using Gradle (you can generate a new one at start.spring.io)
- An existing or newly created frontend application (you can create a react app by following this guide)

Combining a Spring backend with a frontend app:

Note: this commit shows the code changes resulting from steps 1–5

  1. Create a new directory in your Spring app’s root directory that will be used to hold your frontend code later on, I called mine “frontend”.
  2. Create a settings.gradle file in the root Spring project directory if it does not exist already.
  3. Add the following line to the settings.gradle file using the name of the frontend directory you created. This tells the spring app to check in the frontend directory for possible project configuration.
include 'frontend'

4. Add the following code block into the existing “repositories” section of the build.gradle file. This block tells the Spring backend to add the entire “/frontend/build” directory to the public folder of the jar at build time. In a Spring application if there is an index.html file in the “public” directory of the built code it will be served to the user when the root URL of the application is hit via a browser.

Note: This step assumes that you will be building your frontend code into a directory called “build” and that built UI code contains an index.html file.

processResources {
from ('frontend/build') {
into 'public'
}
}

5. Create a build.gradle file inside the frontend directory and add the below code to it. The Moowork plugin adds the ability to use gradle commands to run npm scripts from the root project dir.

plugins {
id "com.moowork.node" version "1.2.0"
}

6. Add your entire new or existing frontend project into that new directory.
Note: this commit shows a basic React application added to the project.

7. Validate that npm commands are wired up with Gradle by running the gradle npmInstall command from the root project directory. This is the same as running the npm install command within the frontend directory.

Note: You can run any npm command via a gradle command by converting the spaces to underscores. For example npm run test can now be run by using gradle npm_run_test and npm start can be run using gradle npm_start

8. Run your frontend build command followed by your backend start server command to view your full stack application hosted on one server.

Note: If using a standard Spring Boot backend and a create react app frontend, you can run gradle npm_run_build to build the frontend static files followed by gradle bootrun to start the app.

8. Important: Now that everything is wired up lets speed up the time it takes to get paint to the screen. This is done by enabling GZIP compression in the backend to shrink the size of the UI files being served from the server to the browser. For reference, after enabling compression and serving up a new create react app project (v2.1.5) the main chunk of JS served up to the UI was ~40KB, compared to ~125KB before compression. This can be enabled by adding the following three configuration items to the Spring application.properties or application.yml file.

Note: See this commit for reference.

# Enable response compression
server.compression.enabled=true
# The comma-separated list of mime types that should be compressed
server.compression.mime-types=text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json
# Compress the response only if the size is larger than 1KB
server.compression.min-response-size=1024

10. Optional, unless you’re using a router in your frontend that changes the url. You need to add a backend controller to allow a browser refresh from one of the router routes. The reason this is needed is because a Spring app will by default only serve up the index.html file when the root route (“/”) is hit. Within your UI when the url changes to something else, lets say “/blog” for this example, and the user refreshes the page the Spring backend tries to look for an endpoint called “/blog”, but can’t find one. By adding a controller, similar to the one below, that contains all of your UI routes then your UI will be served to the user no matter which router route they try to hit.

Note: This commit shows where I added a router to the frontend and a new backend controller to allow page refreshing from the “/blog” route

@Controller
public class IndexController {
@GetMapping({"/home", "/blog"})
public String index() {
return "index.html";
}
}

All done, your combined application should provide you with all the functionality you had with two separate apps! Enjoy the reduction to your operational costs!

--

--