react app frontend and spring boot backend
parent
45ecd8c373
commit
b0f36ba13a
111
Serve ReactApp with SpringBoot.md
Normal file
111
Serve ReactApp with SpringBoot.md
Normal file
@ -0,0 +1,111 @@
|
||||
## Create a Spring Boot app
|
||||
|
||||
To get started, go to [start.spring.io](https://start.spring.io/ "Spring Initializr") and generate a new Spring Boot app. Make sure to pick at least the Web dependency. We are going to use Gradle as build tool.
|
||||
|
||||
# Serving static content with Spring Boot
|
||||
|
||||
To serve our front end web app from a Spring Boot jar file, we need to first understand how Spring Boot handles [static content](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc-static-content).
|
||||
|
||||
> By default, Spring Boot serves static content from a directory called `/static` (or `/public` or `/resources` or `/META-INF/resources`) in the classpath or from the root of the `ServletContext`
|
||||
|
||||
For example, the following is an example `index.html` that we will put into `src/main/resources/static/` folder.
|
||||
|
||||
```html
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Static content test</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World</h1>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
When we start our Spring Boot app and point our web browser to it (with default configuration the URL should be `localhost:8080`), _Hello World_ should be displayed to us. Everything in `src/main/resources/static/` is moved to the correct location in the packaged jar file. Now that we know how to serve static content, it should be relatively easy to serve the React app in a similar manner.
|
||||
|
||||
_But wait! Javascript source files have to be built first, CSS minified etc. We can’t just put our React source files to `src/main/resources` and expect everything to work._
|
||||
|
||||
That’s correct. We have to build the React app before we can move it into the `/static` directory. Let’s have a look at how to do that. But first, we need to generate a new React app.
|
||||
|
||||
# Create a React app
|
||||
|
||||
It’s super easy to get started with React by using [`create-react-app`](https://facebook.github.io/create-react-app/ "Create React App"). If you have the necessary tools installed (e.g. `node`, `npm`), you can just execute this command
|
||||
|
||||
```bash
|
||||
npx create-react-app enter-app-name-here
|
||||
```
|
||||
|
||||
It does not meter where exactly to place the generated web app. This projec going to use `src/main/webapp` path.
|
||||
|
||||
# Gradle build script
|
||||
|
||||
Before we can put our web app to production, [we must create a minified bundle](https://github.com/facebook/create-react-app#quick-overview "Create React App Quick Overview") with `npm run build`. To serve the minified bundle with Spring Boot, we have to move it to one of the directories where [Spring Boot serves static content](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc-static-content). This project is using [Gradle](https://gradle.org/ "Gradle Build Tool") to build and package the Spring Boot application, but the same can be achieved with other build tools. The key is to remember that in addition to building the Java code, we **must also create the minified bundle of our web app and copy it to the correct directory**.
|
||||
|
||||
To integrate a Gradle build with Node, the [`gradle-node-plugin`](https://github.com/node-gradle/gradle-node-plugin/tree/master "Gradle plugin for integrating NodeJS in your build") can be used.
|
||||
|
||||
> [!TODO]
|
||||
> The following are the most interesting parts of a Gradle build script from outdated [`gradle-node-plugin`](https://github.com/srs/gradle-node-plugin "Gradle plugin for integrating NodeJS in your build") plugin
|
||||
|
||||
```groovy
|
||||
plugins {
|
||||
id "com.moowork.node" version "1.3.1"
|
||||
}
|
||||
|
||||
....
|
||||
|
||||
// Read more about how to configure the plugin from
|
||||
// https://github.com/srs/gradle-node-plugin/blob/master/docs/node.md
|
||||
node {
|
||||
download = true
|
||||
|
||||
// Set the work directory for unpacking node
|
||||
workDir = file("${project.buildDir}/nodejs")
|
||||
|
||||
// Set the work directory for NPM
|
||||
npmWorkDir = file("${project.buildDir}/npm")
|
||||
}
|
||||
|
||||
task appNpmInstall(type: NpmTask) {
|
||||
description = "Installs all dependencies from package.json"
|
||||
workingDir = file("${project.projectDir}/src/main/webapp")
|
||||
args = ["install"]
|
||||
}
|
||||
|
||||
task appNpmBuild(type: NpmTask) {
|
||||
description = "Builds production version of the webapp"
|
||||
workingDir = file("${project.projectDir}/src/main/webapp")
|
||||
args = ["run", "build"]
|
||||
}
|
||||
|
||||
task copyWebApp(type: Copy) {
|
||||
from 'src/main/webapp/build'
|
||||
into 'build/resources/main/static/.'
|
||||
}
|
||||
```
|
||||
|
||||
`appNpmInstall` is a Gradle task that runs `npm install` in the `webapp` directory. Similar to `appNpmInstall`, the build script declares the `appNpmBuild` task that runs `npm run build` to create the minified bundle of the web app. Finally, `copyWebApp` is a simple [`Copy`](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Copy.html) task to copy the minified bundle to the static content directory. Feel free to test run these tasks in isolation and see how they work. For example, running `gradle appNpmInstall` should install all of our web app dependencies and place them in `src/main/webapp/node_modules/` directory.
|
||||
|
||||
## Development flow
|
||||
|
||||
During web app development, you should start the web app in development mode. Therefore, instead of bundling the web app inside the Spring app, let’s serve it separately using the dev server. Go to the `webapp` directory and run `npm start`. This way, your web app will reload automatically if you make any changes in the source files. At the same time, you should also start the Spring Boot application.
|
||||
|
||||
To make the development flow with Spring Boot a little more pleasant, you can also [configure `spring-boot-devtools` and enable automatic restarts](https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-devtools.html#using-boot-devtools-restart "Automatic Restart"). When configured, the Spring Boot app restarts whenever files on the classpath change.
|
||||
|
||||
## Build for production
|
||||
|
||||
To build our application for production, in addition to compiling and packaging our Java code, we must also create a minified bundle of the web app and place it inside the Jar file to one of the directories where Spring Boot serves static content. We already have our build script configured with tasks that can install our dependencies, create the minified bundle and copy it to the correct location. To make the packaging a bit more simpler, we could define some dependencies between the build tasks in our build script.
|
||||
|
||||
```groovy
|
||||
appNpmBuild.dependsOn appNpmInstall
|
||||
copyWebApp.dependsOn appNpmBuild
|
||||
compileJava.dependsOn copyWebApp
|
||||
```
|
||||
|
||||
This makes sure that whenever Java code is compiled, web app dependencies are also installed, minified bundle is created and the bundle is copied to a static content directory. When you run `gradle clean build`, you don’t have explicitly run any web app specific Gradle tasks. Once the build has finished, you can start the application via command-line.
|
||||
|
||||
```bash
|
||||
java -jar path/to/web-app.jar
|
||||
```
|
||||
|
||||
Point your browser to it and you should see the newly created React app running.
|
Loading…
Reference in New Issue
Block a user