Spring Boot back-end and Angular front-end Maven configuration

Introduction

Spring Boot, Angular and Maven single JAR Configuration is an overlooked feature in introductory material. There are some scenarios where full-stack applications require to conveniently build and deploy both back and frontends together. In this article we are going to explore a simple way to integrate both Spring Boot back-end and Angular front-end in a single Maven build process and deploy the application as a single JAR file. Watch the video and follow the steps in this article and let us know your comments.

Spring Boot back-end and Angular front-end Maven configuration

Spring Boot initial project

We will start with an empty Spring Boot Initializr project, with a basic dependency. For this example we will use Maven as the project build tool but a similar approach works for Gradle too. Download and unzip the resulting file in any location.

Spring Initializr screenshot

Once unzipped, enter the project folder and create a new Angular project with the name front-end (we will see how to change the name later).

ng new frontend

This will create our project and we can proceed with the Spring Boot, Angular and Maven single JAR configuration steps.

Frontend and Backend setup

The basic project structure follows the standard project structure of Spring Boot and adds a new folder for our Angular front-end. We will use the usual toolchain for the two frameworks as we desire to be as compatible as we can. Furthermore, additional modifications can be made effortlessly and a future separation of both code bases will be straightforward.

project-dir
  frontend
  src
    main
    test
    pom.xml

Spring Boot Maven Single JAR Configuration in Maven

The main consideration here is to take advantage of the vast plugin ecosystem for Maven. In our case we will use the following plugins:

  • exec-maven-plugin: In order to execute npm build commands we call this plugin in the prepare-package Maven phase once Java source code is compiled. This generates the static files in the frontend/dist folder.
  • maven-resources-plugin: After generating the static files, the resources plugin copies the files to the static resources folder of the Spring Boot project and guarantees to include them in the target jar file.
  • maven-clean-plugin: We use this plugin to clean the static resources from the Spring Boot project with the clean phase.

The following code snipped shows the plugins used. You can copy and paste it into your existing pom.xml file in the plugins section to make it work.

<!-- build Angular frontend resources -->
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>3.1.0</version>
    <executions>
        <execution>
            <id>front-end install</id>
            <goals>
                <goal>exec</goal>
            </goals>
            <phase>prepare-package</phase>
            <configuration>
                <executable>npm</executable>
                <arguments>
                    <argument>install</argument>
                </arguments>
            </configuration>
        </execution>
        <execution>
            <id>front-end build</id>
            <goals>
                <goal>exec</goal>
            </goals>
            <phase>prepare-package</phase>
            <configuration>
                <executable>npm</executable>
                <arguments>
                    <argument>run</argument>
                    <argument>build</argument>
                </arguments>
            </configuration>
        </execution>
    </executions>
    <configuration>
        <workingDirectory>${basedir}/frontend</workingDirectory>
    </configuration>
</plugin>
<!-- Copy Angular resources to Spring Boot resource files -->
<plugin>
    <artifactId>maven-resources-plugin</artifactId>
    <version>3.1.0</version>
    <executions>
        
        <execution>
            <id>copy front-end assets</id>
            <goals>
                <goal>copy-resources</goal>
            </goals>
            <phase>prepare-package</phase>
            <configuration>
                <outputDirectory>${basedir}/src/main/resources/static</outputDirectory>
                <resources>
                    <resource>
                        <directory>frontend/dist/frontend</directory>
                        <!--<excludes>
                            <exclude>index.html</exclude>
                        </excludes>-->
                    </resource>
                </resources>
            </configuration>
        </execution>
        <execution>
            <id>copy front-end assets to target</id>
            <goals>
                <goal>copy-resources</goal>
            </goals>
            <phase>prepare-package</phase>
            <configuration>
                <outputDirectory>${basedir}/target/classes/static</outputDirectory>
                <resources>
                    <resource>
                        <directory>frontend/dist/frontend</directory>
                        <!--<excludes>
                            <exclude>index.html</exclude>
                        </excludes>-->
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>

<!-- Clean resources templates -->
<plugin>
    <artifactId>maven-clean-plugin</artifactId>
    <version>3.2.0</version>
    <configuration>
        <filesets>
            <fileset>
                <directory>${basedir}/src/main/resources/static</directory>
                <followSymlinks>false</followSymlinks>
            </fileset>
            <fileset>
                <directory>${basedir}/src/main/resources/templates</directory>
                <includes>
                    <include>index.html</include>
                </includes>
                <followSymlinks>false</followSymlinks>
            </fileset>
            <fileset>
                <directory>${basedir}/frontend/dist</directory>
                <includes>
                    <include>**/*</include>
                </includes>
                
                <followSymlinks>false</followSymlinks>
            </fileset>
        </filesets>
    </configuration>
</plugin>

Testing results

In order to work with this code snipped, you must first build and package the sources with the package target.

snishi@len12345 MINGW64 ~/projects/mvn-ng-sb (main)
$ ./mvnw package
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------< com._40dev:mvnngsb >-------------------------
[INFO] Building mvnngsb 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
...
[INFO] --- exec-maven-plugin:3.1.0:exec (front-end install) @ mvnngsb ---

up to date, audited 902 packages in 3s

91 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
[INFO]
[INFO] --- exec-maven-plugin:3.1.0:exec (front-end build) @ mvnngsb ---

> [email protected] build
> ng build

- Generating browser application bundles (phase: setup)...
√ Browser application bundle generation complete.
√ Browser application bundle generation complete.
- Copying assets...
√ Copying assets complete.
- Generating index html...
√ Index html generation complete.

Initial Chunk Files           | Names         |  Raw Size | Estimated Transfer Size
main.2e2ae92db5339444.js      | main          | 117.39 kB |                35.16 kB
polyfills.794d7387aea30963.js | polyfills     |  33.09 kB |                10.63 kB
runtime.89bfad0fe920d2c9.js   | runtime       | 894 bytes |               518 bytes
styles.ef46db3751d8e999.css   | styles        |   0 bytes |                       -

| Initial Total | 151.35 kB |                46.30 kB

Build at: 2023-03-11T17:08:19.724Z - Hash: 121c4cf467eb431c - Time: 4734ms
[INFO]
...

Spring Boot Maven Single JAR Configuration with other Javascript frameworks

As we are only using npm build commands in our plugins, we can use the same snippet to build any other Javascript front-end framework (i.e. Vue.js) as long as they use npm as its build system. Other build tools can be set up easily with a similar approach.

You can download the source code (with the full pom.xml file) from our GitHub repository.

Further reading

Learning new programming languages involve not only the language itself but also the standard library, the toolchain, best practices, security and runtime environments. In the next articles we are going to explore these topics. In the meantime you can explore the example in this article an look for free resources to explore your deployment options for testing and even production environments. Oracle Cloud offers a good enough Always Free tier and you can also explore free options for your data layer.


Posted

in

, , , , ,

by