Multi-module projects and Packaging frontend-backend together

Why multi-module projects?

In multimodule projects, you split a big project into smaller modules. For instance, a website can be split to front-end, back-end and db modules.

By splitting,

  • it increases the readability and makes the project easier to maintain.
  • It allows allows us to deploy each module separately if needed
  • If many modules use the same dependencies, we can specify the dependency in parent which would be inherited

Creating a multi-module project

  1. Open intellij->Create new maven project (Remove any source folders if it was automatically generated.We only need a pom.xml in the root directory)
  2. Right click the generated project-> New module and Enter the details of the new module->click create

Once you hit create, you can see that a new tag was added in the parent pom file containing the detail of the new module

<modules>
    <module>backend-api</module>
</modules>

There would also be another tag created in the newly created child module pom.xml

 <parent>
      <artifactId>maven-multimodule</artifactId>
      <groupId>com.ashokgurudayal</groupId>
      <version>1.0-SNAPSHOT</version>
 </parent>

The packaging type of the parent should be

<packaging>pom</packaging>

“pom” packaging mentions that it is just the container, which contains other packages/modules like jar, war, and ear.

if you perform any operation on outer package/container like mvn clean compile install. then inner packages/modules also get clean compile install.

There is no need to perform a separate operation for each package/module.

Packaging frontend and Backend together

When an app is deployed, the frontend and backend can be deployed together or separately.

Quick and easy way is to deploy backend and the frontend together as one jar file to production.

Deploying a Spring boot and React application together

Spring Boot applications can serve static content if you put it into the target/classes/static directory of the application jar file. Create React App can build a static bundle for production by running npm build in the frontend directory.

To accomplish deploying frontend and backend together:

  1. Create a production build of the frontend
  2. Copy the production build into target/classes/static folder of Spring boot app

For the above we can use 2 plugins

Maven Front-end plugin

This plugin lets you create a production build of the frontend To use this plugin, in the front-end pom file, include the following:

 <build>
    <plugins>
        <plugin>
            <groupId>com.github.eirslett</groupId>
            <artifactId>frontend-maven-plugin</artifactId>
            <version>1.7.6</version>

            <executions>
                <execution>
                    <id>Install node and npm</id>
                    <goals>
                        <goal>install-node-and-npm</goal>
                    </goals>
                    <phase>generate-resources</phase>
                    <configuration>
                        <nodeVersion>v16.14.2</nodeVersion>
                        <npmVersion>8.5.0</npmVersion>
                    </configuration>
                </execution>

                <execution>
                    <id>npm install</id>
                    <goals>
                        <goal>npm</goal>
                    </goals>
                    <phase>generate-resources</phase>
                    <configuration>
                        <arguments>install</arguments>
                    </configuration>
                </execution>

                <execution>
                    <id>npm build</id>
                    <goals>
                        <goal>npm</goal>
                    </goals>
                    <phase>generate-resources</phase>
                    <configuration>
                        <arguments>run build</arguments>
                    </configuration>
                </execution>
            </executions>
            <configuration>
                <nodeVersion>v16.14.2</nodeVersion>
                <workingDirectory>${project.basedir}</workingDirectory>
            </configuration>
        </plugin>
    </plugins>
</build>

When you run mvn clean install, maven will install npm and node locally and run npm build in the frontend directory. This results in a production build of the frontend in frontend/build directory.

Maven-resources-plugin

This plugin lets you copy resources from one folder to another. In our case we need to copy the frontend build into target/classes/static folder of Spring boot app. To use this plugin, in the back-end pom file, include the following:

 <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <executions>
        <execution>
            <id>Copy my react app into my Spring Boot target static folder</id>
            <phase>process-resources</phase>
            <goals>
                <goal>copy-resources</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.basedir}/target/classes/static</outputDirectory>
                <resources>
                    <resource>
                        <directory>../frontend-react/build</directory>
                        <filtering>true</filtering>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>

In the parent pom, ensure that the frontend module is defined first, so that the frontend is build first

 <modules>
      <module>frontend-react</module>
      <module>backend-api</module>
 </modules>

On running mvn clean install from the parent directory, the jar containing both frontend and backend would be generated in target folder of the backend module.

When you run java -jar [jar-name], you would be access the frontend as well as backend.

Conclusion:

Most web apps involve both frontend and backend modules and in this article we saw how we could easily package both together, which can be used to deploy as a single jar.

A sample multi-module project containing both frontend and backend can be found at github.com/ashokgurudayal/multi-module