A Minimalistic Guide to Building and Deploying Monolithic Spring Boot React Applications

Using Gradle, WebJars, and Heroku

Shekhar Gulati
Xebia Engineering Blog
6 min readSep 9, 2019

--

Photo by Anas Alshanti on Unsplash

I work with many project teams and one pattern that I have seen repeated multiple times is that teams create separate repositories for their front-end and back-end parts and then they struggle to keep things working together. They end up using different deployment models to manage them and waste a lot of time in integration.

I think the main problem is that most teams start thinking about separation of front-end and back-end too early in their lifetime. They start thinking about Docker and Kubernetes and how front-end and back-end service will talk to each other rather than solving the problem at hand. This leads to accidental complexity. Accidental complexity is the problems that developers create for themselves.

In this post I will share how I go about implementing small applications or proof of concepts. I keep my applications modular so if in future I need to create separate deployment units I am able to do that.

I prefer to use Monolithic applications at the start. This keeps feedback cycle short and I can focus on the business problem at hand. For some reason, developers think Microservices is a silver bullet that can make their applications performant and scalable without much thought and pain. I am not in that group. I will recommend that you read the post — Microservices — Please don’t by Sean Kelly.

I read somewhere that successful Microservices architecture implementations were all refactored from monolithic architecture.

With time you learn about your business problem better and you will know where to cut the boundaries.

Prerequisite

To follow along with this guide you will need following installed on your machine

1. Java 8: Download and install the JDK from official website

2. Node.js : Download and install the latest version of node

3. Heroku CLI: Download and install the latest version

In the remaining part of this post, we will create a multi-project Spring Boot Gradle application. There will be two modules:

1. backend: This contains Spring Boot based backend written in Java.

2. frontend: This contains React based frontend of the application.

By the end of this post, you will be able to build the whole application as a single fat jar using Gradle. We will deploy our app to Heroku.

Step 1: Create Spring Boot project using start.spring.io

The easiest way to create a Spring Boot project is to use Spring Initializr available at http://start.spring.io. You can use either the web user interface or tool like cURL to create the project. Below is the cURL command that will create the starter project in the spring-boot-react-app` directory. Navigate to the location where you want to create your project.

$ curl https://start.spring.io/starter.zip -d type=gradle-project 
-d dependencies=web -d groupId=com.xebia
-d artifactId=spring-boot-react-app -d
name=spring-boot-react-app -d
description="Spring Boot React Application"
-d baseDir=spring-boot-react-app
-o spring-boot-react-app.zip
&& unzip spring-boot-react-app.zip
&& rm -f spring-boot-react-app.zip

Please note that you don’t have to type $. $ signifies command-prompt.

You need to have unzip utility installed on your machine. If you don’t have the required tools, then you can create app using http://start.spring.io/ web interface.

The above command will create a Gradle based Spring Boot project. The project uses Gradle wrapper that means you don’t need to install Gradle on your machine. Gradle wrapper will first download the Gradle version and use it.

Change directory to spring-boot-react-app

$ cd spring-boot-react-app

To build the project you can run the following command.

$ ./gradlew clean build

If you are a Windows user, then you can the following command.

$ gradlew.bat clean build

To run the application, you can use ./gradlew bootRun command.

The application will be accessible at http://localhost:8080/.

Step 2: Make a Multi-project build

The Gradle project generated by Spring Boot has a single module. As mentioned earlier, we need to create a Multi-project Gradle build.

Make sure you are inside spring-boot-react-app and run the following command.

$ mkdir backend frontend

Move src directory and build.gradle file to backend directory.

Update settings.gradle to include both the projects.

rootProject.name = ‘spring-boot-react-app’include ‘frontend’include ‘backend’

Create a build.gradle file in the spring-boot-react-app directory. We need to do this because we moved original build.gradle to backend directory.

$ touch build.gradle

Create empty build.gradle inside the frontend directory as well.

Run the full build to ensure everything is working.

$ ./gradlew clean build

