The easiest way to serve an angular front-end from a spring-boot application , is to have a multi-module project. Then automate the build process to copy the dist folder from the ui module into the service module during maven clean install
itself.This way, you could have a single executable jar that serves the angular as well.For instance, consider the following project structure :
SampleMultiModuleProject
|__SampleMultiModuleService
|__SampleMultiModuleUI
In this case, you will have three different pom files like as follows.
SampleMultiModuleProject main pom.xml
: (where all main dependencies are present)
<modules>
<module>SampleMultiModuleUI</module>
<module>SampleMultiModuleService</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/>
</parent>
//add rest of the dependencies here.
SampleMultiModuleService service pom.xml
: (for service module and add the springboot maven plugin to make it executable with embedded tomcat, and add other dependencies that are needed in service module , for instance lombok)
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
and finally configure the ui module to build angular like SampleMultiModuleUI pom.xml
:
<build>
<plugins>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.9.1</version>
<configuration>
<workingDirectory>./</workingDirectory>
<nodeVersion>v13.3.0</nodeVersion>
<npmVersion>6.13.1</npmVersion>
<nodeDownloadRoot>http://nodejs.org/dist/</nodeDownloadRoot>
<npmDownloadRoot>http://registry.npmjs.org/npm/-/</npmDownloadRoot>
<installDirectory>./</installDirectory>
<npmInheritsProxyConfigFromMaven>false</npmInheritsProxyConfigFromMaven>
</configuration>
<executions>
<execution>
<id>install node and npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<phase>generate-resources</phase>
</execution>
<execution>
<id>npm install</id>
<goals>
<goal>npm</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<arguments>install</arguments>
</configuration>
</execution>
<execution>
<id>npm run-script build-prod</id>
<phase>prepare-package</phase>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>run-script build</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
So what happens is when you do maven clean install, it will trigger the build of the ui module which in turn uses the frontend builder to install a local npm which runs the command specified in the arguments. The package.json
file in your angular application will by default contain something like :
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build --prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"stats": "webpack-bundle-analyzer dist/stats.json"
},
So you are essentially calling this ng build --prod
through this process.Also in angular.json
set the output path
as the resources folder under the service module in your project, so that the assets will be created there.
"newProjectRoot": "projects",
"projects": {
"SampleMultiModuleUI": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "../SampleMultiModuleService/src/main/resources/static",
//rest of the config