Changes since 25.2.5
Fixes
-
Read minimum frontend package age from config in dev mode (#25101) (CP: 25.2)
Commit · Pull requestThe dev mode initializer built the frontend Options without reading the npm.minimumFrontendPackageAgeDays property, so the minimum package age check was ignored at runtime and always fell back to the Options default of one day. The Maven build path already wired this through, making dev mode inconsistent with the build. Read the property in DevModeInitializer and pass it to the Options via withMinimumFrontendPackageAgeDays.
-
Collect frontend dependencies of dev tools message handlers (#25089) (CP: 25.2)
Commit · Pull requestFrontendDependencies resolves DevToolsMessageHandler subtypes to add them as internal entry points, but the class was missing from the
@HandlesTypesof DevModeStartupListener. DevModeClassFinder only knows the classes listed there and throws for anything else, and that exception was swallowed by the surrounding catch block intended for a missing dev tools classpath entry. As a result, frontend dependencies declared by dev tools plugins were silently skipped in development mode when the byte-code scanner is enabled. -
Do not reinstall packages when pnpm reformats its workspace file (#25084) (CP: 25.2)
Commit · Pull request · IssuePnpmWorkspaceFile.save() compared the serialized text of pnpm-workspace.yaml against the file on disk. pnpm rewrites that file while installing, in its own formatting, so the next dev-mode start re-serialized identical content, saw different text and reported a change. That marks package.json as modified and runs a full package install on the first reload of a fresh project, while the user waits. Compare the parsed content instead, so the same configuration in a different layout is not a change.
-
Keep the development frontend token out of production archives (#25071) (CP: 25.2)
Commit · Pull request · IssuevaadinPrepareFrontend writes a development flow-build-info.json into resourceOutputDirectory, and the plugin registered that folder as a resources source folder unconditionally. Invoking the task explicitly then caused two failures: - processResources consumed the folder without any ordering against the task producing it, so Gradle failed with an implicit dependency validation error. - In a production build the development token was copied into build/resources/main while vaadinBuildFrontend wrote its own token into its task-owned output directory, so the archive ended up with two conflicting copies of META-INF/VAADIN/config/flow-build-info.json and the jar/war task failed. A folder left behind by an earlier development build was enough to trigger this, without the two tasks ever sharing a task graph. Register resourceOutputDirectory as a resources source folder only in development mode - in production vaadinBuildFrontend generates the whole META-INF/VAADIN tree into its own output directory - and declare the ordering that processResources and vaadinBuildFrontend need relative to vaadinPrepareFrontend, without adding a dependency that would make the task execute on every build.
-
Shortcuts should not leak over popover or modal boundary (#25044) (CP: 25.2)
Commit · Pull request · IssueBlock shortcut propagation if crossing a popover-open or modal boundary. This makes dialog shortcuts not propagate up from a nested dialog.
-
Resolve route scope UI from the detach event (#25064) (CP: 25.2)
Commit · Pull request · IssueRouteStoreWrapper#getBeanStore re-points a bean store to the UI created by a browser refresh, but the store's detach listener stays on the previous UI. resetUI() then asked findPreservingUI() about currentUI, which is no longer the UI the detach event comes from. If the refreshed UI had already been removed from the session, its session reference is null and findPreservingUI() threw a NullPointerException. The exception escaped before the branch that destroys the store, so the route scoped beans were not destroyed and the store stayed in routeStores. During session expiration the beans are still released by the session destroy listener of RouteStoreWrapper, but when only the UIs of an idle browser window are removed nothing cleans them up and they leak until the session ends. Pass the detached UI from the event into resetUI() so the lookup always gets the UI the event originates from, which still has its session at that point. findPreservingUI() now also returns null instead of dereferencing a UI that has no session anymore.