Step 3: Create a React application

In the previous step, we created the multi-project Gradle Spring Boot application but we haven’t yet created the React application inside the frontend module.

Change directory to frontend and create a new application.

$ npx create-react-app .

Delete the .git directory inside the frontend

If there is a yarn.lock file then delete it and run npm install . It will create package-lock.json. We will be using npm.

You can run the application using npm start command. The application will start at http://localhost:3000/

Step 4: Build frontend React code using Gradle

Create a build.gradle file inside the frontend directory and populate it with the following contents.

plugins {id “com.moowork.node” version “1.3.1”}apply plugin: ‘java’apply plugin: “com.moowork.node”node {version = “12.9.1”download = true}task bundle(type: NpmTask, dependsOn: npmInstall) {args = [‘run’, ‘build’]}task uiTest(type: NpmTask) {environment = [‘CI’: ‘true’]args = [‘run’, ‘test’]}task run(type: NpmTask) {args = [‘start’]}check.dependsOn(test)jar.dependsOn(bundle)

In the code above, we did the following:

• We made use of moowork node Gradle plugin to download and install node

• We define a couple of tasks to run tests and run the application. You will be able to run the application using ./gradlew :frontend:run

• We made Gradle jar task depend on bundle task. The bundle task will create frontend distribution. It will run npm run build

Now, go back to the root directory and run the ./gradlew clean build. This time both frontend and backend modules will be built.

Step 5: Creating frontend as webjar

WebJar allows you to package your client side dependencies as a JAR file. Spring Boot is preconfigured to handle them. It will serve the index.html in the jar’s META-INF/resources directory. I find this a clean way to package frontend code.

Update the build.gradle of frontend module to define a webjar task as shown below.

… // Rest remains the sametask webjar(type: Jar) {from(fileTree(“build”)) {into “META-INF/resources”}}check.dependsOn(test)jar.dependsOn(bundle)jar.finalizedBy(‘webjar’)

In the code snippet above, we did the following:

1. We defined webjar task. This task copies resources from build directory to the META-INF directory. This is required as the JAR plugin will copy them to the same location. Spring Boot will automatically understand that it can render web resources from META-INF directory.

Step 6: Adding frontend dependency in backend

We want to bundle frontend JAR in the backend. So, we have to add one dependency in the backend module build.gradle as shown below.

dependencies {implementation project(‘:frontend’)… // Rest remains same}

Build the project again.

$ ./gradlew clean build

Now, when you run the backend.jar you will see the React app being rendered.

$ java -jar backend/build/libs/backend-0.0.1-SNAPSHOT.jar

Go to http://localhost:8080/

Step 7: Deploying to Heroku

We will start by first initialising our project as Heroku project.

$ heroku create spring-boot-react-app-webjar

The project that we have created is a multi-project Gradle build project so we need to help Heroku deploy our application. These steps are covered in Heroku docs.

First, we need to create a gradle/heroku/stage.gradle file in your repo with the code that defines the stage task for all sub-projects. For example:

task stage(dependsOn: [‘build’])

Then apply the stage.gradle in your root project’s build.gradle like this:

subprojects {apply from: file(“$rootProject.projectDir/gradle/heroku/stage.gradle”)}

Next, we need to create a Procfile in the root directory to tell Heroku which JAR it should run.

web: java $JAVA_OPTS -Dserver.port=$PORT -jar backend/build/libs/backend-0.0.1-SNAPSHOT.jar

Finally, commit and push to Heroku

$ git add — all$ git commit -am “Pushing to Heroku”$ git push heroku master

You will see your application running on Heroku

As we are using free resources provided by Heroku so at times your build will get stuck.

If you don’t want Heroku to build the project then you can directly deploy the JAR file as well.

Please refer to the Heroku documentation for more information.

If you like this post then clap this post and follow us on Medium.

If working on Java and related technologies, building web applications using the latest JavaScript framework are things you find interesting, you might enjoy working with us at Xebia!

--

--