From 06613049d4b1c417aae4c3ed405f9774522a74be Mon Sep 17 00:00:00 2001 From: Beniamin Malinski Date: Tue, 14 Jul 2026 16:13:05 +0200 Subject: [PATCH 1/2] build(console-ui): upgrade tanstack query to 5.101.2 Co-Authored-By: OpenAI Codex --- frontend/bun.lock | 12 ++++++------ frontend/package.json | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/bun.lock b/frontend/bun.lock index b3fdc8d4c0..8e0c97227e 100644 --- a/frontend/bun.lock +++ b/frontend/bun.lock @@ -42,7 +42,7 @@ "@shikijs/themes": "^3.23.0", "@stepperize/react": "^5.1.9", "@tanstack/react-form": "^1.12.3", - "@tanstack/react-query": "^5.99.2", + "@tanstack/react-query": "5.101.2", "@tanstack/react-router": "^1.170.17", "@tanstack/react-table": "^8.21.3", "@tanstack/react-virtual": "^3.13.12", @@ -119,7 +119,7 @@ "@rsdoctor/rspack-plugin": "1.5.12", "@tailwindcss/typography": "^0.5.19", "@tailwindcss/vite": "4.2.4", - "@tanstack/react-query-devtools": "^5.90.2", + "@tanstack/react-query-devtools": "5.101.2", "@tanstack/react-router-devtools": "^1.167.0", "@tanstack/router-plugin": "^1.168.19", "@testing-library/dom": "^10.4.1", @@ -1151,15 +1151,15 @@ "@tanstack/pacer": ["@tanstack/pacer@0.15.4", "", { "dependencies": { "@tanstack/devtools-event-client": "^0.3.2", "@tanstack/store": "^0.7.5" } }, "sha512-vGY+CWsFZeac3dELgB6UZ4c7OacwsLb8hvL2gLS6hTgy8Fl0Bm/aLokHaeDIP+q9F9HUZTnp360z9uv78eg8pg=="], - "@tanstack/query-core": ["@tanstack/query-core@5.99.2", "", {}, "sha512-1HunU0bXVsR1ZJMZbcOPE6VtaBJxsW809RE9xPe4Gz7MlB0GWwQvuTPhMoEmQ/hIzFKJ/DWAuttIe7BOaWx0tA=="], + "@tanstack/query-core": ["@tanstack/query-core@5.101.2", "", {}, "sha512-hH5MLoJhF7KaIGd7q3xTXGXvslI+GYlM1Z/35aSHHWaCJWB7XvTSHYuV3eM7tw+aE0mT/xMro4M4Q9rCGHT0lw=="], - "@tanstack/query-devtools": ["@tanstack/query-devtools@5.90.1", "", {}, "sha512-GtINOPjPUH0OegJExZ70UahT9ykmAhmtNVcmtdnOZbxLwT7R5OmRztR5Ahe3/Cu7LArEmR6/588tAycuaWb1xQ=="], + "@tanstack/query-devtools": ["@tanstack/query-devtools@5.101.2", "", {}, "sha512-o+wHcqgN7Pp0s8v1i0UGq/ZrrEKrxdIiMQmKRdYb2w7NPtylYSJ4+wg/tIn71m9DLstwUwdEGAvROdly6HXP6w=="], "@tanstack/react-form": ["@tanstack/react-form@1.25.0", "", { "dependencies": { "@tanstack/form-core": "1.25.0", "@tanstack/react-store": "^0.7.7" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-SjKpBkjegNVW9WU+qlO8+/+kSbSEwo2zwHnrQz/yOnnJRhtdgubUt50LfeUtdzkMsbbptQ5MSZrXH03kidQjyw=="], - "@tanstack/react-query": ["@tanstack/react-query@5.99.2", "", { "dependencies": { "@tanstack/query-core": "5.99.2" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-vM91UEe45QUS9ED6OklsVL15i8qKcRqNwpWzPTVWvRPRSEgDudDgHpvyTjcdlwHcrKNa80T+xXYcchT2noPnZA=="], + "@tanstack/react-query": ["@tanstack/react-query@5.101.2", "", { "dependencies": { "@tanstack/query-core": "5.101.2" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-seDkr6kzGzX1okaaTtZPtgA688CDPlXUz1C6xSg0ESqn04Vuc8tlrYms1s3de+znBqhPVxFRfpAfUf+6XvfPWg=="], - "@tanstack/react-query-devtools": ["@tanstack/react-query-devtools@5.90.2", "", { "dependencies": { "@tanstack/query-devtools": "5.90.1" }, "peerDependencies": { "@tanstack/react-query": "^5.90.2", "react": "^18 || ^19" } }, "sha512-vAXJzZuBXtCQtrY3F/yUNJCV4obT/A/n81kb3+YqLbro5Z2+phdAbceO+deU3ywPw8B42oyJlp4FhO0SoivDFQ=="], + "@tanstack/react-query-devtools": ["@tanstack/react-query-devtools@5.101.2", "", { "dependencies": { "@tanstack/query-devtools": "5.101.2" }, "peerDependencies": { "@tanstack/react-query": "^5.101.2", "react": "^18 || ^19" } }, "sha512-eU7HctdA9gDjqoERoEdzLbw9DiqnBDfh5+Hu0u26gjqoHJezOpQAuiesDL2VvkU+2cPV76zgv0tMZsOrI4LjnQ=="], "@tanstack/react-router": ["@tanstack/react-router@1.170.17", "", { "dependencies": { "@tanstack/history": "1.162.0", "@tanstack/react-store": "^0.9.3", "@tanstack/router-core": "1.171.14", "isbot": "^5.1.22" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-ppLkjCfSMaeug9rmFRYzOd4TIqWV+yTE7tzIny7alJsSnM7w4lzEZm6eqCehG0SPetpZ0R3K+UnanSmBgOAVcQ=="], diff --git a/frontend/package.json b/frontend/package.json index bab242bc06..b2f202e0ee 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -86,7 +86,7 @@ "@shikijs/themes": "^3.23.0", "@stepperize/react": "^5.1.9", "@tanstack/react-form": "^1.12.3", - "@tanstack/react-query": "^5.99.2", + "@tanstack/react-query": "^5.101.2", "@tanstack/react-router": "^1.170.17", "@tanstack/react-table": "^8.21.3", "@tanstack/react-virtual": "^3.13.12", @@ -163,7 +163,7 @@ "@rsdoctor/rspack-plugin": "1.5.12", "@tailwindcss/typography": "^0.5.19", "@tailwindcss/vite": "4.2.4", - "@tanstack/react-query-devtools": "^5.90.2", + "@tanstack/react-query-devtools": "^5.101.2", "@tanstack/react-router-devtools": "^1.167.0", "@tanstack/router-plugin": "^1.168.19", "@testing-library/dom": "^10.4.1", From 1ba4ca9fd85a02ae83d0b22be3c13b2c2b4f3e2b Mon Sep 17 00:00:00 2001 From: Beniamin Malinski Date: Tue, 14 Jul 2026 16:13:13 +0200 Subject: [PATCH 2/2] perf(console-ui): tune tanstack router integration Co-Authored-By: OpenAI Codex --- frontend/rsbuild.config.ts | 24 +++++++++----- frontend/src/app.tsx | 2 ++ .../components/routes/route-pending.test.tsx | 22 +++++++++++++ .../src/components/routes/route-pending.tsx | 4 +-- frontend/src/embedded-app.tsx | 2 ++ frontend/src/router-defaults.test.ts | 25 ++++++++++++++ frontend/src/router-defaults.ts | 20 +++++++++++ frontend/src/tanstack-router-config.test.ts | 33 +++++++++++++++++++ frontend/tanstack-router.config.ts | 25 ++++++++++++++ frontend/vitest.config.integration.mts | 10 ++---- 10 files changed, 148 insertions(+), 19 deletions(-) create mode 100644 frontend/src/components/routes/route-pending.test.tsx create mode 100644 frontend/src/router-defaults.test.ts create mode 100644 frontend/src/router-defaults.ts create mode 100644 frontend/src/tanstack-router-config.test.ts create mode 100644 frontend/tanstack-router.config.ts diff --git a/frontend/rsbuild.config.ts b/frontend/rsbuild.config.ts index d1a95ba02c..12550f05c2 100644 --- a/frontend/rsbuild.config.ts +++ b/frontend/rsbuild.config.ts @@ -8,12 +8,13 @@ import { pluginSvgr } from '@rsbuild/plugin-svgr'; import { pluginTailwindcss } from '@rsbuild/plugin-tailwindcss'; import { pluginYaml } from '@rsbuild/plugin-yaml'; import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin'; -import { TanStackRouterRspack } from '@tanstack/router-plugin/rspack'; +import { tanstackRouter } from '@tanstack/router-plugin/rspack'; import MonacoWebpackPlugin from 'monaco-editor-webpack-plugin'; import { moduleFederationConfig } from './module-federation.config'; import { HEAP_APP_ID } from './src/heap/heap.helper'; import { HUBSPOT_PORTAL_ID } from './src/hubspot/hubspot.helper'; +import { TANSTACK_CHUNK_PATTERN, tanstackRouterConfig } from './tanstack-router.config'; import path from 'node:path'; const { publicVars, rawPublicVars } = loadEnv({ prefixes: ['REACT_APP_'] }); @@ -143,6 +144,18 @@ export default defineConfig({ // production diagnostics. removeConsole: ['log', 'warn'], }, + splitChunks: { + preset: 'default', + cacheGroups: { + tanstack: { + test: TANSTACK_CHUNK_PATTERN, + name: 'lib-tanstack', + chunks: 'all', + priority: 10, + reuseExistingChunk: true, + }, + }, + }, output: { distPath: { root: 'build', @@ -192,14 +205,7 @@ export default defineConfig({ }; const plugins = [ - TanStackRouterRspack({ - target: 'react', - autoCodeSplitting: true, - routesDirectory: './src/routes', - generatedRouteTree: './src/routeTree.gen.ts', - quoteStyle: 'single', - semicolons: true, - }), + tanstackRouter(tanstackRouterConfig), new MonacoWebpackPlugin({ languages: ['yaml', 'json', 'typescript', 'javascript', 'protobuf'], customLanguages: [ diff --git a/frontend/src/app.tsx b/frontend/src/app.tsx index c3d956ec64..edace18cbf 100644 --- a/frontend/src/app.tsx +++ b/frontend/src/app.tsx @@ -52,6 +52,7 @@ import { patchedRedpandaTheme as redpandaTheme } from 'utils/redpanda-theme'; import { applyOverrides as applyDebugFeatureFlagOverrides } from './components/debug-helper/feature-flag-overrides'; import { NotFoundPage } from './components/misc/not-found-page'; import { addBearerTokenInterceptor, checkExpiredLicenseInterceptor, getGrpcBasePath, setup } from './config'; +import { routerDefaults } from './router-defaults'; import { routeTree } from './routeTree.gen'; import { installUISettingsSideEffects } from './state/ui'; @@ -67,6 +68,7 @@ const dataplaneTransport = createConnectTransport({ // Create router instance const router = createRouter({ routeTree, + ...routerDefaults, context: { basePath: getBasePath(), queryClient, diff --git a/frontend/src/components/routes/route-pending.test.tsx b/frontend/src/components/routes/route-pending.test.tsx new file mode 100644 index 0000000000..fa20f9b4fa --- /dev/null +++ b/frontend/src/components/routes/route-pending.test.tsx @@ -0,0 +1,22 @@ +/** + * Copyright 2026 Redpanda Data, Inc. + * + * Use of this software is governed by the Business Source License + * included in the file https://github.com/redpanda-data/redpanda/blob/dev/licenses/bsl.md + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0 + */ + +import { render, screen } from '@testing-library/react'; + +import { RoutePending } from './route-pending'; + +describe('RoutePending', () => { + it('announces route loading', () => { + render(); + + expect(screen.getByRole('status', { name: 'Loading page' })).toBeVisible(); + }); +}); diff --git a/frontend/src/components/routes/route-pending.tsx b/frontend/src/components/routes/route-pending.tsx index f8c0dcc7dc..d49bd2db1f 100644 --- a/frontend/src/components/routes/route-pending.tsx +++ b/frontend/src/components/routes/route-pending.tsx @@ -17,9 +17,9 @@ import { LoaderIcon } from 'components/icons'; */ export const RoutePending = () => (
-
+ Loading... -
+
); diff --git a/frontend/src/embedded-app.tsx b/frontend/src/embedded-app.tsx index 0c13b67fe1..bc240ed94f 100644 --- a/frontend/src/embedded-app.tsx +++ b/frontend/src/embedded-app.tsx @@ -51,6 +51,7 @@ import { type SetConfigArguments, setup, } from './config'; +import { routerDefaults } from './router-defaults'; import { routeTree } from './routeTree.gen'; import { appGlobal } from './state/app-global'; import { installUISettingsSideEffects } from './state/ui'; @@ -137,6 +138,7 @@ function EmbeddedApp({ basePath = '', ...p }: EmbeddedProps) { () => createRouter({ routeTree, + ...routerDefaults, context: { basePath, queryClient, diff --git a/frontend/src/router-defaults.test.ts b/frontend/src/router-defaults.test.ts new file mode 100644 index 0000000000..114187bcc9 --- /dev/null +++ b/frontend/src/router-defaults.test.ts @@ -0,0 +1,25 @@ +/** + * Copyright 2026 Redpanda Data, Inc. + * + * Use of this software is governed by the Business Source License + * included in the file https://github.com/redpanda-data/redpanda/blob/dev/licenses/bsl.md + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0 + */ + +import { RouteError } from './components/routes/route-error'; +import { RoutePending } from './components/routes/route-pending'; +import { routerDefaults } from './router-defaults'; + +describe('routerDefaults', () => { + it('preloads on intent while TanStack Query owns caching and route boundaries', () => { + expect(routerDefaults).toEqual({ + defaultErrorComponent: RouteError, + defaultPendingComponent: RoutePending, + defaultPreload: 'intent', + defaultPreloadStaleTime: 0, + }); + }); +}); diff --git a/frontend/src/router-defaults.ts b/frontend/src/router-defaults.ts new file mode 100644 index 0000000000..e9525e0965 --- /dev/null +++ b/frontend/src/router-defaults.ts @@ -0,0 +1,20 @@ +/** + * Copyright 2026 Redpanda Data, Inc. + * + * Use of this software is governed by the Business Source License + * included in the file https://github.com/redpanda-data/redpanda/blob/dev/licenses/bsl.md + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0 + */ + +import { RouteError } from './components/routes/route-error'; +import { RoutePending } from './components/routes/route-pending'; + +export const routerDefaults = { + defaultPreload: 'intent', + defaultPreloadStaleTime: 0, + defaultPendingComponent: RoutePending, + defaultErrorComponent: RouteError, +} as const; diff --git a/frontend/src/tanstack-router-config.test.ts b/frontend/src/tanstack-router-config.test.ts new file mode 100644 index 0000000000..6cddbf0548 --- /dev/null +++ b/frontend/src/tanstack-router-config.test.ts @@ -0,0 +1,33 @@ +/** + * Copyright 2026 Redpanda Data, Inc. + * + * Use of this software is governed by the Business Source License + * included in the file https://github.com/redpanda-data/redpanda/blob/dev/licenses/bsl.md + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0 + */ + +import { TANSTACK_CHUNK_PATTERN, tanstackRouterConfig } from '../tanstack-router.config'; + +describe('tanstackRouterConfig', () => { + it('configures file-based React routes with automatic code splitting', () => { + expect(tanstackRouterConfig).toMatchObject({ + autoCodeSplitting: true, + generatedRouteTree: './src/routeTree.gen.ts', + quoteStyle: 'single', + routeFileIgnorePattern: String.raw`\.(?:test|spec)\.[cm]?[jt]sx?$`, + routeFileIgnorePrefix: '-', + routesDirectory: './src/routes', + semicolons: true, + target: 'react', + }); + }); + + it('matches TanStack packages across operating systems', () => { + expect(TANSTACK_CHUNK_PATTERN.test('/app/node_modules/@tanstack/react-router/dist/index.js')).toBe(true); + expect(TANSTACK_CHUNK_PATTERN.test(String.raw`C:\app\node_modules\@tanstack\react-query\dist\index.js`)).toBe(true); + expect(TANSTACK_CHUNK_PATTERN.test('/app/node_modules/@redpanda-data/ui/dist/index.js')).toBe(false); + }); +}); diff --git a/frontend/tanstack-router.config.ts b/frontend/tanstack-router.config.ts new file mode 100644 index 0000000000..6ded78e358 --- /dev/null +++ b/frontend/tanstack-router.config.ts @@ -0,0 +1,25 @@ +/** + * Copyright 2026 Redpanda Data, Inc. + * + * Use of this software is governed by the Business Source License + * included in the file https://github.com/redpanda-data/redpanda/blob/dev/licenses/bsl.md + * + * As of the Change Date specified in that file, in accordance with + * the Business Source License, use of this software will be governed + * by the Apache License, Version 2.0 + */ + +import type { Config } from '@tanstack/router-plugin/rspack'; + +export const TANSTACK_CHUNK_PATTERN = /[\\/]node_modules[\\/]@tanstack[\\/]/; + +export const tanstackRouterConfig = { + target: 'react', + autoCodeSplitting: true, + routesDirectory: './src/routes', + generatedRouteTree: './src/routeTree.gen.ts', + routeFileIgnorePrefix: '-', + routeFileIgnorePattern: String.raw`\.(?:test|spec)\.[cm]?[jt]sx?$`, + quoteStyle: 'single', + semicolons: true, +} satisfies Partial; diff --git a/frontend/vitest.config.integration.mts b/frontend/vitest.config.integration.mts index 9c4b114901..6e0369bf41 100644 --- a/frontend/vitest.config.integration.mts +++ b/frontend/vitest.config.integration.mts @@ -6,6 +6,7 @@ import envCompatible from 'vite-plugin-env-compatible'; import tsconfigPaths from 'vite-tsconfig-paths'; import { defineConfig } from 'vitest/config'; +import { tanstackRouterConfig } from './tanstack-router.config'; import { sharedAliases } from './vitest.shared.mts'; const ENV_PREFIX = 'REACT_APP_'; @@ -80,14 +81,7 @@ export default defineConfig(({ mode }) => { }, }, plugins: [ - tanstackRouter({ - target: 'react', - autoCodeSplitting: true, - routesDirectory: './src/routes', - generatedRouteTree: './src/routeTree.gen.ts', - quoteStyle: 'single', - semicolons: true, - }), + tanstackRouter(tanstackRouterConfig), react(), envCompatible({ prefix: ENV_PREFIX }), tsconfigPaths({