github vaadin/flow 25.2.1
Vaadin Flow 25.2.1

2 hours ago

Changes since 25.2.0

All changes

New features

  • Allow setting frontend build toggles via system properties (#24786) (CP: 25.2)
    Commit · Pull request

    Several build-frontend toggles could only be configured through a POM <configuration> block, making it hard to override them for a single build. Add a property attribute to generateBundle, runNpmInstall, generateEmbeddableWebComponents, optimizeBundle and eagerServerLoad so they can be set at runtime, e.g. -Dvaadin.generateBundle=false.

  • Warn when an addon uses the legacy META-INF/resources/frontend layout (#24655) (CP: 25.2)
    Commit · Pull request

    TaskCopyFrontendFiles still scans META-INF/resources/frontend/ for backwards compatibility, but that location is deprecated. Emit a once-per-jar/dir warning recommending the split layout: bundle sources for @JsModule/@CssImport under META-INF/frontend/, and runtime resources for @StyleSheet/@JavaScript under META-INF/resources/ (served directly by the servlet container).

  • Support custom timeout for DevTools license download (#24722) (CP: 25.2)
    Commit · Pull request · Issue

    DevTools triggers an asynchronous license download that opens the system browser so the user can sign in and fetch a license. The license-checker waits a fixed 60 seconds for that to complete, which is too short for first-time users who still need to register a Vaadin account before they can download the license. When the timeout elapses the download fails and the popup that initiated it becomes stale, forcing a page reload and a repeat of the whole flow. Allow callers of downloadLicense in the dev tools to pass an optional timeout. The value is forwarded to the server and passed on to LicenseChecker.checkLicenseAsync; when omitted the previous default behavior is kept.

  • Add RouterState.isNavigationPending() (#24771) (CP: 25.2)
    Commit · Pull request · Issue

    Add RouterState.isNavigationPending() to detect pre-navigation state, so user code can detect the pre-navigation state without an NPE.

  • Fail loudly when a trigger is created without an action (#24716) (CP: 25.2)
    Commit · Pull request

    A Trigger that is never armed with an action does nothing on the client, which is almost always a forgotten terminal binding call (e.g. Clipboard.onClick(button) with no following writeText(...)). Detect this in the Trigger base class — so it covers every trigger/action user, not just clipboard — by deferring a check to beforeClientResponse and throwing an IllegalStateException if no action was committed. Track arming as an intent flag set the moment a binding commits to an action, and add Trigger.triggersWhenAttached(target, supplier) so a binding that legitimately defers wiring until a target component attaches (Fullscreen.enter(detachedPanel)) is not mistaken for a forgotten one.

Fixes

  • Write frontend build files into build dir when it is outside project dir (#24805) (CP: 25.2)
    Commit · Pull request · Issue

    When the build dir is relocated outside the project dir, vaadinPrepareFrontend wrote vaadin-dev-server-settings.json and the dev-bundle output paths underthe source tree. buildFolder() is now always relative to projectDir.

  • Cancel pending validation effect listener on binding removal (#24791) (CP: 25.2)
    Commit · Pull request · Issue

    Binding a not-yet-attached field schedules the internal validation signal effect via a component attach listener instead of creating it immediately. That listener registration was not tracked, so unbind() could not cancel it. After removeBinding(), the stale listener stayed on the field and fired on a later attach, creating an effect for an already-unbound binding. The effect then read the binding's now-null field, throwing a NullPointerException wrapped in "This binding is already unbound" (only reproducible when the attach happened outside the removing UI.access() scope). The attach listener registration is now stored and removed in unbind(), so removing a binding fully tears down its pending effect setup.

  • Support the configuration cache when packaging the production jar (#24795) (CP: 25.2)
    Commit · Pull request · Issue

    The production-mode token-restore action was added as a Jar.doFirst {} whose lambda captures the whole Project, which can't be serialized for the configuration cache. It's moved to the block where the vaadinBuildFrontendToken service is already in scope, and now captures that service provider instead of the Project.

  • Improve shared signal transaction error message (#24663) (CP: 25.2)
    Commit · Pull request

    Clarify error when updating multiple shared signals in a transaction. Explain shared signal transaction restriction with cluster context.

  • Declare signal class tokens as Class<@NonNull T> (#24548) (CP: 25.2)
    Commit · Pull request

    NullAway 0.13.2+ analyzes constructor diamond operators and rejects passing String.class (Class<String>) to a SharedXSignal<@Nullable String> whose constructor takes Class<T>, since Class<T> is invariant. Per JSpecify guidance (NullAway uber/NullAway#1595), declare the type-token parameter (and backing field) as Class<@NonNull T> -- the projection use case. A class token never carries nullness, so this lets callers pass a plain class literal for a nullable element type with no cast.

  • Omit feature flag updater script when no flags are enabled (#24522) (CP: 25.2)
    Commit · Pull request · Issue

    The feature flag bootstrap script was always written into index.html, even when no feature flags were enabled. This left a redundant registration in the production document: js window.Vaadin = window.Vaadin || {}; window.Vaadin.featureFlagsUpdaters = window.Vaadin.featureFlagsUpdaters || []; window.Vaadin.featureFlagsUpd aters.push((activator) => {}); Since feature flags default to disabled, every default production app shipped this dead script. ## Fix featureFlagsInitializer(...) now returns an empty string when no enabled features exist, and initializeFeatureFlags(...) only adds the <script> element when there is something to emit. The generated feature-flags.js already guards on the presence of the window.Vaadin.featureFlagsUpdaters array (if (window.Vaadin.featureFlagsUpdaters) { ... }), so omitting it is safe. ## Testing Updated IndexHtmlRequestHandlerTest to assert the updater script is omitted when no feature flags are enabled (previously it asserted the opposite). mvn spotless:check passes and the test is green. � Generated with Claude Code

  • Fire cancelable event on license download instead of forcing reload (#24721) (CP: 25.2)
    Commit · Pull request · Issue

    DevTools reloaded the page when a license was downloaded, which prevented consumers (such as Copilot) from resuming an ongoing operation. Now a cancelable 'vaadin-license-download-completed' event is dispatched on the document. If no listener calls preventDefault(), the previous reload behavior is kept as the default. Documented that a refresh/reload is necessary so that components replaced by placeholders are recreated and shown again.

  • Send browser details as plain query parameters during v-r=init (#24636) (CP: 25.2)
    Commit · Pull request · Issue

    The initial v-r=init bootstrap request appended browser details as a single JSON-encoded v-browserDetails URL query parameter. The resulting URL contained many percent-encoded escape sequences (%7B, %22, %3A, ...), which some firewalls/WAFs (e.g. Sophos) flag and block, failing the application on the very first page load. Browserdetails are now appended as individual, unwrapped v-* query parameters (e.g. &v-sw=1641&v-tzid=Europe%2FBerlin). Plain key=value pairs contain no JSON braces/quotes,
    so the bootstrap URL no longer carries the percent-encoded JSON pattern. There is a single transport with no fallback. The server reconstructs the details from every v-*request parameter except the v-r request-type marker.

  • Write generated frontend files atomically (#24667) (CP: 25.2)
    Commit · Pull request

    Generated frontend files (vaadin.ts, index.ts, generated-flow-imports, etc.) were written via Files.writeString, which truncates the target and rewrites it in place. A file system watcher such as Vite's can observe that intermediate state and read an empty or partially written file, crashing the dev server with errors like "Failed to resolve import './index' from 'generated/vaadin.ts'". This is hit when Java is recompiled in the background (IDE or agent) while the dev server runs. FileIOUtils.writeIfChanged now writes to a temp file in the same directory and moves it over the target with an atomic move (falling back to a regular replace when the file system does not support atomic moves), so watchers only ever see the complete old or complete new content.

Don't miss a new flow release

NewReleases is sending notifications on new releases.