├── .gitignore
├── Dockerfile
├── README.md
├── circle.yml
├── pom.xml
└── src
├── main
├── frontend
│ ├── package.json
│ ├── src
│ │ ├── Application.jsx
│ │ ├── Application.less
│ │ └── app.js
│ └── webpack.config.js
├── java
│ └── .gitkeep
├── kotlin
│ └── io
│ │ └── mikael
│ │ └── app
│ │ ├── app.kt
│ │ └── service.kt
└── resources
│ ├── application.properties
│ └── static
│ └── index.html
└── test
├── java
└── io
│ └── mikael
│ └── poc
│ └── ApplicationTests.java
└── kotlin
└── .gitkeep
/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | .settings
3 | .project
4 | .classpath
5 | /.idea/
6 | /*.iml
7 | /devdb*
8 | /src/main/resources/git.properties
9 | /data/
10 | node_modules/
11 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM java:8
2 | RUN mkdir -p /app
3 | COPY target/*.jar /app/
4 | USER nobody
5 | CMD ["/bin/sh", "-c", "java ${JAVA_OPTS} -jar /app/*.jar ${APP_OPTS}"]
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### POC: Kotlin + Spring Boot + Webpack + Babel + ReactJS
2 |
3 | ```bash
4 | mvn clean package spring-boot:run
5 | ```
6 |
7 | The project provides backend services using Spring Boot, and generates a nice clean JavaScript frontend
8 | using the Maven Frontend plugin to first fetch a relevant Node.JS binary package, NPM, then run
9 | `npm install` to fetch a shitload of JS modules, and execute WebPack through `npm run prod-build`.
10 |
11 | WebPack goes on to load its Babel.JS module, and configure it with ES2015 and React Babel profiles.
12 |
13 | Babel then transpiles the JavaScript input files from shiny new ES2015 to ES5,
14 | which shitty browsers can actually run.
15 |
16 | WebPack slams all this JavaScript together: the entrypoint JS file set in the configuration file,
17 | everything that file imports, and everything THAT imports, ad nauseam, into the (possibly giant)
18 | `target/classes/static/bundle.js` file.
19 |
20 | Take a look at the `src/main/frontend` directory, and the configuration files and ES6 entry point there.
21 |
22 | Basically this should work on Linux x86 and x64, Windows 32 and 64 bit, and OSX. **Should.**
23 |
24 | You can also install NVM, have NVM install Node.JS LTS, upgrade your NPM to newest, then run `npm install`
25 | and `npm run-script dev-build` to manually compile the stuff. It should be pretty easy to set up a watchdog
26 | to automatically build things, and trigger LiveReload.
27 |
28 | But that's a story to be explored on some other night.
29 |
30 | ### IntelliJ IDEA users
31 |
32 | File -> Settings -> Languages & Frameworks -> JavaScript:
33 |
34 | JavaScript language version: JSX Harmony
35 |
36 | Libraries -> ECMAScript 6: Enabled
37 |
38 | -----
39 |
40 | File -> Settings -> Build, Execution, Deployment -> Compiler:
41 |
42 | Make project automatically: Enabled
43 |
44 | -----
45 |
46 | CTRL-SHIFT A -> Registry... :
47 |
48 | compiler.automake.allow.when.app.running: Enabled
49 |
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | machine:
2 | java:
3 | version: oraclejdk8
4 | services:
5 | - docker
6 |
7 | general:
8 | artifacts:
9 | - "target/*.jar"
10 |
11 | test:
12 | post:
13 | - "mkdir -p $CIRCLE_TEST_REPORTS/junit/"
14 | - "find . -type f -regex \".*/target/surefire-reports/.*xml\" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \\;"
15 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | io.mikael.poc
6 | kotlin-spring-boot-reactjs-poc
7 | 0.0.1-SNAPSHOT
8 | jar
9 |
10 | kotlin-spring-boot-reactjs-poc
11 | Kotlin + Spring Boot + ReactJS POC
12 |
13 |
14 | org.springframework.boot
15 | spring-boot-starter-parent
16 | 1.4.2.RELEASE
17 |
18 |
19 |
20 |
21 | 1.8
22 | 1.0.5
23 |
24 |
25 |
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-devtools
30 |
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-web
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-tomcat
39 |
40 |
41 |
42 |
43 |
44 | org.springframework.boot
45 | spring-boot-starter-undertow
46 |
47 |
48 |
49 | org.springframework.boot
50 | spring-boot-starter-test
51 | test
52 |
53 |
54 |
55 | org.jetbrains.kotlin
56 | kotlin-stdlib
57 | ${kotlin.version}
58 |
59 |
60 |
61 | org.jetbrains.kotlin
62 | kotlin-test
63 | ${kotlin.version}
64 | test
65 |
66 |
67 |
68 |
69 | ${project.basedir}/src/main/kotlin
70 | ${project.basedir}/src/test/kotlin
71 |
72 |
73 | org.springframework.boot
74 | spring-boot-maven-plugin
75 |
76 |
77 | kotlin-maven-plugin
78 | org.jetbrains.kotlin
79 | ${kotlin.version}
80 |
81 |
82 | compile
83 | compile
84 | compile
85 |
86 |
87 | src/main/java
88 | src/main/kotlin
89 |
90 |
91 |
92 |
93 | test-compile
94 | test-compile
95 | test-compile
96 |
97 |
98 | src/test/java
99 | src/test/kotlin
100 |
101 |
102 |
103 |
104 |
105 |
106 | com.github.eirslett
107 | frontend-maven-plugin
108 | 1.0
109 |
110 | src/main/frontend
111 | https://nodejs.org/dist/
112 | v6.4.0
113 | 3.10.3
114 | target
115 |
116 |
117 |
118 | install node and npm
119 |
120 | install-node-and-npm
121 |
122 | generate-resources
123 |
124 |
125 | npm install
126 |
127 | npm
128 |
129 |
130 | install
131 | target
132 |
133 |
134 |
135 | webpack build
136 |
137 | npm
138 |
139 | generate-resources
140 |
141 | run-script dev-build
142 |
143 |
144 |
145 |
146 |
147 | org.apache.maven.plugins
148 | maven-compiler-plugin
149 |
150 |
151 | compile
152 | compile
153 |
154 | compile
155 |
156 |
157 |
158 | testCompile
159 | test-compile
160 |
161 | testCompile
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
--------------------------------------------------------------------------------
/src/main/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sbmfp-frontend",
3 | "version": "0.0.1",
4 | "description": "SBMFP Frontend",
5 | "license": "MIT",
6 | "repository": "yeah",
7 | "private": true,
8 | "devDependencies": {
9 | "babel-core": "^6.18.2",
10 | "babel-loader": "^6.2.7",
11 | "babel-preset-es2015": "^6.18.0",
12 | "babel-preset-react": "^6.16.0",
13 | "babel-plugin-transform-object-assign": "^6.8.0",
14 | "css-loader": "^0.25.0",
15 | "expose-loader": "^0.7.1",
16 | "imports-loader": "^0.6.5",
17 | "style-loader": "^0.13.1",
18 | "webpack": "^1.13.3",
19 | "extract-text-webpack-plugin": "^1.0.1",
20 | "less": "^2.7.1",
21 | "less-loader": "^2.2.3"
22 | },
23 | "dependencies": {
24 | "babel-runtime": "^6.18.0",
25 | "babel-polyfill": "^6.16.0",
26 | "history": "^4.4.0",
27 | "moment": "^2.15.2",
28 | "jquery": "^3.1.1",
29 | "react-bootstrap": "^0.30.6",
30 | "react": "^15.3.2",
31 | "react-dom": "^15.3.2",
32 | "react-router": "^3.0.0",
33 | "react-router-bootstrap": "^0.23.1"
34 | },
35 | "scripts": {
36 | "watch": "webpack -d --watch",
37 | "dev-build": "webpack -d --display-modules",
38 | "prod-build": "webpack -d -p"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/frontend/src/Application.jsx:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import React from 'react';
4 | import $ from 'jquery';
5 |
6 | require('!style!css!less!./Application.less');
7 |
8 | export class Application extends React.Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = {
12 | name: 'Initial',
13 | counter: -1,
14 | when: ''
15 | };
16 | }
17 | fetchState() {
18 | $.ajax('/api/hello').done((data) => this.setState(data));
19 | }
20 | render() {
21 | return (
22 |
23 | Hello {this.state.name} #{this.state.counter} at {this.state.timestamp}
24 |
25 | );
26 | }
27 | componentDidMount() {
28 | this.interval = window.setInterval(this.fetchState.bind(this), 1000);
29 | }
30 | componentWillUnmount() {
31 | clearInterval(this.interval);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/frontend/src/Application.less:
--------------------------------------------------------------------------------
1 | div.app-hello-message {
2 | font-family: "Trebuchet MS", Verdana, sans-serif;
3 | font-size: 20pt;
4 | margin: 30pt;
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/frontend/src/app.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import React from 'react';
4 | import ReactDOM from 'react-dom';
5 |
6 | import { Application } from './Application.jsx';
7 |
8 | window.app = ReactDOM.render(, document.getElementById('content'));
9 |
--------------------------------------------------------------------------------
/src/main/frontend/webpack.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require('path');
3 | var ExtractTextPlugin = require('extract-text-webpack-plugin');
4 |
5 | module.exports = {
6 | entry: "./src/app.js",
7 | output: {
8 | path: '../../../target/classes/static/',
9 | filename: "bundle.js"
10 | },
11 | module: {
12 | loaders: [
13 | {
14 | test: /\.css$/,
15 | loader: "style!css"
16 | },
17 | {
18 | test: /\.jsx?$/,
19 | include: [
20 | path.resolve(__dirname, "./src")
21 | ],
22 | loader: 'babel',
23 | query: {
24 | presets: ['es2015', 'react']
25 | }
26 | },
27 | {
28 | test: /\.css$/,
29 | loader: ExtractTextPlugin.extract("style-loader", "css-loader")
30 | },
31 | {
32 | test: /\.less$/,
33 | loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
34 | }
35 | ]
36 | },
37 | plugins: [
38 | new ExtractTextPlugin("[name].css")
39 | ]
40 | };
41 |
--------------------------------------------------------------------------------
/src/main/java/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikaelhg/spring-boot-webpack-es6-react-poc/ced51824c2cf57cf197c7cc7781bf3c2abcf9b76/src/main/java/.gitkeep
--------------------------------------------------------------------------------
/src/main/kotlin/io/mikael/app/app.kt:
--------------------------------------------------------------------------------
1 | package io.mikael.app
2 |
3 | import org.springframework.boot.SpringApplication
4 | import org.springframework.boot.autoconfigure.SpringBootApplication
5 | import org.springframework.web.bind.annotation.GetMapping
6 | import org.springframework.web.bind.annotation.RestController
7 | import java.time.OffsetDateTime
8 | import java.util.concurrent.atomic.AtomicLong
9 |
10 | @SpringBootApplication
11 | open class Application {
12 |
13 | }
14 |
15 | @RestController
16 | open class AppController {
17 |
18 | private val counter = AtomicLong()
19 |
20 | @GetMapping("/api/hello")
21 | fun hello() = mapOf(
22 | "name" to "World",
23 | "counter" to counter.getAndIncrement().toString(),
24 | "timestamp" to OffsetDateTime.now().toString()
25 | )
26 |
27 | }
28 |
29 | fun main(args: Array) {
30 | SpringApplication.run(Application::class.java, *args)
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/kotlin/io/mikael/app/service.kt:
--------------------------------------------------------------------------------
1 | package io.mikael.app
2 |
3 | import org.springframework.stereotype.Service
4 |
5 | @Service
6 | class HelloService {
7 |
8 | fun hello() = "Hello!"
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikaelhg/spring-boot-webpack-es6-react-poc/ced51824c2cf57cf197c7cc7781bf3c2abcf9b76/src/main/resources/application.properties
--------------------------------------------------------------------------------
/src/main/resources/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Spring Boot + Maven Frontend Plugin + Node + Npm + Webpack + Babel + React + JQuery
6 |
7 |
8 | Spring Boot + Maven Frontend Plugin + Node + Npm + Webpack + Babel + React + JQuery
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/test/java/io/mikael/poc/ApplicationTests.java:
--------------------------------------------------------------------------------
1 | package io.mikael.poc;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
9 |
10 | @RunWith(SpringRunner.class)
11 | @SpringBootTest(webEnvironment = RANDOM_PORT)
12 | public class ApplicationTests {
13 |
14 | @Test
15 | public void contextLoads() {
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/test/kotlin/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikaelhg/spring-boot-webpack-es6-react-poc/ced51824c2cf57cf197c7cc7781bf3c2abcf9b76/src/test/kotlin/.gitkeep
--------------------------------------------------------------------------------