I have a Spring Boot + Angular 2 project. I want to deploy it to Heroku. I'm able to run the npm build then copy the generated files over to the public folder (src/resources/public) manually, then run the backend build. What I want to do is to set up a gradle build that will do all of that at once. What I have so far is a gradle build that will build the front end, build the backend, however it does not copy the static files before generating the jar. Since the jar does not contain said static files, it won't work on Heroku.
Here's the project folder structure:
root
backend
src/main/java
src/main/resources
frontend
--> angular files go here
build/libs -> where the JAR file goes
The gradle build file:
buildscript {
repositories {
mavenCentral()
}
dependencies {
// spring
classpath('org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE')
classpath('org.springframework:springloaded:1.2.6.RELEASE')
}
}
plugins {
id "com.moowork.node" version "1.2.0"
}
// gradle wrapper
task wrapper(type: Wrapper) {
gradleVersion = '3.4'
}
// configure gradle-node-plugin
node {
version = '8.1.4'
npmVersion = '5.0.3'
download = true
workDir = file("${project.projectDir}/node")
nodeModulesDir = file("${project.projectDir}/")
}
// clean node/node_modules/dist
task npmClean(type: Delete) {
final def webDir = "${rootDir}/frontend"
delete "${webDir}/node"
delete "${webDir}/node_modules"
delete "${webDir}/dist"
delete "${webDir}/coverage"
delete "${rootDir}/backend/src/main/resources/public"
}
// clean task for npm
task copyFiles {
doLast {
copy {
from "${rootDir}/frontend/dist"
into "${rootDir}/backend/src/main/resources/public"
}
}
}
// build task for npm
task frontendBuild {}
frontendBuild.dependsOn(npm_install)
frontendBuild.dependsOn(npm_run_build)
npm_install {
args = ['--prefix', './frontend']
}
npm_run_build {
args = ['--prefix', './frontend']
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
sourceSets {
main {
java {
srcDirs = ['backend/src/main/java']
}
resources {
srcDirs = ['backend/src/main/resources']
}
}
}
copyFiles.dependsOn(frontendBuild);
compileJava.dependsOn(frontendBuild);
task backendBuild {}
backendBuild.dependsOn(compileJava)
backendBuild.dependsOn(jar)
jar.dependsOn(copyFiles)
repositories {
mavenCentral()
}
eclipse {
classpath {
containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
containers('org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8')
}
}
idea {
module {
inheritOutputDirs = false
outputDir = file("${buildDir}/classes/main/")
}
}
jar {
baseName = 'expense-splitter'
version = '0.0.1'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
configurations {
dev
}
dependencies {
// spring
compile('org.springframework.boot:spring-boot-starter-web:1.5.2.RELEASE')
compile('org.springframework.boot:spring-boot-starter-data-jpa:1.5.2.RELEASE')
compile('org.springframework.boot:spring-boot-starter-security:1.5.2.RELEASE')
compile('org.apache.commons:commons-lang3:3.3.2')
// to make hibernate handle java 8 date and time types correctly
// it's marked as deprecated but we need to keep it until
// spring boot jpa starts using hibernate 5.2
compile('org.hibernate:hibernate-java8:5.1.0.Final')
// json web tokens
compile ('io.jsonwebtoken:jjwt:0.7.0')
compile 'mysql:mysql-connector-java'
// google gson
compile('com.google.code.gson:gson:2.8.0')
// jackson - parsing of java 8 date and time types
compile('com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.7')
// spring dev tools
dev('org.springframework.boot:spring-boot-devtools:1.5.2.RELEASE')
// testing
testCompile('org.springframework.boot:spring-boot-starter-test:1.5.2.RELEASE')
}
// run spring boot app
bootRun {
//addResources = true
classpath = sourceSets.main.runtimeClasspath + configurations.dev
jvmArgs = ["-Xdebug -agentlib:jdwp=transport=dt_socket,address=8080,server=y,suspend=n"]
}
// run all task
task runAll {}
runAll.dependsOn(bootRun)
Thanks in advance,
The Jar is created under the $project/build/libs/ folder.
Try a different approach. Instead of manually copying the resources, tell Gradle that when it processes resources for the JAR, also take into consideration what is in frontend/dist/
:
processResources {
from ('frontend/dist/') {
into 'public'
}
}
This should result in a JAR containing a public/
directory, with the contents of frontend/dist/
inside of it.
Gradle configuration for Spring Boot 1.5\2.x + Angular 2-6
Angular in sub-folder frontend
Frontend module
Crate build.gradle
:
plugins {
id "com.moowork.node" version "1.2.0"
}
node {
version = '8.11.3'
npmVersion = '5.6.0'
download = true
workDir = file("${project.buildDir}/node")
nodeModulesDir = file("${project.projectDir}")
}
task build(type: NpmTask) {
args = ['run', 'build']
}
build.dependsOn(npm_install)
Note for Angular 6
Update outputPath
value in angular.json
to 'dist'
Backend module
Edit build.gradle
for backend module:
Spring Boot 2.X:
bootJar {
archiveName = "yourapp.jar"
mainClassName = 'com.company.app.Application'
from('frontend/dist') {
into 'static'
}
}
Spring Boot 1.5.X:
jar {
archiveName = "yourapp.jar"
manifest {
attributes 'Main-Class': 'com.company.app.Application'
}
from('frontend/dist') {
into 'static'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Finally execute bootRepackage
or bootJar
task and check results in builds/libs
Assume that front end is located at the following folder: src/main/webapp/fe-ui/
, the following solution for the Spring Boot version 2.1.1.RELEASE could be considered:
bootJar {
baseName = 'jar-name'
version = '0.1.0'
from('src/main/webapp/fe-ui/build') {
into 'public'
}
}
task installFeDependencies(type: NpmTask) {
args = ['install']
}
task buildFe(type: NpmTask) {
args = ['run', 'build']
dependsOn installFeDependencies
}
compileJava {
dependsOn buildFe
}
Running gradlew build
will install, build front end as well as will invoke bootJar
. The latter will package built front end bundle.
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