April 14, 2019
This article demonstrates how to integrate a Vue.js app built with NPM into a Maven RESTful web services project.
Vue CLI generates a skeleton project that includes build instructions for NPM. A production build transforms the Vue.js source code into consolidated files optimized for downloading. The NPM build step is integrated into the compilation step of the Maven build. After the compilation phase is completed, all of the code -- compiled Java and transformed Vue.js -- is packed in a Web Archive (WAR).
The following UML Deployment Diagram shows the demo project. There are two components: "basic-demo" which is a Vue.js app and APIApplication which is a RESTful backend.
maven-npm-build-demo.war is a deployable archive consisting of the Java code from APIApplication and the web artifacts -- HTML, JavaScript, CSS -- from build-demo. The following screenshot from IntelliJ shows the source code structure of the project. The RESTful service returns a string which the Vue.js app displays from a GET call.
The actual code isn't important for the article, but here are a few setup notes.
<jboss-web>
<context-root>build-demo</context-root>
</jboss-web>
module.exports = {
publicPath:
process.env.NODE_ENV === "production" ? "/build-demo/" : "/"
};
The POM starts with a typical WAR packaging configuration: Java version, JAX-RS dependency, ignoreXml flag. Maven delegates the processing of the Vue.js app to NPM using an Exec Plugin. The npm run build
is run during the compilation phase. As the Java source is compiled, the Vue.js app is transformed into its production file structure.
With the compiled code and transformed JavaScript in place, the packaging phase is entered. This produces the Web Archive (WAR) which is a zipped folder. The WAR Plugin is configured to pull in the /dist folder of the Vue.js app.
Finally, the Clean Plugin is configured to also remove the generated /dist folder. This could be expanded to remove node_modules, however this would make a full build slower. Maven's dependencies are usually stored across projects in a centralized local store, so Maven artifacts are typically retained between full builds.
This is the pom.xml stored at the top of the project.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.bekwam</groupId>
<artifactId>maven-npm-build-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.6.2.Final</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<webResources>
<resource>
<directory>src/main/vuejs/build-demo/dist</directory>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>npm</executable>
<workingDirectory>src/main/vuejs/build-demo</workingDirectory>
<arguments>
<argument>run</argument>
<argument>build</argument>
</arguments>
</configuration>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
<configuration>>
<filesets>
<fileset>
<directory>src/main/vuejs/build-demo/dist</directory>
</fileset>
</filesets>
</configuration>
</plugin>
</plugins>
</build>
</project>>
This article showed how to integrate a Vue.js app with a Java EE RESTful backend. Maven is used to unify the build process of two distinct components by adding an npm call in the early stages of the build. To develop with this setup, run the Webpack Dev Server alongside WildFly to serve up the Vue.js pages. That way, you can have a consolidated build with the benefits of Hot Module Reloading (HRM).
By Carl Walker
President and Principal Consultant of Bekwam, Inc