Find out how to combine Create React App with Spring Boot to give you a single war file
The basic idea of what Spring Boot and Create React App do.
* Side note: my IDE of choice is IntelliJ. When working on react code I usually switch over to VS Code. Feel Free to use what makes you feel comfortable
GroupId: e.the.awesome
Artifact: spring-react-combo-app
3. Unzip the downloaded project into your git directory. Commit, Commit, Commit. Your SpringReactComboAppApplication should look like this.
package e.the.awesome.springreactcomboapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class SpringReactComboAppApplication extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(SpringReactComboAppApplication.class, args);
}
}
4. Let’s create a basic service now. We’ll call it the DadJokesController. This should be created in the same folder as SpringReactComboAppApplication file. I’m aware this is not a proper Rest API format but let’s ignore that for now.
package e.the.awesome.springreactcomboapp;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DadJokesController {
@GetMapping("/api/dadjokes")
public String dadJokes() {
return "Justice is a dish best served cold, if it were served warm it would be just water.";
}
}
5. In your terminal run
mvn spring-boot:run
Then in your browser check http://localhost:8080/api/dadjokes . You should see the dad joke we added to our controller.
6. To create your React app, just run in the root directory
npx create-react-app basic-frontend-app
You can call it whatever you want, I just called mine basic-frontend-app
7. To run the front end application:
cd basic-frontend-app<br>npm start
After starting it should look like:
8. Since we want to integrate our Dad Jokes service into the frontend, first we will address proxy issues. If you’ve noticed, your service starts on localhost:8080 while the frontend starts on localhost:3000. If we try calling our service from the frontend, depending on your browser, you’ll get a CORS error.
The simplest way to address the issue is to have your front end proxy any requests from port 3000 to 8080. This change will be made in your package.json file
{
"name": "basic-frontend-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.3.1",
"react-dom": "^16.3.1",
"react-scripts": "1.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"proxy": {
"/api": {
"target": "http://localhost:8080",
"ws": true
}
}
}
Add the following to your frontend App.js file
import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
state = {};
componentDidMount() {
this.dadJokes()
}
dadJokes = () => {
fetch('/api/dadjokes')
.then(response => response.text())
.then(message => {
this.setState({message: message});
});
};
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo"/>
<h3 className="App-title">{this.state.message}</h3>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
</div>
);
}
}
export default App;
Restart the front end and you should be good. if you happen to get this error: I deleted my package-lock.json file and node_modules folder reinstalled npm packages and ran it again
9. Your application should now look like. You can see the results of the dad jokes API call.
10. Now that our basic front end and backend is complete, it’s time to create a production build and single war file.
Under the <dependencies> add this in
<!-- https://mvnrepository.com/artifact/com.github.eirslett/frontend-maven-plugin -->
<dependency>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.6</version>
</dependency>
Under the <plugins> section of the pom file, we will add the following commands which will do the following things when mvn clean install is run.
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.6</version>
<configuration>
<workingDirectory>basic-frontend-app</workingDirectory>
<installDirectory>target</installDirectory>
</configuration>
<executions>
<execution>
<id>install node and npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<configuration>
<nodeVersion>v8.9.4</nodeVersion>
<npmVersion>5.6.0</npmVersion>
</configuration>
</execution>
<execution>
<id>npm install</id>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>install</arguments>
</configuration>
</execution>
<execution>
<id>npm run build</id>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>run build</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>generate-resources</phase>
<configuration>
<target>
<copy todir="${project.build.directory}/classes/public">
<fileset dir="${project.basedir}/basic-frontend-app/build"/>
</copy>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
Side note: order is important for your plugins so make sure your node/npm install execution is before copying the build file execution
11. After adding this, run mvn clean install and verify that the target/classes directory contains both frontend files and java files. And you should be good to go.
A final look at my pom file.
So that’s all I got. If you would like to take a look at the repo or use it. It can be found here on my Github.
Next up is an article on how to deploy your war file on Heroku. Look forward to it!