github vaadin/flow 25.2.0-alpha1
Vaadin Flow 25.2.0-alpha1

pre-release5 hours ago

Changes since 25.1.0-beta1

All changes

Breaking changes

  • Make localeSignal() read-only on VaadinSession and UI
    Commit · Pull request

    Return Signal instead of SharedValueSignal/ValueSignal from localeSignal() so that all locale changes go through setLocale(), which handles UI propagation and LocaleChangeObserver notification. Add javadoc showing two-way binding pattern with bindValue and setLocale. Add tests for bindValue-based locale switching, UI locale independence from session, and session setLocale with per-UI override.

  • Split computed into separate cached and direct versions
    Commit · Pull request

    Previously, the computed method was just one out of many ways of creating a computed signal with the distinction that this computed signal was also caching. This made it difficult to understand when to use the method. computed signal and introducing a separate cached method that creates a cached signal out of any other signal. signals

New features

  • Extract interface HierarchicalTreeData from TreeData
    Commit · Pull request · Issue

    TreeDataProvider currently takes a TreeData as its source. But it relies only on a few methods of TreeData. This change extracts those methods into an interface. It then introduces a super class to TreeDataProvider which accepts a HierarchicalTreeData instead of a TreeData. A client has now the choice to either use the TreeData and the TreeDataProvider, or it can implement the HierarchicalTreeData interface and use the HierarchicalTreeDataProvider. This change introduces a new interface and a class but does not change or break any existing API.

  • BuildFrontend Incremental build
    Commit · Pull request

    Add incremental build to the buildFrontend task. Closes #17354

  • Retain local signal values during hotswap
    Commit · Pull request · Issue

    Automatically transfer local signal values from old view fields to matching fields in the new view during hotswap refresh. ---------

  • Apply ElementEffect once when created
    Commit · Pull request · Issue

    ElementEffect is executed immediately once when created. This affects all Signal.effect calls with an owner component. Immediate execution ensures that exceptions can be thrown eagerly when e.g. bindText(signal) is called, not later when component is attached.

  • Throw binding exception if setItems is called while an active signal binding
    Commit · Pull request · Issue

  • Add local web components plugin to vite.generated.ts
    Commit · Pull request

    Auto-detects a web-components/node_modules directory in the project root and redirects polymer/* and vaadin/* imports to it in dev mode. A custom folder can be specified through vite.config.ts using the overrideVaadinConfig mechanism.

  • Add bindItems to HasDataProvider components
    Commit · Pull request

  • Add setTestId/getTestId convenience methods to Component
    Commit · Pull request · Issue

  • Add SignalBinding with rich BindingContext for bind methods
    Commit · Pull request

    All Element bind methods (bindText, bindEnabled, bindVisible, bindProperty, bindAttribute, etc.), and Style.bind(), bindWidth(), bindHeight(), ThemeList.bind(), HasStyle.bindClassNames(), and HasTheme.bindThemeNames() now return SignalBinding object instead of void. SignalBinding exposes an onChange callback that receives a BindingContext with the old value, new value, whether it's the initial run, and the bound element/component. ElementEffect.bind() creates the SignalBinding internally and wires the effect registration into it so callers can control the effect lifecycle.

  • Allow setProperty if signal write callback is present
    Commit · Pull request · Issue

    This change allows setting element property value if signal binding's write callback is present (not null). Each Element setProperty method is updated to change the signal value with the same logic as with a property value change from the client did before (and same logic as in HasValue#bindValue two-way binding). One-way binding, with null write callback, works same as before and throws BindingActiveException.

  • Add content-hash cache busting for Stylesheet URLs
    Commit · Pull request

    • In production mode, append a ?v-c=<8-char-sha256> query parameter to StyleSheet URLs so browsers reload only when file content changes, enabling aggressive caching with Cache-Control: max-age=31536000, immutable for versioned requests. - Content hashing is applied in both the AppShell path (AppShellRegistry.addStyleSheets) and the component dependency path (UidlWriter.dependencyToJson), covering all StyleSheet usage. - StaticFileServer now returns a 1-year immutable cache header when the v-c query parameter is present in production mode, instead of the default short-lived cache.

Fixes

  • Shade asm into flow-build-tools
    Commit · Pull request · Issue

    Shades ASM into flow-build-tools and relocates classes to an internal package. Prevents build time errors with projects that depend on older ASM versions.

  • Remove type parameter from Signal.effect
    Commit · Pull request · Issue

    The removal of type parameter T from the Signal.effect methods is binary-compatible and source-compatible.

  • Add missing registerStyles import to generated app-shell-imports.js
    Commit · Pull request · Issue

    The generated app-shell-imports.js file was missing the THEMABLE_MIXIN_IMPORT line (import { css, unsafeCSS, registerStyles }), causing ReferenceError: registerStyles is not defined at startup in production mode when CssImport with themeFor was used on an AppShellConfigurator. Also ensures import statements are moved to the top of the generated app shell file, consistent with other generated import files.

  • Prevent duplicated CSS imports in web component generated file
    Commit · Pull request · Issue

    When a CSS file is referenced by both a regular component and a WebComponentExporter (or AppShellConfigurator), the generated web component imports file contained duplicate import statements and duplicate style registrations for the same CSS. This happened because the web component output merges multiple independently generated files, and the existing string-based deduplication could not recognize that two imports for the same file were equivalent. The fix detects duplicate CSS file imports after merging and unifies their variable references so that identical style registrations are properly deduplicated, while preserving distinct registrations when the same CSS file is intentionally used with different configurations.

  • Use UI identity for background change detection in Effect
    Commit · Pull request · Issue

    EffectContext.isBackgroundChange() always returned false for shared signals modified by another user's session because the check only looked at VaadinRequest.getCurrent(), which is non-null on any request thread. Now Effect tracks its owner UI and compares UI.getCurrent() against it, correctly detecting cross-session changes as background changes.

  • Prevent computed signal from being evaluated twice during binding
    Commit · Pull request · Issue

    Previously, when creating a signal binding (e.g., bindText, bindProperty), the signal was evaluated twice: 1. Once via signal.peek() to initialize the previousValue 2. Once via signal.get() during the first effect execution This was inefficient, especially for expensive computed signals. The fix removes the signal.peek() call and instead tracks whether the effect has run before using a hasRun flag. On the first execution, oldValue is set to newValue (maintaining the contract that they are equal on initial run). On subsequent executions, oldValue comes from the previousValue array. 🤖 Generated with Claude Code

  • Prevent stale JAR cache in Reflector under Maven daemon (mvnd)
    Commit · Pull request

    Mirror the Gradle daemon fix (33fa374) in the Maven plugin's Reflector and ReflectorClassLoader/CombinedClassLoader: - Extract ReflectionsClassFinder.disableJarCaching() as a public utility so both plugins can reuse it. - Wrap jar: URLs in ReflectorClassLoader.getResource() and getResources() (flow-maven-plugin) and CombinedClassLoader (flow-dev-bundle-plugin) with useCaches(false) to prevent stale JarFileFactory entries across daemon builds. - Make Reflector implement Closeable with a close() method that releases the URLClassLoader file handles, and register a Cleaner action for best-effort GC cleanup of abandoned instances. - Close the temporary Reflector in FlowModeAbstractMojo.isHillaAvailable(MavenProject) via try-with-resources. Releated to #15458

  • Prevent stale JAR cache in ReflectionsClassFinder under Gradle daemon
    Commit · Pull request · Issue

    Close URLClassLoader on cleanup to release JAR file handles, and disable JVM-level JAR caching in getResource() by wrapping jar: URLs with a URLStreamHandler that sets useCaches(false). The Gradle daemon reuses JVMs across builds. When a sibling module's JAR is rewritten, two independent caching layers can hold stale file handles: 1. URLClassLoader internal cache (URLClassPathJarLoader) 2. JarFileFactory static HashMap (populated via JarURLConnection) The URLClassLoader.close() call addresses layer 1, but layer 2 is JVM-global and independent of the class loader. Setting useCaches(false) on jar: URL connections prevents JarFileFactory from caching JarFile instances, matching the approach used by Spring's PathMatchingResourcePatternResolver (SPR-4639).

  • Delete flow-build-info.json after Maven session via AbstractMavenLifecycleParticipant
    Commit · Pull request · Issue

    BuildFrontendUtil.updateBuildFile() calls deleteOnExit() on the production token file, but this never fires when using the Maven Daemon (mvnd) because the JVM stays alive between builds. As a result, flow-build-info.json with productionMode: true persists in target/classes/META-INF/VAADIN/config/ and causes incorrect production-mode behavior when starting the app from the IDE. Adds FlowLifecycleParticipant, an AbstractMavenLifecycleParticipant that hooks into afterSessionEnd() to delete the token file after every build session. BuildFrontendMojo stores the resolved token file path in a Maven project property so the participant always uses the correct path even when resourceOutputDirectory is user-configured. AbstractMavenLifecycleParticipant only activates when the plugin is declared as a Maven extension, so users must add <extensions>true</extensions> to the plugin declaration in their pom.xml to benefit from this fix. The existing deleteOnExit() call acts as a transparent fallback for projects that do not opt in.

  • Build should not depend on prepare
    Commit · Pull request

    Running the build frontend task should not depend on the prepare task so that the tasks do not break each others caching. Also introduces a build service for token file deletion at the end of the build process. part of #17354

  • Prevent addon stylesheet links from being removed during CSS live reload
    Commit · Pull request · Issue

    During CSS live reload, PublicResourcesLiveUpdater pushed null content for addon stylesheets not found in local source roots, and removeOldLinks() in vaadin-dev-tools used substring matching (.includes()) which could incorrectly remove unrelated <link> tags. Server-side changes: - Add jar-resources folder as a watched source root in DevModeHandlerManagerImpl so addon CSS changes are detected - Skip pushing null updates for stylesheets that exist on the classpath (e.g. from addon JARs) in PublicResourcesLiveUpdater - Use ResourceProvider to check classpath existence before deciding to remove a stylesheet - Strip frontend/ prefix in PublicStyleSheetBundler when resolving addon stylesheets against jar-resources roots, since TaskCopyFrontendFiles removes that prefix during copy Client-side change: - Replace .includes(path) with path-suffix matching in removeOldLinks() to only remove links whose href ends with '/' + path or exactly equals path, after stripping query strings and fragments

  • Propagate forceInstantiation and recreateLayoutChain flags through forward/reroute
    Commit · Pull request · Issue

    When refreshCurrentRoute(true) triggers a BeforeEnterObserver that calls forwardTo() or rerouteTo(), the forceInstantiation and recreateLayoutChain flags were lost because the redirect navigation events were created without them. This caused the redirect target to reuse existing component instances instead of creating new ones. Propagate the flags in three locations: - AbstractNavigationStateRenderer.getNavigationEvent() for both normal and error redirect paths - InternalRedirectHandler.handle() for internal redirects

  • Merge property descriptors when getter and setter come from different interfaces
    Commit · Pull request · Issue

    BeanUtil's dedup loop was replacing a read-only descriptor with a write-only one (or vice versa) instead of merging them. This caused BeanPropertySet to lose the getter when a parent interface provided it and a child interface provided the setter.

  • Use targeted item refresh when signal-bound item value changes
    Commit · Pull request · Issue

    • Add a two-argument refreshItem(T newItem, T oldItem) overload to DataProvider, DataView, and related classes, enabling targeted refresh when an item's identity changes (e.g., signal-bound items replaced with new instances) - DataRefreshEvent now carries an optional old item reference via getOldItem(), allowingDataCommunicator and KeyMapper to remap from the old identity to the new one instead of failing to find the item - HierarchicalDataCommunicator throws UnsupportedOperationException for identity-changing refreshes, deferring TreeGrid bindItems support to a future change
  • Move thread start out of DevServerWatchDog constructor
    Commit · Pull request

    Starting a thread in a constructor can expose a partially constructed object. Extract the thread start into a separate start() method that callers invoke after construction completes.

  • Use String type for Style.bind return value
    Commit · Pull request

    Change Style.bind(String, Signal<String>) return type from SignalBinding<?> to SignalBinding<String> since the method always accepts a Signal<String> and we always know the value type is String. This provides better type safety and eliminates the need for casts when using the binding's onChange callbacks.

  • Route with context path name
    Commit · Pull request · Issue

    the same start as the context path from clearing context path out from the url when using react router.

  • Move import statements to top in generated web component imports file
    Commit · Pull request

    AbstractUpdateImports.process() already reorders import lines to the top for generatedFlowImports, but the same sorting was not applied to generatedFlowWebComponentImports. This caused interleaved import and non-import lines (e.g. injectGlobalWebcomponentCss() calls mixed with import statements) in the web component output. Extract a reusable moveImportsToTop() method and apply it both in process() for main imports and in mergeWebComponentOutputLines() after merging and deduplicating the web component sources. Related to #23689 (comment)

  • Skip ElementEffect callback on reattach when no signals changed
    Commit · Pull request · Issue

    Add passivate/activate lifecycle to Effect so that ElementEffect can preserve tracked Usage instances across detach/attach cycles. On reattach, activate checks whether any dependency has changed since passivation: if so, the callback re-runs with isInitialRun=true; if not, only the dependency listeners are re-registered without invoking the callback, avoiding redundant work and confusing double invocations.

  • Improve npm resolution for non-windows
    Commit · Pull request

    Adds another potential path to the npm resolver algorithm to make it compatible with node installation performed by frontend-maven-plugin

  • Detect router-link attribute in ancestor elements during click navigation
    Commit · Pull request

    When a nested element (e.g., Button) inside a RouterLink is clicked, the navigation trigger was incorrectly reported as CLIENT_SIDE because only the direct click target was checked for the router-link attribute. Traverse the composed path instead so any ancestor with router-link is correctly identified as a ROUTER_LINK trigger.

  • Allow local signal reads in computed callbacks triggered from transaction commit
    Commit · Pull request · Issue

    During the StagedTransaction commit phase, listener callbacks that re-evaluate computed signals could not read local signals because inExplicitTransaction() still returned true. The transaction is no longer staging commands at that point, so local signal access is safe.

  • Shared Signal.get() should throw outside reactive context with fallback transaction
    Commit · Pull request · Issue

    The reactive context check in AbstractSharedSignal.get() used Transaction.inTransaction() which returns true when a session-scoped fallback transaction is active. This caused shared signals to silently allow get() calls outside reactive contexts when the session lock was held (e.g. in onAttach), unlike local signals which correctly threw. Changed the check to use Transaction.inExplicitTransaction() so that only explicitly started transactions (via runInTransaction) count as a valid reactive context, matching the behavior of local signals.

  • Skip validation on signal effect initial run in Binder
    Commit · Pull request · Issue

    The reactive signal effect created by initInternalSignalEffectForValidators() was firing validation on its initial run when deferred to component attach, causing required fields to be marked invalid immediately on navigation. Use the context-aware Signal.effect() variant and skip fireValidationEvents on the initial run, so validation only triggers on actual value changes.

  • Suppress duplicate WEB-INF/lib JAR scan warnings in Jetty
    Commit · Pull request

    Add webInfIncludeJarPattern to the Jetty plugin configuration in flow-tests pluginManagement. The regex pattern excludes JARs from the jetty_overlays directory while still scanning Maven-resolved dependencies. This prevents Jetty from scanning the same JARs twice when overlay WARs are used (Maven classpath + overlay WEB-INF/lib). This eliminates ~31,000 "scanned from multiple locations" warnings per CI build from the WAR overlay modules (test-router-custom-context-encoded and its prod variant).

  • Preserve scroll position of all scrollable elements after hot-swap
    Commit · Pull request · Issue

    Capture and restore scroll positions of all scrollable elements during hot-swap UI refresh and full page reload. Elements are identified by CSS selector paths built from nth-of-type selectors anchored to the nearest ancestor with an ID, so elements without explicit IDs are also supported. The window scroll position uses a special window key. Only elements with non-zero scroll are captured, keeping the snapshot small. Both code paths are updated: the vaadin-dev-tools TypeScript (used for dev server WebSocket-triggered refreshes and full reloads via sessionStorage) and the Hotswapper Java inline JS (used for the vaadin-refresh-ui custom event).

  • Add SignalBindingFeature by default for text state node
    Commit · Pull request

    Supporting SignalBindingFeature by default removes danger to get IllegalStateException when using StateNode#getFeatureIfInitialized(Class) to get SignalBindingFeature.

  • Use absolute path for Aura CSS resource availability check
    Commit · Pull request

    The isResourceAvailable call used the relative path "aura/aura.css" which, after URI resolution, was passed unchanged to ServletContext.getResource(). The Servlet specification requires paths to start with "/" and the missing leading slash caused a MalformedURLException, making the check always fail and flooding logs with warnings on every page load.

  • Exclude duplicate flow-build-tools JAR from WAR packaging
    Commit · Pull request

    The maven-shade-plugin replaces the main artifact's file reference with shaded content during reactor builds, causing both flow-build-tools.jar and flow-build-tools-shaded.jar (byte-identical) to end up in test WAR WEB-INF/lib directories. This produces hundreds of duplicate-class warnings from Jetty's AnnotationParser. Add a packagingExcludes regex to the maven-war-plugin configuration in the root POM's pluginManagement to exclude the non-shaded JAR while keeping the shaded one.

Tests

  • Migrate flow-polymer-template tests to JUnit 6
    Commit · Pull request

  • Migrate flow-build-tools tests to JUnit 5
    Commit · Pull request

  • Migrate flow-data tests to JUnit 5
    Commit · Pull request

    Convert 71 test files from JUnit 4 to JUnit 5: - Replace JUnit 4 imports with JUnit 5 equivalents - Before/After -> BeforeEach/AfterEach - Test(expected=X.class) -> assertThrows(X.class, ...) - ExpectedException Rule -> assertThrows + message assertions - Assert.xxx() -> static imports from Assertions - Message-first assertions reordered to message-last - RunWith(Parameterized.class) -> ParameterizedTest + ValueSource for DataCommunicatorTest and DataCommunicatorAsyncTest - Visibility adjustments for cross-package inheritance

  • Migrate vaadin-dev-server tests to JUnit 6
    Commit · Pull request

Don't miss a new flow release

NewReleases is sending notifications on new releases.