Maven plugin for Vaadin Flow applications that handles frontend resource management, webpack bundling, and development workflow automation
The build-frontend goal creates optimized frontend bundles for production deployment with comprehensive dependency management and build optimization.
<goal>build-frontend</goal>
<!-- Default phase: process-classes -->
<!-- Dependency resolution: compile-plus-runtime -->This goal performs production build tasks:
package.json with @NpmPackage annotations from classpathnode_modules@JsModule, @Theme, and @JavaScript annotations<configuration>
<!-- Bundle generation -->
<generateBundle>true</generateBundle>
<optimizeBundle>true</optimizeBundle>
<generateEmbeddableWebComponents>true</generateEmbeddableWebComponents>
<compressBundle>true</compressBundle>
<!-- NPM behavior -->
<runNpmInstall>true</runNpmInstall>
<ciBuild>false</ciBuild>
<forceProductionBuild>false</forceProductionBuild>
<!-- Directories -->
<frontendResourcesDirectory>${project.basedir}/src/main/resources/META-INF/frontend</frontendResourcesDirectory>
<frontendOutputDirectory>${project.build.outputDirectory}/META-INF/VAADIN/webapp</frontendOutputDirectory>
<!-- Cleanup -->
<cleanFrontendFiles>true</cleanFrontendFiles>
</configuration><generateBundle>true|false</generateBundle> <!-- Generate frontend bundle -->
<runNpmInstall>true|false</runNpmInstall> <!-- Run npm install -->
<generateEmbeddableWebComponents>true|false</generateEmbeddableWebComponents> <!-- Generate web components -->
<optimizeBundle>true|false</optimizeBundle> <!-- Use bytecode scanner optimization -->
<ciBuild>true|false</ciBuild> <!-- Use npm ci instead of npm install -->
<forceProductionBuild>true|false</forceProductionBuild> <!-- Force build even with default bundle -->
<cleanFrontendFiles>true|false</cleanFrontendFiles> <!-- Clean generated files after build --><frontendResourcesDirectory>path/to/frontend/resources</frontendResourcesDirectory>
<frontendOutputDirectory>path/to/output/directory</frontendOutputDirectory><plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<version>24.9.0</version>
<executions>
<execution>
<goals>
<goal>build-frontend</goal>
</goals>
</execution>
</executions>
</plugin><plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<version>24.9.0</version>
<configuration>
<ciBuild>true</ciBuild>
<forceProductionBuild>true</forceProductionBuild>
<optimizeBundle>true</optimizeBundle>
<runNpmInstall>true</runNpmInstall>
</configuration>
<executions>
<execution>
<goals>
<goal>build-frontend</goal>
</goals>
</execution>
</executions>
</plugin><configuration>
<generateBundle>false</generateBundle>
<runNpmInstall>false</runNpmInstall>
<optimizeBundle>false</optimizeBundle>
<cleanFrontendFiles>false</cleanFrontendFiles>
</configuration><configuration>
<frontendResourcesDirectory>${project.basedir}/frontend-src</frontendResourcesDirectory>
<frontendOutputDirectory>${project.build.directory}/classes/static</frontendOutputDirectory>
</configuration>@NpmPackage annotationsgenerated-flow-imports.js with discovered moduleswebpack.generated.js with build settingsWhen optimizeBundle is enabled, the plugin uses bytecode analysis to discover frontend components:
<optimizeBundle>true</optimizeBundle>Benefits:
The plugin automatically detects production mode based on:
The plugin validates licenses for commercial Vaadin components:
<commercialWithBanner>false|true</commercialWithBanner>false (default): Requires valid license for commercial componentstrue: Allows commercial components with banner warningMissingLicenseKeyException if license requiredAutomatic React integration when React Router is detected:
<reactEnable>true|false|null</reactEnable>null (default): Auto-detect based on routes filetrue: Force React modefalse: Disable React supportSpecial handling for Hilla (full-stack) applications:
# Standard production build
mvn flow:build-frontend
# Force production build
mvn flow:build-frontend -Dvaadin.forceProductionBuild=true
# CI build with locked dependencies
mvn flow:build-frontend -Dvaadin.ciBuild=true
# Build with custom output directory
mvn flow:build-frontend -Dvaadin.frontendOutputDirectory=target/static
# Debug build process
mvn flow:build-frontend -XFor large projects, increase Maven memory:
export MAVEN_OPTS="-Xmx2g -XX:MaxPermSize=512m"
mvn flow:build-frontendEnable parallel dependency resolution:
<configuration>
<pnpmEnable>true</pnpmEnable> <!-- pnpm has better parallel performance -->
</configuration>The plugin includes intelligent caching:
Error: Frontend build failed
Solution: Check webpack output, verify Node.js version, ensure dependencies are compatibleError: JavaScript heap out of memory
Solution: Increase Node.js memory limit or Maven heap sizeError: Missing license key for commercial component
Solution: Add license key or enable commercialWithBanner modeError: npm ERR! peer dependency conflict
Solution: Use ciBuild=false for development, resolve version conflicts in package.jsonTypical phase binding:
<plugin>
<executions>
<execution>
<id>prepare-frontend</id>
<phase>process-resources</phase>
<goals>
<goal>prepare-frontend</goal>
</goals>
</execution>
<execution>
<id>build-frontend</id>
<phase>process-classes</phase>
<goals>
<goal>build-frontend</goal>
</goals>
</execution>
</executions>
</plugin>Install with Tessl CLI
npx tessl i tessl/maven-com-vaadin--vaadin-maven-plugin