Angular projet build relies on the Angular CLI tool.
Spring boot project build relies on the Spring Boot Maven Plugin.
So how to configure and build a Spring Boot application that hosts an Angular Application on the front-end ?
My requirements are the following :
using Maven as Java build tool
running the application in a embedded Tomcat instance bootstrapped by Spring Boot.
efficient build lifecycle in development environment
reliable build for post-development environment
Angular Configuration
First, I need to configure the Angular application to make the build of the Angular application available in the source code directory of the Spring Boot Maven project.
A simple way to do it requires 2 simple changes :
moving the angular application folder in the root folder of the Spring Boot Maven project.
modifying the .angular-cli.json
configuration file to
change the apps/outDir
value that is "dist"
by default, by
"../src/main/resources/static"
.
That is :
{
...
"apps": [
{
"root": "src",
"outDir": "../src/main/resources/static",
...
}
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
.
In this way, as I execute the ng build
command, the angular application bundled by Webpack will be located in the resource directory for static contents of Spring Boot.
Spring Boot configuration
I don't want to perform exactly the same Spring Boot build tasks in development and in post-development environments.
Of course, it doesn't mean that the builds will produce a distinct functional behavior according to the target environments.
In development, I want to have a fast build.
As I modify the source code (Java, JavaScript or anything else), I want a fast feedback. I don't want to package and redeploy the application at each source code modification for example.
I don't want to do some special things at each time the source code is changed either.
I want that changes be reflected in the application fast and automatically.
To build the application for post-development environments, I want to have a reliable build and that contains the final content.
Here the detailed requirements for the post-development environments :
I want to perform a full build from scratch of the Angular application (and even of the overall Spring Boot application).
Incremental updates of the webpack bundled application at each source code modification is fine during development but as I deliver my application, I will really reduce potential side effects at its maximum.
I don't care if I have to package the application from scratch as I don't create this build frequently and I also leave this task to automatic tools such as the continuous integration.
I want to repackage the application in a way where it is autonomous by running itself an embedded Tomcat that deploys it.
The repackage
goal of Spring Boot Maven plugin achieves it.
To be able to switch in a clean/reliable way from a type of build to another one, I want to specify two distinct builds.
Maven (as Gradle) provides a build profile feature that addresses very well this requirement.
So, I use it.
Here is the Maven profile for the development build :
<profile>
<id>fast-build</id>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<jvmArguments>
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
</jvmArguments>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
</profile>
Some additional notes :
In development, I want always have a way to add a break point if I need and without restarting the application.
The jvmArguments
argument of the Spring Boot Maven plugin valued in this way :
<jvmArguments>
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
</jvmArguments>
specifies 5005
as port for the debugger listener without being blocking (suspend=n
) for the server.
addResources
to true
.Here is the Maven profile for the post-development build (plus declared properties used by it) :
<properties>
...
<node.version>v6.9.1</node.version>
<npm.version>3.10.8</npm.version>
...
</properties>
...
<profile>
<id>full-build</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.2</version>
<configuration>
<installDirectory>angular-app</installDirectory>
<workingDirectory>angular-app</workingDirectory>
</configuration>
<executions>
<execution>
<id>install node and npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<configuration>
<nodeVersion>${node.version}</nodeVersion>
<npmVersion>${npm.version}</npmVersion>
</configuration>
</execution>
<execution>
<id>install angular app</id>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>install</arguments>
</configuration>
</execution>
<execution>
<id>npm build</id>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>run build</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Some additional notes :
angular-app
declared here : <workingDirectory>angular-app</workingDirectory>
is the directory of the angular application that I copied in the Maven Spring Boot project.
<installDirectory>angular-app</installDirectory>
is the working folder where the frontend-maven-plugin
will install node and required dependencies.
In itself, the angular-app
directory is not directly used to generate the packaged application.
So using this directory is fine and also allows to run the angular application from Angular CLI.
Angular and Spring Boot command to run the builds
For development build :
angular-app
directory, execute ng build -w
.
It will build the Angular application and also update incrementally the build (w
for watch) mvn spring-boot:run -Pfast-build
(a script that executes it is welcome)For post-development build :
mvn spring-boot:run
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