Angular in the enterprise: Building Angular apps through Maven

Traditionally, Maven’s concept of modules and lifecycle phases doesn’t fit very well to development in the Node ecosystem. Can we do better to bring together both worlds?

Maven’s idea is that each module describes itself in a pom.xml including its dependencies and the build plugins. Build plugins attach to the project’s lifecycle and execute required tasks and commands. A module may have multiple sub modules and, obviously, a sub module references its parent module. Dependencies are installed to a local Maven repository on the user's machine.

In Node and node-related package management — whether that is npm, yarn or pnpm — dependencies are listed in a package.json. Running the package manager’s install command, e.g. yarn install, resolves dependencies, extracts tarballs from a registry and copies a flattened dependency tree to a local node_modules folder.

Node vs. Maven

Node’s node_modules folder is very different to a local Maven repository! A local node_modules folder is on a per-package basis and it will store resolved dependencies in a filesystem tree. On the other side, a local Maven repository is on a per-user basis and stores (potentially) resolvable dependencies.

The most common pitfall in the enterprise world is a thinking of:

“Oh, the file name starts with a letter p and albeit it has a dot-json file ending it somehow looks like a pom.xml”

That thinking led to enterprise-grade build set ups where you were tying each pom.xml to one package.json and thus forcing developers to resolving, extracting and copying dependencies to a node_modules folder – all file system operations on disk again and again and over again again...

A better idea is to treat the Node ecosystem as a first-class citizen in the project’s source code repository and let it install dependencies to a common node_modules folder. In the node community, developers coined the term "dependency hoisting" for such a strategy. The thinking should be that each Maven (sub-)module is related to one app configuration in the Angular CLI. Check out the project’s GitHub Wiki on Multiple Apps integration in the Angular CLI.

Running Node through Maven

From the giant sea of Maven plugins, the Frontend Maven Plugin enables to run Node and related package managers through maven. The ‘trick’ here is to share one node_modules folder across several Maven modules.

The way to achieve such a strategy is to execute the package manager’s install command in the parent module while executing dedicated build commands for each sub module. The parent’s pom.xml looks like so:

    <modules>
<module>apps/bar</module>
<module>apps/foo</module>
<module>apps/foo-bar</module>
</modules>
    <build>
<plugins>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<executions>
<execution>
<id>install node and yarn</id>
<goals>
<goal>install-node-and-yarn</goal>
</goals>
<phase>generate-resources</phase>
</execution>
<execution>
<id>yarn install</id>
<goals>
<goal>yarn</goal>
</goals>
<configuration>
<arguments>install --frozen-lockfile --non-interactive</arguments>
</configuration>
</execution>
</executions>
<configuration>
<nodeVersion>v8.9.0</nodeVersion>
<yarnVersion>v1.3.2</yarnVersion>
</configuration>
</plugin>
</plugins>
</build>

A sub module’s pom.xml sets the working directory of the Frontend Maven Plugin to the project's root directory; i.e., equivalent to the Maven property ${pom.parent.basedir}:

<build>
<plugins>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<!-- .. -->
<configuration>
<workingDirectory>${pom.parent.basedir}</workingDirectory>
</configuration>
</plugin>
</plugins>
</build>

Let’s build the Angular apps through maven:

The classic ng commands

Though our project is now ready to be rocketed into enterprise-grade heaven, frontend developers still got the love of running their most-memoized and firm-favourite cli commands on the shell of their choice. Let’s do that!

Are you interested in seeing the set up live and in action? Get it on GitHub!