Changes since 25.2.4
Breaking changes
-
Restore cached Gradle frontend build outputs (#25001) (CP: 25.2)
Commit · Pull request · IssueGradle production builds could produce application archives (JAR/WAR) without the Vaadin frontend resources when the
vaadinBuildFrontendoutput was restored from Gradle's build cache, causing the packaged application to fail in production because the client bundle was missing. The production frontend output is now a declared task output, so it is correctly restored from the build cache and reliably packaged into the application archive, including custom archive tasks. The newincludeArchiveTasksandexcludeArchiveTasksoptions let you control which archives receive the frontend bundle. Breaking change: a customfrontendOutputDirectorymust now follow theMETA-INF/VAADIN/webapplayout (as the default does). A value that does not end inMETA-INF/VAADIN/webappis rejected with a build error in production mode. Previously it silently produced an archive without the frontend bundle and, on Gradle 9, failed with an implicit task-dependency error.Breaks ONLY Gradle projects defining a custom
frontendOutputDirectorynod ending inMETA-INF/VAADIN/webapp.
Fixes
-
Make vaadinBuildFrontend build cache relocatable (#25033) (CP: 25.2)
Commit · Pull request · IssueThe task cache key embedded absolute project paths, so a shared build cache never hit across checkouts at different locations. Directory inputs no longer contribute their absolute path to the key. ---------
-
Include
/usr/binas location for linux tools (#25026) (CP: 25.2)
Commit · Pull requestWhen installing nodejs through the package manager it lands in
/usr/bin -
Expose production frontend bundle on the runtime classpath (#25024) (CP: 25.2)
Commit · Pull request · IssueThe production frontend bundle produced by vaadinBuildFrontend was written to a task-owned directory (build/vaadin-build-frontend) that is not on the runtime classpath. It was copied into application archives with an explicit Jar.from(...), but never exposed on the classpath, so an application served in place from the source set output - gretty during a production build, or an IDE/bootRun launch - no longer found the bundle or the production flow-build-info.json and started in development mode, failing with "There is no dev-bundle ... found". Register the bundle directory as an extra output of the main source set (output.dir(builtBy: vaadinBuildFrontend)), restoring the behavior that shipped through 25.1.x: the bundle is on the runtime classpath for in-place runs and is packaged into every application archive through standard source-set-output handling (WEB-INF/classes for WAR, the archive root for plain and Spring Boot executable jars). The task-owned output directory introduced in #25001 is kept, so the build-cache fix (#24012) is preserved. Because output.dir makes the
classeslifecycle task depend on vaadinBuildFrontend, this task no longer depends onclasses(which would form a cycle). Ordering after compilation is established by its@ClasspathclassesDirs input, and ordering after resource processing by an explicit dependency on the processResources task. The per-archive Jar.from(...) copying, the Spring Boot BOOT-INF/classes special-casing, and the includeArchiveTasks/excludeArchiveTasks options (all introduced in 25.3.0-alpha4, never in a stable release) are no longer needed and are removed. The Spring Boot bundle location returns to the archive root, matching 25.1.x. -
Write pnpm overrides to pnpm-workspace.yaml (#24918) (CP: 25.2)
Commit · Pull requestRecent pnpm versions no longer read the "pnpm" field from package.json, so the dependency overrides Flow generated there were silently ignored and pnpm logged a warning about it. As a result Flow could no longer lock transitive dependencies to the platform versions when using pnpm. Flow now writes these overrides to pnpm-workspace.yaml, the location pnpm actually reads, and moves any overrides left in package.json over to it. Existing user content in pnpm-workspace.yaml is preserved, and a Flow-generated file is cleaned up like other generated frontend files.
-
Respect custom npm registry in seeded package-lock.json (#24921) (CP: 25.2)
Commit · Pull requestWhen seeding a project's
package-lock.jsonfrom the dev-bundle template, Flow copied it verbatim, keeping the hardcodedregistry.npmjs.orgURLs in everyresolvedfield. With a custom npm registry configured, this leaves a committed lock (withcleanFrontendFiles=false) that still points atregistry.npmjs.org, and packages can end up being downloaded from npmjs instead of the configured registry — for example when only a scoped@scope:registryis set, or when npm's registry-host rewriting is turned off. This breaks private/air-gapped setups and any tooling that consumes the lock without npm's rewriting. Strip theresolvedfields from the seeded npmpackage-lock.jsonwhen a custom registry is configured, so npm re-resolves the download URLs against that registry. Theintegrityhashes are kept so npm still verifies the downloaded tarballs against the versions Vaadin tested. Default setups keep the verbatim fast-path copy. Whether a custom registry is configured is now determined by npm itself (npm config ls --json) rather than by scanning.npmrcfiles, so it also covers registries set through environment variables, the global npmrc, or the command line, as well as scoped registries. -
Prevent NPE in ElementEffect detach listener on re-attach (#25005) (CP: 25.2)
Commit · Pull request · IssueElementEffect registered a new detach listener on every attach, stored it in the single detachRegistration field, and relied on each detach listener removing itself. When an element is re-attached without a detach event firing in between - StateNode.removeFromTree(false), as used by UIInternals.moveToNewUI for
@PreserveOnRefresh- a second detach listener was registered while the first was still present. The next real detach ran both: the first nulled detachRegistration, the second dereferenced null and threw a NullPointerException. Register the detach listener through a helper that removes any previous registration before adding a new one, and null-guard the removal inside the listener so at most one detach listener is ever active. -
Skip vaadinBuildFrontend in development mode (#25002) (CP: 25.2)
Commit · Pull request · IssueThe Gradle vaadinBuildFrontend task is now skipped when Vaadin production mode is not enabled. This prevents development and multi-module builds from failing when the task is part of the build graph, and avoids producing a production configuration while running in development mode.