Hilla Documentation

Deploying to Production

How to deploy to a production server by compiling and packaging the application and optimizing it for the server.

Although you may have launched your server directly from your IDE during development, for production you need to deploy the application as a WAR file (Java Servlet) or JAR file that includes your application server (Spring Boot and other embedded servers).

By default, Hilla applications are set up to run in development mode. This requires a bit more memory and CPU power, but enables easier debugging. When deploying your application to your users, you will want to switch to production mode instead.

The main difference between development and production modes is that, in the development mode, Hilla uses webpack to serve JavaScript files to the browser, instead of the Java server the application is running on. This is so that if you change a JavaScript or CSS file, your changes are picked up and served automatically. When you are in production mode, you don’t want this extra overhead, since the files will not change. It’s more efficient to prepare JavaScript and CSS files once, during build, and let one server (the Java Server) serve all requests. At the same time, the client resources can be optimized and minified to reduce the load on the network and browser even further.

Enabling Production Mode

The pom.xml file in a Hilla project has the following built-in Maven configuration to create a production-mode build:

<profiles>
    <profile>
        <id>production</id>
        <properties>
            <vaadin.productionMode>true</vaadin.productionMode>
        </properties>

        <!--
		.. configuration depending on environment ..
		 -->
         <executions>
             <execution>
                 <goals>
                     <goal>build-frontend</goal>
                 </goals>
                 <phase>compile</phase>
             </execution>
         </executions>
		 <!--
		 .. more configuration ..
		 -->
    </profile>
</profiles>

The actual content of the profile will depend on what environment your application is running in, but all of the variants do two things:

  1. Set the property vaadin.productionMode to true

  2. Call the Maven goal vaadin:build-frontend. The Maven goal vaadin:prepare-frontend is also required, but this is often already declared in the development build.

To create a production build, you can call mvn clean package -Pproduction. This will build a JAR or WAR file with all the dependencies and transpiled front-end resources, ready to be deployed. The file can be found in the target folder after the build completes.

If you don’t have the production Maven profile in your POM file, the easiest way to get it’s to create a project base using the CLI, and then copy the production profile from the downloaded POM file.

Having production mode be a separate Maven profile is recommended, so that you don’t get any unexpected problems due to production settings when running in development mode.

Note
Building for 64-bit
If your operating system is 64-bit, make sure to use a 64-bit JDK installation as well.

Excluding the Development Server Module

The webpack server integration and live reload features, which are available only in development mode, are contained in the module com.vaadin:vaadin-dev-server. When running the application in production mode, it’s recommended to exclude this module. This can be achieved by adding the following dependency exclusion to the <dependencies> section in the production profile:

<profiles>
    <profile>
        <id>production</id>

        <!-- above production mode configuration -->

        <dependencies>
            <dependency>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin</artifactId>
                <exclusions>
                    <exclusion>
                        <groupId>com.vaadin</groupId>
                        <artifactId>vaadin-dev-server</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    </profile>
</profiles>

This results in less code and fewer dependency libraries being bundled in the production application.

Transpilation and Bundling

Transpilation in Hilla means converting all ES6 JavaScript to ES5 JavaScript format for older browsers. All Vaadin components are written using ES6, and consist of several JavaScript and CSS files. Transpilation makes sure this newer JavaScript code also works in browsers which don’t support all the latest JavaScript features.

During the build, minimization is carried out to make the files smaller. When minifying code, it’s often obfuscated, which makes it harder to read. Hence, this isn’t done in development mode.

Bundling is an optimization where we merge multiple files to a single collection, so that the browser doesn’t need to request so many files from the server. This helps the application to load faster.

Plugin Goals and Goal Parameters

prepare-frontend

This goal validates whether the node and npm tools are installed and aren’t too old (node version 10 or later and npm version 5.6 or later), and also installs them automatically to the .vaadin folder in the user’s home directory if they are missing. If they are installed globally but too old, there will be an error message suggesting that you install newer versions instead. Node.js is needed to run npm to install frontend dependencies and webpack, which bundles the frontend files served to the client.

In addition, it visits all the resources used by the application and copies them under the node_modules folder, so that they are available when webpack builds the frontend. It also creates or updates the package.json, webpack.config.json and webpack.generated.json files.

Goal Parameters

includes (default: **/*.js,**/*.css)

Comma-separated wildcards for files and directories that should be copied. The default is only .js and .css files.

npmFolder (default: ${project.basedir})

The folder where the package.json file is located. The default is the project root folder.

webpackTemplate (default: webpack.config.js)

Copy webapp.config.js from the specified URL if it’s missing. The default is the template provided by this plugin. Set it to an empty string to disable the feature.

webpackGeneratedTemplate (default: webpack.generated.js)

Copy webapp.config.js from the specified URL if it’s missing. The default is the template provided by this plugin. Set it to an empty string to disable the feature.

generatedFolder (default: ${project.build.directory}/frontend/)

The folder where Flow will put generated files that will be used by webpack.

require.home.node (default: false)

If set to true, always prefer Node.js automatically downloaded and installed into the .vaadin directory in the user’s home directory.

build-frontend

This goal builds the frontend bundle. This is a complex process involving several steps:

  • update package.json with all the @NpmPackage annotation values found in the classpath and automatically install these dependencies.

  • update the JavaScript files containing code to import everything used in the application. These files are generated in the target/frontend folder, and will be used as the entry point of the application.

  • create webpack.config.js if it’s not found, or update it if some project parameters have changed.

  • generate JavaScript bundles, chunks and transpile to ES5 using the webpack server. The target folder for WAR packaging is target/${artifactId}-${version}/build; for JAR packaging, it’s target/classes/META-INF/resources/build.

Goal Parameters

npmFolder (default: ${project.basedir}

The folder where the package.json file is located. The default is the project root folder.

generatedFolder (default: ${project.build.directory}/frontend/)

The folder where Flow will put generated files that will be used by webpack.

frontendDirectory (default: ${project.basedir}/frontend)

The directory with the project’s frontend source files.

generateBundle (default: true)

Whether to generate a bundle from the project frontend sources.

runNpmInstall (default: true)

Whether to run pnpm install (or npm install, depending on the pnpmEnable parameter value) after updating dependencies.

generateEmbeddableWebComponents (default: true)

Whether to generate embedded web components from WebComponentExporter inheritors.

optimizeBundle (default: true)

Whether to include only frontend resources used from application entry points (the default) or to include all resources found on the class path. Should normally be left to the default, but a value of false can be useful for faster production builds or debugging discrepancies between development and production mode.

pnpmEnable (default: false)

Whether to use the pnpm or npm tool to handle frontend resources. The default is npm.

useGlobalPnpm (default: false)

Whether to use a globally installed pnpm tool instead of the default supported version of pnpm.

clean-frontend

This goal will clean-frontend files that may cause inconsistencies when changing versions. It’s suggested not to add the goal as a default to pom.xml, but instead to use it with mvn vaadin:clean-frontend when necessary.

Executing the clean-frontend goal will remove:

  • the package lock file

  • the generated frontend folder (by default frontend/generated)

  • the node_modules folder (this might need manual deletion)

The goal will also clean all dependencies that are framework-managed, and any dependencies that target the build folder from the package.json file.

The clean-frontend goal supports the same parameters as prepare-frontend.