We have a react webapp and a spring boot application(built with maven) in development.
The React app(on npm) and boot app are running separately but time has come to now integrate them and put it into QA/staging.
We are using webpack for bundling the react application.
The boot app is a single module with REST API(consumed by the react front-end) with hibernate for database persistence.
Questions
I found resources on web where both the react and the boot applications were on separate repos/directories without any integration, which is not optimal; I am yet to find a resource where both webapp resources and boot resources are in the same directory tree which also accounts for development lifecycle and production lifecycle.
Bonus : The react developers know only html/js/css. Is it possible that they have only the react app resources in their vscode/webstorm project ?
The basic idea of what Spring Boot and Create React App do.Create React App helps you start a React project very quickly. It gives you all the basic things you need to get up and running asap. Spring boot helps you start and maintain a spring application quickly and easily.
In the development phase, we can run React and Java on separate ports. In the production phase, we packed the entire React source code and Java code into a deployable war file. In the production phase, you can build the React app and put all the assets in the build folder and load it with the java code.
So, here is a quick guide how to run a react frontend and a spring boot backend on the same port and how to package them as a single jar file. First, create a spring boot project with https://start.spring.io. Add the Web dependency. Set the groupId and artifactId to whatever you want.
We have a react webapp and a spring boot application (built with maven) in development. The React app (on npm) and boot app are running separately but time has come to now integrate them and put it into QA/staging.
Using React to call Spring Rest API: Otherwise, when deploying React production-build with Spring Boot project, we only need to run Spring Boot Project for the fullstack (React.js + Spring Boot) system. In this example, we access http://localhost:8080/.
It acts as a plugin and performs npm install and npm run build for the build process of the react application and finally copies the files to the static directory of the spring boot from where it is served. We also need to make modifications in the spring boot security config for react-router to work.
You can use your own React Project, or just download the source code on Github, or follow these steps to create a new one. Open cmd and create a new React Project as following command: After the process is done. We create additional folders and files like the following tree: App.css App.js
You can run React and SpringBoot on the same port and Package them as a single artifact !! Please follow the steps that I have explained here, that should get you up and running. To answer your questions-
Here is the Github link of the demo project that I am going to explain here
Spring Boot can serve static content from src/main/resources/static
folder. We will exploit the above mentioned feature of Spring Boot to serve the single page of the react project. We will serve a html page from the static folder in the target directory, not in the source directory.
The Project structure-
First, create a spring boot project with https://start.spring.io. Add the Web dependency. Set the groupId and artifactId to whatever you want. Generate the project and unzip it into your project directory.
Or, if you are using Spring Tools Suite you can simply click
File->New->Spring Starter Project
and mention the required details to create a spring boot project.
The frontend
folder inside src/main
should have your react application build using create-react-app.
So, there are two steps-
We we will use two maven plugins and Thymleaf for that.
For frontend-maven-plugin at Step 1-- If you closely look at the pom.xml
there I have mentioned the src
directroy from where frontend-maven-plugin will take the files, create the production build and place the contents inside the output directory mentioned(inside src/main/frontend/build
).
<workingDirectory>${frontend-src-dir}</workingDirectory>
<installDirectory>${project.build.directory}</installDirectory>
For maven-resources-plugin at step 2-- It will take the production build that was just created by frontend-maven-plugin and place it inside your root directory then target/classes/static
.
Then we will use Thymleaf to serve the static content from the target/classes/static
using a rest endpoint in the controller. Or else you have to type in the name of the html file
, like http://localhost:8080/index.html
Your pom.xml should look like this-
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.springreact</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Run React Frontend and SpringBoot Backend on the same port.</description>
<properties>
<java.version>1.8</java.version>
<frontend-src-dir>${project.basedir}/src/main/frontend</frontend-src-dir>
<node.version>v14.15.4</node.version>
<yarn.version>v1.16.0</yarn.version>
<frontend-maven-plugin.version>1.7.6</frontend-maven-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>${frontend-maven-plugin.version}</version>
<configuration>
<nodeVersion>${node.version}</nodeVersion>
<yarnVersion>${yarn.version}</yarnVersion>
<workingDirectory>${frontend-src-dir}</workingDirectory>
<installDirectory>${project.build.directory}</installDirectory>
</configuration>
<executions>
<execution>
<id>install-frontend-tools</id>
<goals>
<goal>install-node-and-yarn</goal>
</goals>
</execution>
<execution>
<id>yarn-install</id>
<goals>
<goal>yarn</goal>
</goals>
<configuration>
<arguments>install</arguments>
</configuration>
</execution>
<execution>
<id>build-frontend</id>
<goals>
<goal>yarn</goal>
</goals>
<phase>prepare-package</phase>
<configuration>
<arguments>build</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>position-react-build</id>
<goals>
<goal>copy-resources</goal>
</goals>
<phase>prepare-package</phase>
<configuration>
<outputDirectory>${project.build.outputDirectory}/static</outputDirectory>
<resources>
<resource>
<directory>${frontend-src-dir}/build</directory>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Here is the Controller code.
package com.springreact.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class IndexController {
@GetMapping("")
public ModelAndView home() {
ModelAndView mav=new ModelAndView("index");
return mav;
}
}
If you follow the above mentioned steps , you should see your React App being spun up on http://localhost:8080/
.
For further details you can checkout the blog that I have written on it. Here are the links of the blog on two different platforms-
Dev Community- https://dev.to/arpan_banerjee7/run-react-frontend-and-springboot-backend-on-the-same-port-and-package-them-as-a-single-artifact-14pa
Medium- https://medium.com/codex/run-react-frontend-and-springboot-backend-on-the-same-port-and-package-them-as-a-single-artifact-a790c9e10ac1
I would suggest creating multimodule maven project, where one module will be spring-boot app and second one react app. To make it into uber jar, pack react app into webjar build by maven. Building can be done also by maven with proper plugin.
So:
This will allow you to have everything as one uber jar app. On the other hand, front-end people can work with react module as with any other react application.
I found this post that may answer your question. It shows how to develop the react front end and spring boot back end and then merge them into a single jar file for deployment.
https://medium.com/@mukundmadhav/build-and-deploy-react-app-with-spring-boot-and-mysql-6f888eb0c600
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With