bekwam courses

Building for WildFly and Vue.js

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.

UML Deployment Diagram
Components in WAR Deployed to WildFly

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.

    IntelliJ Project Browser
    Java Code and Web Code

    The actual code isn't important for the article, but here are a few setup notes.

  1. The RESTful Web Services use the a JAX-RS for building which will be provided by the WildFly container.
  2. Vue CLI is run with the -n option since Git will be managed at the toplevel.
  3. We're ignoring but keeping the node_modules folder during a clean to keep the builds performant.
  4. There is a jboss-web.xml file that sets the context root to /build-demo rather than the default (/maven-npm-build-demo-0.0.1-SNAPSHOT).
  5.       
    <jboss-web>
        <context-root>build-demo</context-root>
    </jboss-web>
    
  6. As is typical with production Vue.js configurations, there is the following export in the vue.config.js file.
  7.     
    module.exports = {
        publicPath:
            process.env.NODE_ENV === "production" ? "/build-demo/" : "/"
    };
        

POM

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).


Headshot of Carl Walker

By Carl Walker

President and Principal Consultant of Bekwam, Inc