In addition to an answer I submitted here: Hosting a single page application with spring boot
Below is the directory structure you will need. You'll obviously have your REST API within the java directory (make sure to note the controller specifics within my other answer I provided above):
- sample-project-root
- src
- main
-java
- js
app.js
index.js
- resources
- templates
index.html
webpack.config.js
package.json
pom.xml
Below is the index.html page that your 'MainController' will render using Thymeleaf. This needs to be placed in the src/main/resources/templates/ directory (standard Spring behavior).
index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta charset="UTF-8"/>
<title>Sample Project</title>
</head>
<body>
<!-- Entry point to our ReactJS single page web application -->
<div id="root"></div>
<script type="text/javascript" src="built/bundle.js"></script>
</body>
</html>
Below is the index.js page that will actually boot up your React app. Notice that the main render function is getting the document id 'root' that's within your index.html page.
index.js
const React = require('react');
const ReactDOM = require('react-dom');
import App from './app.js';
import 'bootstrap/dist/css/bootstrap.min.css';
// Render main app
ReactDOM.render(
<App />,
document.getElementById('root')
);
You're going to need to utilize Webpack to manage your ReactJS dependencies. I'll share with you a sample webpack.config.js file that lives at the root of the project.
webpack.config.js
var path = require('path');
module.exports = {
entry: ['babel-polyfill', './src/main/js/index.js'],
devtool: 'sourcemaps',
cache: true,
mode: 'development',
output: {
path: __dirname,
filename: './src/main/resources/static/built/bundle.js'
},
module: {
rules: [
{
test: path.join(__dirname, '.'),
exclude: /(node_modules)/,
use: [{
loader: 'babel-loader',
options: {
presets: ["@babel/preset-env", "@babel/preset-react"]
}
}]
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif|eot|otf|ttf|woff|woff2)$/,
use: [
{
loader: 'url-loader',
options: {}
}
]
}
]
}
};
Don't worry too much about the bottom two rules, what you want to focus on is the entry point which is our index.js page and the output path that is the result of running your package.json file.
package.json (place this at root level of your project as well)
{
"name": "spring-data-rest-and-reactjs",
"version": "0.1.0",
"description": "Demo of ReactJS + Spring Data REST",
"repository": {
"type": "git",
"url": "git@github.com:spring-guides/tut-react-and-spring-data-rest.git"
},
"keywords": [
"rest",
"hateoas",
"spring",
"data",
"react"
],
"author": "Sample Team",
"license": "Apache-2.0",
"bugs": {
"url": ""
},
"homepage": "url",
"dependencies": {
"react": "^16.5.2",
"react-dom": "^16.5.2",
"rest": "^1.3.1",
"bootstrap": "^4.2.1",
"jquery": "^3.3.1",
"popper.js": "^1.14.6",
"style-loader": "^0.23.1",
"css-loader": "^2.1.0",
"url-loader": "^1.1.2",
"postcss-loader": "^3.0.0",
"precss": "^4.0.0",
"autoprefixer": "^9.4.3",
"sass-loader": "^7.1.0",
"react-octicon": "^3.0.1"
},
"scripts": {
"watch": "webpack --watch -d"
},
"devDependencies": {
"@babel/core": "^7.1.0",
"babel-polyfill": "^6.0.16",
"@babel/preset-env": "^7.1.0",
"@babel/preset-react": "^7.0.0",
"babel-loader": "^8.0.2",
"webpack": "^4.19.1",
"webpack-cli": "^3.1.0"
}
}
Your React app might require different dependencies but this is just an example.
Finally, add the following to your Maven plugins (pom.xml):
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.6</version>
<configuration>
<installDirectory>target</installDirectory>
</configuration>
<executions>
<execution>
<id>install node and npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<configuration>
<nodeVersion>v10.11.0</nodeVersion>
<npmVersion>6.4.1</npmVersion>
</configuration>
</execution>
<execution>
<id>npm install</id>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>install</arguments>
</configuration>
</execution>
<execution>
<id>webpack build</id>
<goals>
<goal>webpack</goal>
</goals>
</execution>
</executions>
</plugin>
Resources:
Good luck!