From aae22cf30e7c39d14d6f1e5a736cc78e2e84a405 Mon Sep 17 00:00:00 2001 From: Elecmonkey Date: Sat, 9 May 2026 18:02:50 +0800 Subject: [PATCH 1/8] refactor: unify Rsbuild server middleware and support ssr-middleware run in preview mode --- e2e/react-start/basic/package.json | 5 + e2e/react-start/basic/playwright.config.ts | 8 +- .../custom-server-rsbuild/rsbuild.config.ts | 2 +- packages/react-start/src/plugin/rsbuild.ts | 13 + .../src/rsbuild/dev-server.ts | 129 ---------- .../start-plugin-core/src/rsbuild/plugin.ts | 11 +- .../start-plugin-core/src/rsbuild/schema.ts | 2 +- .../src/rsbuild/server-middleware.ts | 237 ++++++++++++++++++ 8 files changed, 272 insertions(+), 135 deletions(-) delete mode 100644 packages/start-plugin-core/src/rsbuild/dev-server.ts create mode 100644 packages/start-plugin-core/src/rsbuild/server-middleware.ts diff --git a/e2e/react-start/basic/package.json b/e2e/react-start/basic/package.json index caf0c16cbc..442e8df8b8 100644 --- a/e2e/react-start/basic/package.json +++ b/e2e/react-start/basic/package.json @@ -12,6 +12,7 @@ "build:vite": "vite build && tsc --noEmit", "build:rsbuild": "rsbuild build && tsc --noEmit", "preview": "vite preview", + "preview:rsbuild": "rsbuild preview", "start": "node server.js", "test:e2e:startDummyServer": "node -e 'import(\"./tests/setup/global.setup.ts\").then(m => m.default())' & node -e 'import(\"./tests/setup/waitForDummyServer.ts\").then(m => m.default())'", "test:e2e:stopDummyServer": "node -e 'import(\"./tests/setup/global.teardown.ts\").then(m => m.default())'", @@ -78,6 +79,10 @@ { "toolchain": "rsbuild", "mode": "prerender" + }, + { + "toolchain": "rsbuild", + "mode": "preview" } ] } diff --git a/e2e/react-start/basic/playwright.config.ts b/e2e/react-start/basic/playwright.config.ts index 5e46a2b1c7..bd22024073 100644 --- a/e2e/react-start/basic/playwright.config.ts +++ b/e2e/react-start/basic/playwright.config.ts @@ -7,6 +7,7 @@ import { import packageJson from './package.json' with { type: 'json' } const mode = process.env.MODE ?? 'ssr' +const toolchain = process.env.E2E_TOOLCHAIN ?? 'vite' const e2ePortKey = process.env.E2E_PORT_KEY ?? packageJson.name const distDir = process.env.E2E_DIST_DIR ?? 'dist' @@ -24,9 +25,13 @@ const PORT = await getTestServerPort(e2ePortKey) const START_PORT = await getTestServerPort(`${e2ePortKey}_start`) const EXTERNAL_PORT = await getDummyServerPort(e2ePortKey) const baseURL = `http://localhost:${PORT}` +const previewCommand = + toolchain === 'rsbuild' + ? `pnpm preview:rsbuild --port ${PORT}` + : `pnpm preview --outDir ${distDir} --port ${PORT}` const commandByMode = mode === 'preview' - ? `pnpm run test:e2e:startDummyServer && pnpm preview --outDir ${distDir} --port ${PORT}` + ? `pnpm run test:e2e:startDummyServer && ${previewCommand}` : `pnpm run test:e2e:startDummyServer && pnpm start` /** * See https://playwright.dev/docs/test-configuration. @@ -50,6 +55,7 @@ export default defineConfig({ stdout: 'pipe', env: { MODE: mode, + E2E_TOOLCHAIN: toolchain, VITE_NODE_ENV: 'test', VITE_EXTERNAL_PORT: String(EXTERNAL_PORT), VITE_SERVER_PORT: String(PORT), diff --git a/e2e/react-start/custom-server-rsbuild/rsbuild.config.ts b/e2e/react-start/custom-server-rsbuild/rsbuild.config.ts index e638f8319c..2b7450b33c 100644 --- a/e2e/react-start/custom-server-rsbuild/rsbuild.config.ts +++ b/e2e/react-start/custom-server-rsbuild/rsbuild.config.ts @@ -5,6 +5,6 @@ import { tanstackStart } from '@tanstack/react-start/plugin/rsbuild' export default defineConfig({ plugins: [ pluginReact({ splitChunks: false }), - tanstackStart({ rsbuild: { installDevServerMiddleware: false } }), + tanstackStart({ rsbuild: { installServerMiddleware: false } }), ], }) diff --git a/packages/react-start/src/plugin/rsbuild.ts b/packages/react-start/src/plugin/rsbuild.ts index 7e0fcbb6c2..bd159690f1 100644 --- a/packages/react-start/src/plugin/rsbuild.ts +++ b/packages/react-start/src/plugin/rsbuild.ts @@ -10,6 +10,16 @@ import type { } from '@tanstack/start-plugin-core/rsbuild' import type { RsbuildPlugin } from '@rsbuild/core' +const reactStartRsbuildEnvironmentOverrides = { + all: { + resolve: { + dedupe: ['react', 'react-dom'], + }, + }, +} satisfies NonNullable< + TanStackStartRsbuildPluginCoreOptions['rsbuild'] +>['environments'] + export function tanstackStart( options?: TanStackStartRsbuildInputConfig & { rsc?: { enabled?: boolean } }, ): RsbuildPlugin { @@ -20,6 +30,9 @@ export function tanstackStart( defaultEntryPaths: reactStartDefaultEntryPaths, providerEnvironmentName: RSBUILD_ENVIRONMENT_NAMES.server, ssrIsProvider: true, + rsbuild: { + environments: reactStartRsbuildEnvironmentOverrides, + }, } if (rscEnabled) { diff --git a/packages/start-plugin-core/src/rsbuild/dev-server.ts b/packages/start-plugin-core/src/rsbuild/dev-server.ts deleted file mode 100644 index c83ec71448..0000000000 --- a/packages/start-plugin-core/src/rsbuild/dev-server.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { NodeRequest, sendNodeResponse } from 'srvx/node' -import { RSBUILD_ENVIRONMENT_NAMES } from './planning' -import type { IncomingMessage, ServerResponse } from 'node:http' -import type { RsbuildConfig } from '@rsbuild/core' - -type ServerSetupFn = Extract< - NonNullable['setup']>, - (...args: Array) => any -> -type SSRMiddleware = ( - req: IncomingMessage & { originalUrl?: string }, - res: ServerResponse, - next: () => void, -) => Promise - -/** - * Returns a `server.setup` function for rsbuild v2. - * - * Two middleware positions are used: - * - * 1. **Setup body** (BEFORE built-ins): Intercepts `/_serverFn/` URLs so - * they never reach rsbuild's htmlFallback/htmlCompletion middleware, - * which can swallow long base64 function IDs. - * - * 2. **Returned callback** (AFTER built-ins, BEFORE fallback): Handles - * all remaining SSR requests (page navigations). This position lets - * rsbuild's asset middleware serve compiled JS/CSS first. - * - * See rsbuild source: devMiddlewares.ts `applyDefaultMiddlewares()`. - */ -export function createServerSetup(opts: { - serverFnBasePath: string -}): ServerSetupFn { - return (context) => { - // Only install SSR middleware in dev mode - if (context.action !== 'dev') { - return () => {} - } - - const serverFnBase = opts.serverFnBasePath - - const handleSSR: SSRMiddleware = async (req, res, next) => { - const ssrEnv = - context.server.environments[RSBUILD_ENVIRONMENT_NAMES.server] - - if (!ssrEnv) { - console.error( - `[tanstack-start] SSR environment "${RSBUILD_ENVIRONMENT_NAMES.server}" not found`, - ) - return next() - } - - try { - const serverEntry = await ssrEnv.loadBundle<{ - default: { fetch: (req: Request) => Promise } - }>('index') - - // Restore the original URL (rsbuild may rewrite to /index.html) - if (req.originalUrl) { - req.url = req.originalUrl - } - - const webReq = new NodeRequest({ req, res }) - const webRes = await serverEntry.default.fetch(webReq) - return sendNodeResponse(res, webRes) - } catch (e) { - console.error('[tanstack-start] SSR error:', e) - - const webReq = new NodeRequest({ req, res }) - if (webReq.headers.get('content-type')?.includes('application/json')) { - return sendNodeResponse( - res, - new Response( - JSON.stringify( - { - status: 500, - error: 'Internal Server Error', - message: - 'An unexpected error occurred. Please try again later.', - timestamp: new Date().toISOString(), - }, - null, - 2, - ), - { - status: 500, - headers: { 'Content-Type': 'application/json' }, - }, - ), - ) - } - - return sendNodeResponse( - res, - new Response( - ` - - Error - -

Internal Server Error

-
${e instanceof Error ? e.message : String(e)}
- -`, - { - status: 500, - headers: { 'Content-Type': 'text/html' }, - }, - ), - ) - } - } - - // Position 1: BEFORE built-ins — intercept server function calls - // early so they are not swallowed by htmlFallback or assetsMiddleware. - context.server.middlewares.use(async (req, res, next) => { - const url = req.url || '/' - if (url.startsWith(serverFnBase)) { - return handleSSR(req, res, next) - } - return next() - }) - - // Position 2: AFTER built-ins, before fallback — SSR catch-all for - // page navigations. Assets are already handled by rsbuild middleware. - return () => { - context.server.middlewares.use(handleSSR) - } - } -} diff --git a/packages/start-plugin-core/src/rsbuild/plugin.ts b/packages/start-plugin-core/src/rsbuild/plugin.ts index 337cdd55c4..03c5027576 100644 --- a/packages/start-plugin-core/src/rsbuild/plugin.ts +++ b/packages/start-plugin-core/src/rsbuild/plugin.ts @@ -24,7 +24,7 @@ import { START_MANIFEST_PLACEHOLDER, registerVirtualModules, } from './virtual-modules' -import { createServerSetup } from './dev-server' +import { createServerSetup } from './server-middleware' import { registerClientBuildCapture } from './normalized-client-build' import { registerRouterPlugins } from './start-router-plugin' import { postBuildWithRsbuild } from './post-build' @@ -142,6 +142,8 @@ export function tanStackStartRsbuild( const resolvedEntryPlan = configContext.resolveEntries() const isDev = api.context.action === 'dev' + const isPreview = api.context.action === 'preview' + const shouldInstallServerMiddleware = isDev || isPreview const entryAliases = createRsbuildResolvedEntryAliases({ entryPaths: resolvedEntryPlan.entryPaths, @@ -207,11 +209,14 @@ export function tanStackStartRsbuild( htmlFallback: false, // server.setup returned callback runs after built-in middleware // but BEFORE fallback middleware — the ideal slot for SSR. - ...(isDev && - startPluginOpts.rsbuild?.installDevServerMiddleware !== false + ...(shouldInstallServerMiddleware && + startPluginOpts.rsbuild?.installServerMiddleware !== false ? { setup: createServerSetup({ serverFnBasePath: serverFnBase, + serverOutputDirectory: + resolvedStartConfig.outputDirectories.server, + publicBase: resolvedStartConfig.basePaths.publicBase, }), } : {}), diff --git a/packages/start-plugin-core/src/rsbuild/schema.ts b/packages/start-plugin-core/src/rsbuild/schema.ts index 9c0c0cbef7..3f5911d70c 100644 --- a/packages/start-plugin-core/src/rsbuild/schema.ts +++ b/packages/start-plugin-core/src/rsbuild/schema.ts @@ -9,7 +9,7 @@ export const tanstackStartRsbuildOptionsSchema = tanstackStartOptionsObjectSchema .extend({ rsbuild: z - .object({ installDevServerMiddleware: z.boolean().optional() }) + .object({ installServerMiddleware: z.boolean().optional() }) .optional(), }) .optional() diff --git a/packages/start-plugin-core/src/rsbuild/server-middleware.ts b/packages/start-plugin-core/src/rsbuild/server-middleware.ts new file mode 100644 index 0000000000..08011d9974 --- /dev/null +++ b/packages/start-plugin-core/src/rsbuild/server-middleware.ts @@ -0,0 +1,237 @@ +import { resolve } from 'node:path' +import { pathToFileURL } from 'node:url' +import { NodeRequest, sendNodeResponse } from 'srvx/node' +import { joinURL } from 'ufo' +import { RSBUILD_ENVIRONMENT_NAMES } from './planning' +import type { IncomingMessage, ServerResponse } from 'node:http' +import type { RsbuildConfig } from '@rsbuild/core' + +type ServerSetupFn = Extract< + NonNullable['setup']>, + (...args: Array) => any +> +type ServerSetupContext = Parameters[0] +type SSRMiddleware = ( + req: IncomingMessage & { originalUrl?: string }, + res: ServerResponse, + next: (error?: unknown) => void, +) => Promise +type FetchHandler = (req: Request) => Promise | Response + +type ServerEntry = + | FetchHandler + | { + fetch?: FetchHandler + } + +function resolveFetchHandler(serverEntry: ServerEntry): FetchHandler { + if (typeof serverEntry === 'function') { + return serverEntry + } + + if (serverEntry && typeof serverEntry.fetch === 'function') { + return serverEntry.fetch.bind(serverEntry) + } + + throw new Error( + 'Unable to resolve a request handler from Rsbuild server bundle', + ) +} + +function getPublicBasePathname(publicBase: string): string { + try { + return new URL(publicBase, 'http://localhost').pathname + } catch { + return publicBase + } +} + +function restorePreviewUrl(opts: { + req: IncomingMessage & { originalUrl?: string } + publicBase: string +}) { + if (opts.req.originalUrl) { + opts.req.url = opts.req.originalUrl + } + + const publicBasePathname = getPublicBasePathname(opts.publicBase) + if (publicBasePathname === '/') { + return + } + + const url = opts.req.url ?? '/' + if (url.startsWith(publicBasePathname)) { + return + } + + opts.req.url = joinURL(publicBasePathname, url) +} + +async function loadDevFetchHandler( + context: ServerSetupContext, +): Promise { + if (context.action !== 'dev') { + throw new Error('Cannot load Rsbuild dev SSR bundle outside dev mode') + } + + const ssrEnv = context.server.environments[RSBUILD_ENVIRONMENT_NAMES.server] + + if (!ssrEnv) { + throw new Error( + `SSR environment "${RSBUILD_ENVIRONMENT_NAMES.server}" not found`, + ) + } + + const serverEntry = await ssrEnv.loadBundle<{ default: ServerEntry }>('index') + return resolveFetchHandler(serverEntry.default) +} + +/** + * Returns a `server.setup` function for rsbuild v2. + * + * Two middleware positions are used: + * + * 1. **Setup body** (BEFORE built-ins): Intercepts `/_serverFn/` URLs so + * they never reach rsbuild's htmlFallback/htmlCompletion middleware, + * which can swallow long base64 function IDs. + * + * 2. **Returned callback** (AFTER built-ins, BEFORE fallback): Handles + * all remaining SSR requests (page navigations). This position lets + * rsbuild's asset middleware serve compiled JS/CSS first. + * + * The middleware choreography is shared by dev and preview. The server entry + * loader differs: dev reads from Rsbuild's in-memory environment so rebuilds + * are reflected immediately, while preview lazy-imports the production server + * bundle from disk. + * + * See rsbuild source: devMiddlewares.ts `applyDefaultMiddlewares()` and + * previewServer.ts `startPreviewServer()`. + */ +export function createServerSetup(opts: { + serverFnBasePath: string + serverOutputDirectory: string + publicBase: string +}): ServerSetupFn { + let previewFetchHandlerPromise: Promise | undefined + + const getPreviewFetchHandler = () => { + if (!previewFetchHandlerPromise) { + previewFetchHandlerPromise = loadPreviewFetchHandler( + opts.serverOutputDirectory, + ) + } + + return previewFetchHandlerPromise + } + + return (context) => { + if (context.action !== 'dev' && context.action !== 'preview') { + return () => {} + } + + const serverFnBase = opts.serverFnBasePath + + const handleSSR: SSRMiddleware = async (req, res, next) => { + try { + const fetchHandler = + context.action === 'dev' + ? await loadDevFetchHandler(context) + : await getPreviewFetchHandler() + + if (context.action === 'preview') { + // Rsbuild preview's base middleware strips server.base before the + // returned setup callback runs. Put it back before creating the Web + // Request so Start's router sees the same URL shape as build/custom + // servers. The early server-fn middleware runs before that base + // middleware, so avoid prepending when the URL already has the base. + restorePreviewUrl({ req, publicBase: opts.publicBase }) + } else if (req.originalUrl) { + // Restore the original URL (rsbuild may rewrite to /index.html) + req.url = req.originalUrl + } + + const webReq = new NodeRequest({ req, res }) + const webRes = await fetchHandler(webReq) + return sendNodeResponse(res, webRes) + } catch (e) { + console.error('[tanstack-start] SSR error:', e) + + const webReq = new NodeRequest({ req, res }) + if (webReq.headers.get('content-type')?.includes('application/json')) { + return sendNodeResponse( + res, + new Response( + JSON.stringify( + { + status: 500, + error: 'Internal Server Error', + message: + 'An unexpected error occurred. Please try again later.', + timestamp: new Date().toISOString(), + }, + null, + 2, + ), + { + status: 500, + headers: { 'Content-Type': 'application/json' }, + }, + ), + ) + } + + return sendNodeResponse( + res, + new Response( + ` + + Error + +

Internal Server Error

+
${e instanceof Error ? e.message : String(e)}
+ +`, + { + status: 500, + headers: { 'Content-Type': 'text/html' }, + }, + ), + ) + } + } + + // Position 1: BEFORE built-ins — intercept server function calls + // early so they are not swallowed by htmlFallback or assetsMiddleware. + context.server.middlewares.use(async (req, res, next) => { + const url = req.url || '/' + if (url.startsWith(serverFnBase)) { + return handleSSR(req, res, next) + } + return next() + }) + + // Position 2: AFTER built-ins, before fallback — SSR catch-all for + // page navigations. Assets are already handled by rsbuild middleware. + return () => { + context.server.middlewares.use(handleSSR) + } + } +} + +async function loadPreviewFetchHandler( + serverOutputDirectory: string, +): Promise { + const serverEntryPath = resolve(serverOutputDirectory, 'index.js') + const imported = (await import( + pathToFileURL(serverEntryPath).toString() + )) as { default: ServerEntry } + + try { + return resolveFetchHandler(imported.default) + } catch (error) { + throw new Error( + `Unable to resolve a request handler from Rsbuild server bundle at ${serverEntryPath}`, + { cause: error }, + ) + } +} From e4d0a4e49c405f856eef9c7b5c0922276265bb84 Mon Sep 17 00:00:00 2001 From: Elecmonkey Date: Sat, 9 May 2026 18:23:25 +0800 Subject: [PATCH 2/8] fix: ensure Rsbuild preview prints server URLs --- packages/start-plugin-core/src/rsbuild/plugin.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/start-plugin-core/src/rsbuild/plugin.ts b/packages/start-plugin-core/src/rsbuild/plugin.ts index 03c5027576..12b6a32f93 100644 --- a/packages/start-plugin-core/src/rsbuild/plugin.ts +++ b/packages/start-plugin-core/src/rsbuild/plugin.ts @@ -201,6 +201,10 @@ export function tanStackStartRsbuild( }, }, server: { + ...(rsbuildConfig.server?.printUrls === undefined || + rsbuildConfig.server.printUrls === true + ? { printUrls: ({ urls }: { urls: Array }) => urls } + : {}), // Rsbuild compression currently treats Node's raw header array // writeHead form as an object, which corrupts SSR response headers. compress: false, From 6ed106e1bb869371f4c8242793a24296d1adbb5b Mon Sep 17 00:00:00 2001 From: Elecmonkey Date: Mon, 25 May 2026 09:54:48 +0800 Subject: [PATCH 3/8] chore: add changeset for rsbuild preview --- .changeset/quiet-rsbuild-preview.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changeset/quiet-rsbuild-preview.md diff --git a/.changeset/quiet-rsbuild-preview.md b/.changeset/quiet-rsbuild-preview.md new file mode 100644 index 0000000000..8c2bcebeb9 --- /dev/null +++ b/.changeset/quiet-rsbuild-preview.md @@ -0,0 +1,8 @@ +--- +'@tanstack/start-plugin-core': patch +'@tanstack/react-start': patch +--- + +Fix Rsbuild preview support for TanStack Start SSR and rename the middleware option to `installServerMiddleware`. + +Deduplicate `react` and `react-dom` in the React Start Rsbuild integration. From 947911faeed835631a0a24ead0bc45a367ab9a0e Mon Sep 17 00:00:00 2001 From: Elecmonkey Date: Mon, 25 May 2026 10:00:11 +0800 Subject: [PATCH 4/8] fix(start-plugin-core): drop dead branches in rsbuild server middleware --- .../start-plugin-core/src/rsbuild/server-middleware.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/start-plugin-core/src/rsbuild/server-middleware.ts b/packages/start-plugin-core/src/rsbuild/server-middleware.ts index 08011d9974..80212d2ed0 100644 --- a/packages/start-plugin-core/src/rsbuild/server-middleware.ts +++ b/packages/start-plugin-core/src/rsbuild/server-middleware.ts @@ -29,7 +29,7 @@ function resolveFetchHandler(serverEntry: ServerEntry): FetchHandler { return serverEntry } - if (serverEntry && typeof serverEntry.fetch === 'function') { + if (typeof serverEntry.fetch === 'function') { return serverEntry.fetch.bind(serverEntry) } @@ -125,13 +125,9 @@ export function createServerSetup(opts: { } return (context) => { - if (context.action !== 'dev' && context.action !== 'preview') { - return () => {} - } - const serverFnBase = opts.serverFnBasePath - const handleSSR: SSRMiddleware = async (req, res, next) => { + const handleSSR: SSRMiddleware = async (req, res, _next) => { try { const fetchHandler = context.action === 'dev' From 6299e0c6b43a2aae3d45c467996f37722427c625 Mon Sep 17 00:00:00 2001 From: Elecmonkey Date: Mon, 25 May 2026 10:37:10 +0800 Subject: [PATCH 5/8] fix(start-plugin-core): defer rsbuild SSR errors to next() instead of inventing 500 HTML --- .../src/rsbuild/server-middleware.ts | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/packages/start-plugin-core/src/rsbuild/server-middleware.ts b/packages/start-plugin-core/src/rsbuild/server-middleware.ts index 80212d2ed0..70e2f234ce 100644 --- a/packages/start-plugin-core/src/rsbuild/server-middleware.ts +++ b/packages/start-plugin-core/src/rsbuild/server-middleware.ts @@ -127,7 +127,7 @@ export function createServerSetup(opts: { return (context) => { const serverFnBase = opts.serverFnBasePath - const handleSSR: SSRMiddleware = async (req, res, _next) => { + const handleSSR: SSRMiddleware = async (req, res, next) => { try { const fetchHandler = context.action === 'dev' @@ -176,23 +176,7 @@ export function createServerSetup(opts: { ) } - return sendNodeResponse( - res, - new Response( - ` - - Error - -

Internal Server Error

-
${e instanceof Error ? e.message : String(e)}
- -`, - { - status: 500, - headers: { 'Content-Type': 'text/html' }, - }, - ), - ) + return next(e) } } From 0b3d961a0ffc17e55b0886d6187cb9263a38b932 Mon Sep 17 00:00:00 2001 From: Elecmonkey Date: Mon, 25 May 2026 10:54:24 +0800 Subject: [PATCH 6/8] fix(start-plugin-core): serve client assets from client distPath in rsbuild preview --- .../start-plugin-core/src/rsbuild/plugin.ts | 2 + .../src/rsbuild/server-middleware.ts | 121 +++++++++++++++++- 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/packages/start-plugin-core/src/rsbuild/plugin.ts b/packages/start-plugin-core/src/rsbuild/plugin.ts index f571bdb988..fe00c056c7 100644 --- a/packages/start-plugin-core/src/rsbuild/plugin.ts +++ b/packages/start-plugin-core/src/rsbuild/plugin.ts @@ -247,6 +247,8 @@ export function tanStackStartRsbuild( ? { setup: createServerSetup({ serverFnBasePath: serverFnBase, + clientOutputDirectory: + resolvedStartConfig.outputDirectories.client, serverOutputDirectory: resolvedStartConfig.outputDirectories.server, publicBase: resolvedStartConfig.basePaths.publicBase, diff --git a/packages/start-plugin-core/src/rsbuild/server-middleware.ts b/packages/start-plugin-core/src/rsbuild/server-middleware.ts index 70e2f234ce..19e1dcd240 100644 --- a/packages/start-plugin-core/src/rsbuild/server-middleware.ts +++ b/packages/start-plugin-core/src/rsbuild/server-middleware.ts @@ -1,4 +1,5 @@ -import { resolve } from 'node:path' +import { createReadStream, statSync } from 'node:fs' +import { extname, join, normalize, resolve, sep } from 'node:path' import { pathToFileURL } from 'node:url' import { NodeRequest, sendNodeResponse } from 'srvx/node' import { joinURL } from 'ufo' @@ -109,6 +110,7 @@ async function loadDevFetchHandler( */ export function createServerSetup(opts: { serverFnBasePath: string + clientOutputDirectory: string serverOutputDirectory: string publicBase: string }): ServerSetupFn { @@ -190,6 +192,29 @@ export function createServerSetup(opts: { return next() }) + // In preview mode, rsbuild's built-in `sirv` is rooted at + // `context.distPath`, which is the common parent of all environments' + // dist paths. With the SSR layout (`dist/client` + `dist/server`), that + // resolves to `dist/`, so requests for `/static/...` miss and fall + // through to the SSR catch-all returning HTML 404s. Mirror Vite's + // behaviour by serving client assets from the client environment's + // dist directory before our SSR catch-all takes over. + if (context.action === 'preview') { + const clientRoot = resolve(opts.clientOutputDirectory) + const publicBasePathname = getPublicBasePathname(opts.publicBase) + context.server.middlewares.use((req, res, next) => { + if (req.method !== 'GET' && req.method !== 'HEAD') return next() + const rawUrl = req.originalUrl ?? req.url ?? '/' + const filePath = resolveStaticAssetPath( + rawUrl, + publicBasePathname, + clientRoot, + ) + if (!filePath) return next() + return serveStaticFile(filePath, req, res, next) + }) + } + // Position 2: AFTER built-ins, before fallback — SSR catch-all for // page navigations. Assets are already handled by rsbuild middleware. return () => { @@ -198,6 +223,100 @@ export function createServerSetup(opts: { } } +const STATIC_ASSET_MIME: Record = { + '.js': 'application/javascript; charset=utf-8', + '.mjs': 'application/javascript; charset=utf-8', + '.cjs': 'application/javascript; charset=utf-8', + '.css': 'text/css; charset=utf-8', + '.html': 'text/html; charset=utf-8', + '.json': 'application/json; charset=utf-8', + '.map': 'application/json; charset=utf-8', + '.svg': 'image/svg+xml', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.gif': 'image/gif', + '.webp': 'image/webp', + '.avif': 'image/avif', + '.ico': 'image/x-icon', + '.woff': 'font/woff', + '.woff2': 'font/woff2', + '.ttf': 'font/ttf', + '.otf': 'font/otf', + '.txt': 'text/plain; charset=utf-8', + '.wasm': 'application/wasm', +} + +function resolveStaticAssetPath( + rawUrl: string, + publicBasePathname: string, + clientRoot: string, +): string | undefined { + let pathname: string + try { + pathname = new URL(rawUrl, 'http://localhost').pathname + } catch { + return undefined + } + + // Strip the public base so `//static/foo.js` and `/static/foo.js` + // both resolve to `/static/foo.js`. + if (publicBasePathname !== '/' && pathname.startsWith(publicBasePathname)) { + pathname = pathname.slice(publicBasePathname.length) || '/' + } + if (!pathname.startsWith('/')) pathname = `/${pathname}` + + // Decode and refuse traversal attempts. + let decoded: string + try { + decoded = decodeURIComponent(pathname) + } catch { + return undefined + } + if (decoded.includes('\0')) return undefined + + const filePath = normalize(join(clientRoot, decoded)) + if (filePath !== clientRoot && !filePath.startsWith(clientRoot + sep)) { + return undefined + } + + let stat + try { + stat = statSync(filePath) + } catch { + return undefined + } + if (!stat.isFile()) return undefined + + return filePath +} + +function serveStaticFile( + filePath: string, + req: IncomingMessage, + res: ServerResponse, + next: (error?: unknown) => void, +) { + const stat = statSync(filePath) + const mime = STATIC_ASSET_MIME[extname(filePath).toLowerCase()] + if (mime) res.setHeader('content-type', mime) + res.setHeader('content-length', stat.size) + + if (req.method === 'HEAD') { + res.statusCode = 200 + res.end() + return + } + + const stream = createReadStream(filePath) + stream.on('error', (err) => { + stream.destroy() + next(err) + }) + res.statusCode = 200 + stream.pipe(res) +} + async function loadPreviewFetchHandler( serverOutputDirectory: string, ): Promise { From fee9a0ba660d862ba07a1373439541c5051fd824 Mon Sep 17 00:00:00 2001 From: Elecmonkey Date: Wed, 3 Jun 2026 21:47:16 +0800 Subject: [PATCH 7/8] chore: bump rsbuild to 2.0.11 --- benchmarks/bundle-size/package.json | 2 +- .../rspack-basic-file-based/package.json | 2 +- .../package.json | 2 +- e2e/react-start/basic/package.json | 2 +- e2e/react-start/css-inline/package.json | 2 +- .../custom-server-rsbuild/package.json | 2 +- .../deferred-hydration/package.json | 2 +- e2e/react-start/hmr/package.json | 2 +- .../import-protection/package.json | 2 +- e2e/react-start/rsc/package.json | 2 +- e2e/react-start/server-functions/package.json | 2 +- .../rspack-basic-file-based/package.json | 2 +- .../package.json | 2 +- e2e/solid-start/basic/package.json | 2 +- .../deferred-hydration/package.json | 2 +- .../rspack-basic-file-based/package.json | 2 +- .../package.json | 2 +- e2e/vue-start/basic/package.json | 2 +- .../quickstart-rspack-file-based/package.json | 2 +- .../quickstart-rspack-file-based/package.json | 2 +- packages/react-start/package.json | 2 +- packages/solid-start/package.json | 2 +- packages/start-plugin-core/package.json | 2 +- packages/vue-start/package.json | 2 +- pnpm-lock.yaml | 389 +++++++----------- 25 files changed, 180 insertions(+), 257 deletions(-) diff --git a/benchmarks/bundle-size/package.json b/benchmarks/bundle-size/package.json index 333267480f..07c4730576 100644 --- a/benchmarks/bundle-size/package.json +++ b/benchmarks/bundle-size/package.json @@ -17,7 +17,7 @@ "vue": "^3.5.16" }, "devDependencies": { - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-react": "^2.0.0", "@tanstack/router-plugin": "workspace:^", "@types/react": "^19.0.8", diff --git a/e2e/react-router/rspack-basic-file-based/package.json b/e2e/react-router/rspack-basic-file-based/package.json index b19a27af6d..74659b51e1 100644 --- a/e2e/react-router/rspack-basic-file-based/package.json +++ b/e2e/react-router/rspack-basic-file-based/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-react": "^2.0.0", "@tailwindcss/postcss": "^4.2.2", "@tanstack/router-e2e-utils": "workspace:^", diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/package.json b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/package.json index 5609c6cef0..a7b9eb58d4 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/package.json +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-react": "^2.0.0", "@tailwindcss/postcss": "^4.2.2", "@tanstack/router-e2e-utils": "workspace:^", diff --git a/e2e/react-start/basic/package.json b/e2e/react-start/basic/package.json index 3be5d067d3..37a3f4a0e2 100644 --- a/e2e/react-start/basic/package.json +++ b/e2e/react-start/basic/package.json @@ -32,7 +32,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-react": "^2.0.0", "@tailwindcss/postcss": "^4.2.2", "@tailwindcss/vite": "^4.2.2", diff --git a/e2e/react-start/css-inline/package.json b/e2e/react-start/css-inline/package.json index e3e5d79678..a7bc5d023f 100644 --- a/e2e/react-start/css-inline/package.json +++ b/e2e/react-start/css-inline/package.json @@ -24,7 +24,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-react": "^2.0.0", "@tanstack/router-e2e-utils": "workspace:^", "@types/node": "^22.10.2", diff --git a/e2e/react-start/custom-server-rsbuild/package.json b/e2e/react-start/custom-server-rsbuild/package.json index 255b07edc6..75634f79f5 100644 --- a/e2e/react-start/custom-server-rsbuild/package.json +++ b/e2e/react-start/custom-server-rsbuild/package.json @@ -21,7 +21,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-react": "^2.0.0", "@tailwindcss/postcss": "^4.2.2", "@tanstack/router-e2e-utils": "workspace:^", diff --git a/e2e/react-start/deferred-hydration/package.json b/e2e/react-start/deferred-hydration/package.json index 9560a44c41..b225528b49 100644 --- a/e2e/react-start/deferred-hydration/package.json +++ b/e2e/react-start/deferred-hydration/package.json @@ -26,7 +26,7 @@ "react-dom": "^19.0.0" }, "devDependencies": { - "@rsbuild/core": "^2.0.1", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-react": "^2.0.0", "@tanstack/router-e2e-utils": "workspace:^", "@types/node": "^22.10.2", diff --git a/e2e/react-start/hmr/package.json b/e2e/react-start/hmr/package.json index 3854488170..b3a58125b9 100644 --- a/e2e/react-start/hmr/package.json +++ b/e2e/react-start/hmr/package.json @@ -21,7 +21,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-react": "^2.0.0", "@tailwindcss/postcss": "^4.2.2", "@tailwindcss/vite": "^4.2.2", diff --git a/e2e/react-start/import-protection/package.json b/e2e/react-start/import-protection/package.json index e4ad4a79ba..65ad70126b 100644 --- a/e2e/react-start/import-protection/package.json +++ b/e2e/react-start/import-protection/package.json @@ -25,7 +25,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-react": "^2.0.0", "@tanstack/router-e2e-utils": "workspace:^", "@types/node": "^22.10.2", diff --git a/e2e/react-start/rsc/package.json b/e2e/react-start/rsc/package.json index 7a499078d3..36f822e660 100644 --- a/e2e/react-start/rsc/package.json +++ b/e2e/react-start/rsc/package.json @@ -40,7 +40,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-react": "^2.0.0", "@tanstack/eslint-plugin-start": "workspace:^", "@tanstack/router-e2e-utils": "workspace:^", diff --git a/e2e/react-start/server-functions/package.json b/e2e/react-start/server-functions/package.json index 279883dbb4..5efdf6c42a 100644 --- a/e2e/react-start/server-functions/package.json +++ b/e2e/react-start/server-functions/package.json @@ -31,7 +31,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-react": "^2.0.0", "@tailwindcss/postcss": "^4.2.2", "@tailwindcss/vite": "^4.2.2", diff --git a/e2e/solid-router/rspack-basic-file-based/package.json b/e2e/solid-router/rspack-basic-file-based/package.json index 15e0106a68..5641433737 100644 --- a/e2e/solid-router/rspack-basic-file-based/package.json +++ b/e2e/solid-router/rspack-basic-file-based/package.json @@ -17,7 +17,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-babel": "^1.1.2", "@rsbuild/plugin-solid": "^1.1.1", "@tailwindcss/postcss": "^4.2.2", diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/package.json b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/package.json index 49f56c5c7a..f298b42ca6 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/package.json +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/package.json @@ -17,7 +17,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-babel": "^1.1.2", "@rsbuild/plugin-solid": "^1.1.1", "@tailwindcss/postcss": "^4.2.2", diff --git a/e2e/solid-start/basic/package.json b/e2e/solid-start/basic/package.json index 0210535500..1993225f61 100644 --- a/e2e/solid-start/basic/package.json +++ b/e2e/solid-start/basic/package.json @@ -27,7 +27,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-babel": "^1.1.2", "@rsbuild/plugin-solid": "^1.1.1", "@tailwindcss/postcss": "^4.2.2", diff --git a/e2e/solid-start/deferred-hydration/package.json b/e2e/solid-start/deferred-hydration/package.json index e7693d1f10..fd2b681ef1 100644 --- a/e2e/solid-start/deferred-hydration/package.json +++ b/e2e/solid-start/deferred-hydration/package.json @@ -23,7 +23,7 @@ "solid-js": "^1.9.10" }, "devDependencies": { - "@rsbuild/core": "^2.0.1", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-babel": "^1.1.2", "@rsbuild/plugin-solid": "^1.1.1", "@tanstack/router-e2e-utils": "workspace:^", diff --git a/e2e/vue-router/rspack-basic-file-based/package.json b/e2e/vue-router/rspack-basic-file-based/package.json index 78b7e74a41..5d8a072d87 100644 --- a/e2e/vue-router/rspack-basic-file-based/package.json +++ b/e2e/vue-router/rspack-basic-file-based/package.json @@ -17,7 +17,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-babel": "^1.1.2", "@rsbuild/plugin-vue": "^1.2.7", "@rsbuild/plugin-vue-jsx": "^2.0.0", diff --git a/e2e/vue-router/rspack-basic-virtual-named-export-config-file-based/package.json b/e2e/vue-router/rspack-basic-virtual-named-export-config-file-based/package.json index 6a5cfead84..11f61237d3 100644 --- a/e2e/vue-router/rspack-basic-virtual-named-export-config-file-based/package.json +++ b/e2e/vue-router/rspack-basic-virtual-named-export-config-file-based/package.json @@ -17,7 +17,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-babel": "^1.1.2", "@rsbuild/plugin-vue": "^1.2.7", "@rsbuild/plugin-vue-jsx": "^2.0.0", diff --git a/e2e/vue-start/basic/package.json b/e2e/vue-start/basic/package.json index 2df94b1a20..073627701a 100644 --- a/e2e/vue-start/basic/package.json +++ b/e2e/vue-start/basic/package.json @@ -27,7 +27,7 @@ }, "devDependencies": { "@playwright/test": "^1.50.1", - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-babel": "^1.0.5", "@rsbuild/plugin-vue": "^1.2.2", "@rsbuild/plugin-vue-jsx": "^1.1.1", diff --git a/examples/react/quickstart-rspack-file-based/package.json b/examples/react/quickstart-rspack-file-based/package.json index acf4e2324e..7055b4b8af 100644 --- a/examples/react/quickstart-rspack-file-based/package.json +++ b/examples/react/quickstart-rspack-file-based/package.json @@ -17,7 +17,7 @@ "tailwindcss": "^4.2.2" }, "devDependencies": { - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-react": "^2.0.0", "@tanstack/router-plugin": "^1.168.14", "@types/react": "^19.0.8", diff --git a/examples/solid/quickstart-rspack-file-based/package.json b/examples/solid/quickstart-rspack-file-based/package.json index 98aa15f75c..68774d5e72 100644 --- a/examples/solid/quickstart-rspack-file-based/package.json +++ b/examples/solid/quickstart-rspack-file-based/package.json @@ -16,7 +16,7 @@ "tailwindcss": "^4.2.2" }, "devDependencies": { - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@rsbuild/plugin-babel": "^1.1.2", "@rsbuild/plugin-solid": "^1.1.1", "@tanstack/router-plugin": "^1.168.14", diff --git a/packages/react-start/package.json b/packages/react-start/package.json index fb6147d24d..b76e79ba2f 100644 --- a/packages/react-start/package.json +++ b/packages/react-start/package.json @@ -188,7 +188,7 @@ } }, "devDependencies": { - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@types/node": ">=20" } } diff --git a/packages/solid-start/package.json b/packages/solid-start/package.json index 2c52a15ed7..fc32f27b72 100644 --- a/packages/solid-start/package.json +++ b/packages/solid-start/package.json @@ -127,7 +127,7 @@ "pathe": "^2.0.3" }, "devDependencies": { - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@tanstack/router-utils": "workspace:*", "@types/node": ">=20", "vite": "*" diff --git a/packages/start-plugin-core/package.json b/packages/start-plugin-core/package.json index 19dded23d7..5dd5d35e53 100644 --- a/packages/start-plugin-core/package.json +++ b/packages/start-plugin-core/package.json @@ -109,7 +109,7 @@ "zod": "^4.4.3" }, "devDependencies": { - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@types/babel__code-frame": "^7.0.6", "@types/babel__core": "^7.20.5", "@types/node": ">=20", diff --git a/packages/vue-start/package.json b/packages/vue-start/package.json index 9f7a4f501e..ebe172b9c7 100644 --- a/packages/vue-start/package.json +++ b/packages/vue-start/package.json @@ -121,7 +121,7 @@ "pathe": "^2.0.3" }, "devDependencies": { - "@rsbuild/core": "^2.0.8", + "@rsbuild/core": "^2.0.11", "@tanstack/router-utils": "workspace:*", "@types/node": ">=20", "@vitejs/plugin-vue-jsx": "^4.1.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6aa9b16fea..63b7cbe00f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -216,11 +216,11 @@ importers: version: 3.5.25(typescript@6.0.2) devDependencies: '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-react': specifier: ^2.0.0 - version: 2.0.0(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23)) + version: 2.0.0(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23)) '@tanstack/router-plugin': specifier: workspace:* version: link:../../packages/router-plugin @@ -1110,11 +1110,11 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-react': specifier: ^2.0.0 - version: 2.0.0(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23)) + version: 2.0.0(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23)) '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 @@ -1162,11 +1162,11 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-react': specifier: ^2.0.0 - version: 2.0.0(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23)) + version: 2.0.0(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23)) '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 @@ -1385,11 +1385,11 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-react': specifier: ^2.0.0 - version: 2.0.0(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23)) + version: 2.0.0(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23)) '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 @@ -1788,11 +1788,11 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-react': specifier: ^2.0.0 - version: 2.0.0(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23)) + version: 2.0.0(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23)) '@tanstack/router-e2e-utils': specifier: workspace:^ version: link:../../e2e-utils @@ -1959,11 +1959,11 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-react': specifier: ^2.0.0 - version: 2.0.0(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23)) + version: 2.0.0(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23)) '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 @@ -2014,11 +2014,11 @@ importers: version: 19.2.3(react@19.2.3) devDependencies: '@rsbuild/core': - specifier: ^2.0.1 - version: 2.0.1 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-react': specifier: ^2.0.0 - version: 2.0.0(@rsbuild/core@2.0.1)(@rspack/core@2.0.5(@swc/helpers@0.5.21)) + version: 2.0.0(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23)) '@tanstack/router-e2e-utils': specifier: workspace:^ version: link:../../e2e-utils @@ -2207,11 +2207,11 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-react': specifier: ^2.0.0 - version: 2.0.0(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23)) + version: 2.0.0(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23)) '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 @@ -2317,11 +2317,11 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-react': specifier: ^2.0.0 - version: 2.0.0(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23)) + version: 2.0.0(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23)) '@tanstack/router-e2e-utils': specifier: workspace:^ version: link:../../e2e-utils @@ -2476,11 +2476,11 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-react': specifier: ^2.0.0 - version: 2.0.0(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23)) + version: 2.0.0(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23)) '@tanstack/eslint-plugin-start': specifier: workspace:^ version: link:../../../packages/eslint-plugin-start @@ -2830,11 +2830,11 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-react': specifier: ^2.0.0 - version: 2.0.0(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23)) + version: 2.0.0(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23)) '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 @@ -3928,14 +3928,14 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-babel': specifier: ^1.1.2 - version: 1.1.2(@rsbuild/core@2.0.8) + version: 1.1.2(@rsbuild/core@2.0.11) '@rsbuild/plugin-solid': specifier: ^1.1.1 - version: 1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.8)(solid-js@1.9.12) + version: 1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.11)(solid-js@1.9.12) '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 @@ -3974,14 +3974,14 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-babel': specifier: ^1.1.2 - version: 1.1.2(@rsbuild/core@2.0.8) + version: 1.1.2(@rsbuild/core@2.0.11) '@rsbuild/plugin-solid': specifier: ^1.1.1 - version: 1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.8)(solid-js@1.9.12) + version: 1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.11)(solid-js@1.9.12) '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 @@ -4167,14 +4167,14 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-babel': specifier: ^1.1.2 - version: 1.1.2(@rsbuild/core@2.0.8) + version: 1.1.2(@rsbuild/core@2.0.11) '@rsbuild/plugin-solid': specifier: ^1.1.1 - version: 1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.8)(solid-js@1.9.12) + version: 1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.11)(solid-js@1.9.12) '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 @@ -4556,14 +4556,14 @@ importers: version: 1.9.12 devDependencies: '@rsbuild/core': - specifier: ^2.0.1 - version: 2.0.1 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-babel': specifier: ^1.1.2 - version: 1.1.2(@rsbuild/core@2.0.1) + version: 1.1.2(@rsbuild/core@2.0.11) '@rsbuild/plugin-solid': specifier: ^1.1.1 - version: 1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.1)(solid-js@1.9.12) + version: 1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.11)(solid-js@1.9.12) '@tanstack/router-e2e-utils': specifier: workspace:^ version: link:../../e2e-utils @@ -5756,17 +5756,17 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-babel': specifier: ^1.1.2 - version: 1.1.2(@rsbuild/core@2.0.8) + version: 1.1.2(@rsbuild/core@2.0.11) '@rsbuild/plugin-vue': specifier: ^1.2.7 - version: 1.2.7(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23))(vue@3.5.25(typescript@6.0.2)) + version: 1.2.7(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23))(vue@3.5.25(typescript@6.0.2)) '@rsbuild/plugin-vue-jsx': specifier: ^2.0.0 - version: 2.0.0(@babel/core@7.29.0)(@rsbuild/core@2.0.8) + version: 2.0.0(@babel/core@7.29.0)(@rsbuild/core@2.0.11) '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 @@ -5811,17 +5811,17 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-babel': specifier: ^1.1.2 - version: 1.1.2(@rsbuild/core@2.0.8) + version: 1.1.2(@rsbuild/core@2.0.11) '@rsbuild/plugin-vue': specifier: ^1.2.7 - version: 1.2.7(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23))(vue@3.5.25(typescript@6.0.2)) + version: 1.2.7(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23))(vue@3.5.25(typescript@6.0.2)) '@rsbuild/plugin-vue-jsx': specifier: ^2.0.0 - version: 2.0.0(@babel/core@7.29.0)(@rsbuild/core@2.0.8) + version: 2.0.0(@babel/core@7.29.0)(@rsbuild/core@2.0.11) '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 @@ -6034,17 +6034,17 @@ importers: specifier: ^1.57.0 version: 1.58.0 '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-babel': specifier: ^1.0.5 - version: 1.0.6(@rsbuild/core@2.0.8) + version: 1.0.6(@rsbuild/core@2.0.11) '@rsbuild/plugin-vue': specifier: ^1.2.2 - version: 1.2.2(@rsbuild/core@2.0.8)(@swc/core@1.15.33(@swc/helpers@0.5.23))(esbuild@0.27.4)(vue@3.5.25(typescript@6.0.2)) + version: 1.2.2(@rsbuild/core@2.0.11)(@swc/core@1.15.33(@swc/helpers@0.5.23))(esbuild@0.27.4)(vue@3.5.25(typescript@6.0.2)) '@rsbuild/plugin-vue-jsx': specifier: ^1.1.1 - version: 1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.8) + version: 1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.11) '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 @@ -8107,11 +8107,11 @@ importers: version: 4.2.2 devDependencies: '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-react': specifier: ^2.0.0 - version: 2.0.0(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23)) + version: 2.0.0(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23)) '@tanstack/router-plugin': specifier: workspace:* version: link:../../../packages/router-plugin @@ -11080,14 +11080,14 @@ importers: version: 4.2.2 devDependencies: '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@rsbuild/plugin-babel': specifier: ^1.1.2 - version: 1.1.2(@rsbuild/core@2.0.8) + version: 1.1.2(@rsbuild/core@2.0.11) '@rsbuild/plugin-solid': specifier: ^1.1.1 - version: 1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.8)(solid-js@1.9.12) + version: 1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.11)(solid-js@1.9.12) '@tanstack/router-plugin': specifier: workspace:* version: link:../../../packages/router-plugin @@ -12548,8 +12548,8 @@ importers: version: 8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1) devDependencies: '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@types/node': specifier: 25.0.9 version: 25.0.9 @@ -12839,7 +12839,7 @@ importers: version: 7.28.5 '@rsbuild/core': specifier: '>=1.0.2 || ^2.0.0' - version: 2.0.1 + version: 2.0.11 '@tanstack/react-router': specifier: workspace:* version: link:../react-router @@ -13085,8 +13085,8 @@ importers: version: 1.9.12 devDependencies: '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@tanstack/router-utils': specifier: workspace:* version: link:../router-utils @@ -13257,8 +13257,8 @@ importers: version: 4.4.3 devDependencies: '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@types/babel__code-frame': specifier: ^7.0.6 version: 7.0.6 @@ -13504,8 +13504,8 @@ importers: version: 2.0.3 devDependencies: '@rsbuild/core': - specifier: ^2.0.8 - version: 2.0.8 + specifier: ^2.0.11 + version: 2.0.11 '@tanstack/router-utils': specifier: workspace:* version: link:../router-utils @@ -18194,18 +18194,8 @@ packages: cpu: [x64] os: [win32] - '@rsbuild/core@2.0.1': - resolution: {integrity: sha512-5TwUpb10Y+VYaYH8oLL/rfJGrhxrk16BiGzv101kzaMPT60MtOXgjEUTxztbjRuq0ifbtRJ/w7rsIZQ4VziWYg==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - core-js: '>= 3.0.0' - peerDependenciesMeta: - core-js: - optional: true - - '@rsbuild/core@2.0.8': - resolution: {integrity: sha512-V5Bhn3zqljsaB5grw9oMkSk6XZFvMkr6UpIYPZnDmOWsRAT1fNQ6XF6cn8fVUKv/KILblBrKLUZf0DpvDt3exw==} + '@rsbuild/core@2.0.11': + resolution: {integrity: sha512-Mpp/viUSkVdSWJkFipdZxM2nUztrBwSnMm6Q86bPzLHtHnXqQ3VFpSMlA4wWRyySNddP6s6efKiVpx0ZOCf7Gg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -18277,8 +18267,8 @@ packages: cpu: [arm64] os: [darwin] - '@rspack/binding-darwin-arm64@2.0.5': - resolution: {integrity: sha512-++wjLQjQ20GcR0DwbzQmVXg9qy4XCX5NlfSzkzj2icHoDxr3KkrXhyVrQkdWuNG6l/bQrGLPnvLEAqkroC2Y7A==} + '@rspack/binding-darwin-arm64@2.0.6': + resolution: {integrity: sha512-0giCKiWlBfcM4i2scv1j2k9HlSecO9Ybhaa5wsMUyvcFeKr9HbNHh7C2eDFlC6zaI85IUdY71TXF/g/Tcxr9MA==} cpu: [arm64] os: [darwin] @@ -18287,8 +18277,8 @@ packages: cpu: [x64] os: [darwin] - '@rspack/binding-darwin-x64@2.0.5': - resolution: {integrity: sha512-JBD5mCN3JKjV64Mh9nDYx8lLUrWDfEl5tLBuMkREUnqEKbo+z4nfwotyqHHM8/XgZwL+Gr7ps4GLWuQQrZB8+Q==} + '@rspack/binding-darwin-x64@2.0.6': + resolution: {integrity: sha512-/mMo2IpI02aOKMlHbVbZue3TJxFqHGX+ibVTdEO+6bzRSuHs7+R9KM5U3XH2YxcWJy5Sid1X1T1pJAjsXcE3rA==} cpu: [x64] os: [darwin] @@ -18298,8 +18288,8 @@ packages: os: [linux] libc: [glibc] - '@rspack/binding-linux-arm64-gnu@2.0.5': - resolution: {integrity: sha512-JI8+//woanJPNsfL7iGjX39zyiWumnrKHznWQM/7lEtE5nPmk+j+X7TYXxczSWC9zfZegiqI74D3L5JPDC84Fw==} + '@rspack/binding-linux-arm64-gnu@2.0.6': + resolution: {integrity: sha512-H6ACzeM1KBxYDEF8YAim3501Jb1aCsSG79Gjm1M4pwJ5OJPK2ydiJEa438ugXmh0962eKYMHI2yZY0sQq8txaw==} cpu: [arm64] os: [linux] libc: [glibc] @@ -18310,8 +18300,8 @@ packages: os: [linux] libc: [musl] - '@rspack/binding-linux-arm64-musl@2.0.5': - resolution: {integrity: sha512-5LujilxLtJFRiiPz5i5iWcWJriK9oy4gN7gZtTo8YRB7wwmwA8LMypTjjO0GLbkPS4/KeCfY4fDfTC29KmK+tA==} + '@rspack/binding-linux-arm64-musl@2.0.6': + resolution: {integrity: sha512-QTFmBg0n+L397Wi8CIjbd5pe/hxpHnqCDaG1A7e2NWX8Fj9zulAoKLiKflQa1ELEhAY4Foq88aX75+Ilt2tHcw==} cpu: [arm64] os: [linux] libc: [musl] @@ -18322,8 +18312,8 @@ packages: os: [linux] libc: [glibc] - '@rspack/binding-linux-x64-gnu@2.0.5': - resolution: {integrity: sha512-241wqE132jh+/U/pn97qUPV4KpIy4bSrTH0tqfzQCocgw+8hrUj02GqNG+3MXVC3qtwaQeJFYgEBy3TqFKsrIQ==} + '@rspack/binding-linux-x64-gnu@2.0.6': + resolution: {integrity: sha512-rerCAz022zf0ewxI+7n3SrqLEaxCL+MXRxKjK5FLUGFa8UkIrivq+VUP/1OB6JLh2Bucebc7Y9WoWHvtk22mLA==} cpu: [x64] os: [linux] libc: [glibc] @@ -18334,8 +18324,8 @@ packages: os: [linux] libc: [musl] - '@rspack/binding-linux-x64-musl@2.0.5': - resolution: {integrity: sha512-BhaXZD064Lci3Kia0kLDAb4TyxO2C+0UidMlj44e8+ctasxIfFZgnrhCJrhTFHAtOiAwqhU3FHun2UuxPqX0Eg==} + '@rspack/binding-linux-x64-musl@2.0.6': + resolution: {integrity: sha512-96IgOFXQjX6Wbxd+DCYJFy2r/VMu1OoHifW4Cr3kGTYDKoQOIMLwb0ieu/ILp2dGWFMZo5S8odiByAmNICAOIA==} cpu: [x64] os: [linux] libc: [musl] @@ -18344,8 +18334,8 @@ packages: resolution: {integrity: sha512-ANk73ZKtPrZf9gdtyRK2nQUfhi1uXoC5P2KF89pyVAE8+zcoLBnYtZGYpWa/cmNi5BcO5g4Z+v2l1UA3bUPLQQ==} cpu: [wasm32] - '@rspack/binding-wasm32-wasi@2.0.5': - resolution: {integrity: sha512-duEkRoXrl9SW8uGHv7JURJ5lgKu87qFDQ4Exy6UQPvsUJVXhtRXTfvMHCb/CejVJuW2Bw2D632/axZq3qRSuBQ==} + '@rspack/binding-wasm32-wasi@2.0.6': + resolution: {integrity: sha512-0aWiF+qmdb0csp1x+MaR2o1pscoquLaEbLTVdKjmoTRs6sguMemtB1ObnVTahAUL73P66WePuNpFAJ81zNdqzQ==} cpu: [wasm32] '@rspack/binding-win32-arm64-msvc@2.0.0': @@ -18353,8 +18343,8 @@ packages: cpu: [arm64] os: [win32] - '@rspack/binding-win32-arm64-msvc@2.0.5': - resolution: {integrity: sha512-q2WT3HFoWL+2g84l3s2kY7CiE1gEZ1bwB3txx3eZzQQ6YKP7bE82z6sl6S/pTOHGjHdAO4snQXpSaHwUt3LX5g==} + '@rspack/binding-win32-arm64-msvc@2.0.6': + resolution: {integrity: sha512-BX638A1MXsjc2E3tUskVh3X/WBIHjLKK+lo395v7MmEL9u2BA6l3F6RyW+YaJOt5aEOOv83iA7iCZsviVZ49Uw==} cpu: [arm64] os: [win32] @@ -18363,8 +18353,8 @@ packages: cpu: [ia32] os: [win32] - '@rspack/binding-win32-ia32-msvc@2.0.5': - resolution: {integrity: sha512-nMJGIY7kvgbyMolEE7tXDe+Z9jSItDshTIqMQQkkD3WTHdjlBQozHxk4kBtKLsunO+3NkCLe5Oa3hXg1yyStIg==} + '@rspack/binding-win32-ia32-msvc@2.0.6': + resolution: {integrity: sha512-DCK/+MlN35uvH7tp4j0hbg8wIs9MHArMIrNZXtiD8xP6DNw2wrXcGC1VaxxR5apyWpqXAfIL/KsXBiWS3ygCvg==} cpu: [ia32] os: [win32] @@ -18373,16 +18363,16 @@ packages: cpu: [x64] os: [win32] - '@rspack/binding-win32-x64-msvc@2.0.5': - resolution: {integrity: sha512-vP0BR6fxdPL9cb02HAuZATg/CjR07aecWel3s1vqRwW1aDffgXh9PVmqEKIHTgyaNsNR55kSKNJsB9AcQ8/QrA==} + '@rspack/binding-win32-x64-msvc@2.0.6': + resolution: {integrity: sha512-TxutgzdEX9BkAU/5liKxdQmggJ23INz7EZDWtzSJO6C2SiSYzTJdyPQDIJi1ddkM5TX/drzH184gAJMVOQefng==} cpu: [x64] os: [win32] '@rspack/binding@2.0.0': resolution: {integrity: sha512-WA2f9eQpejkvf5Vrnf6wNCn1m8RT1p08NjgOZpKhsCzr0uBjWeRvGduawlrFFHZh/jPnWZTVaVdQ08FEAWbwGw==} - '@rspack/binding@2.0.5': - resolution: {integrity: sha512-Ta1y4WXJA87wM1OstqaMddoPsBGv7Cu779bYToKxEAqR/Yy9DxLkp7bdgBaAx2JH++BwVjV+toWts2V9AaiTFQ==} + '@rspack/binding@2.0.6': + resolution: {integrity: sha512-z5EO9mPlmYNpHAlRGub0Chr6D+Klgy+tX36n7tCm7VRGRlwTmTU9wSENrYbHcCpFbegtrE0s30rDeTBeOu+JiQ==} '@rspack/core@2.0.0': resolution: {integrity: sha512-WD1mJM9LbZ7Z399Rbv9dE3BNEV0+3sE5OzDdzV8hOxUb3mX++ynK5n9kil8w60B6nGdcKeV9ly5aN4PgqiwWUg==} @@ -18396,8 +18386,8 @@ packages: '@swc/helpers': optional: true - '@rspack/core@2.0.5': - resolution: {integrity: sha512-9tv2HAnSiTote5WPH2tmz1hLZ1zKbzkiZc1eYp7LP/8jcsiJBuf40ihiWidAgbbuYtJo3kWET6q+qOm5UhNiGA==} + '@rspack/core@2.0.6': + resolution: {integrity: sha512-ronRqH1T2dYdMFVOQbGvDNxYaLugQK8qhNYYtS2DbOvPKQYvdIYWDenL9k/WV+hLoknnPWMn2ME2cKJcK3Po+g==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: '@module-federation/runtime-tools': ^0.24.1 || ^2.0.0 @@ -18919,9 +18909,6 @@ packages: '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - '@swc/helpers@0.5.21': - resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==} - '@swc/helpers@0.5.23': resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==} @@ -31449,27 +31436,20 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.56.0': optional: true - '@rsbuild/core@2.0.1': + '@rsbuild/core@2.0.11': dependencies: - '@rspack/core': 2.0.0(@swc/helpers@0.5.21) - '@swc/helpers': 0.5.21 - transitivePeerDependencies: - - '@module-federation/runtime-tools' - - '@rsbuild/core@2.0.8': - dependencies: - '@rspack/core': 2.0.5(@swc/helpers@0.5.23) + '@rspack/core': 2.0.6(@swc/helpers@0.5.23) '@swc/helpers': 0.5.23 transitivePeerDependencies: - '@module-federation/runtime-tools' - '@rsbuild/plugin-babel@1.0.6(@rsbuild/core@2.0.8)': + '@rsbuild/plugin-babel@1.0.6(@rsbuild/core@2.0.11)': dependencies: '@babel/core': 7.28.5 '@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.28.5) '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.5) '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) - '@rsbuild/core': 2.0.8 + '@rsbuild/core': 2.0.11 '@types/babel__core': 7.20.5 deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -31477,7 +31457,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@rsbuild/plugin-babel@1.1.2(@rsbuild/core@2.0.1)': + '@rsbuild/plugin-babel@1.1.2(@rsbuild/core@2.0.11)': dependencies: '@babel/core': 7.29.0 '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) @@ -31486,90 +31466,56 @@ snapshots: '@types/babel__core': 7.20.5 reduce-configs: 1.1.1 optionalDependencies: - '@rsbuild/core': 2.0.1 + '@rsbuild/core': 2.0.11 transitivePeerDependencies: - supports-color - '@rsbuild/plugin-babel@1.1.2(@rsbuild/core@2.0.8)': + '@rsbuild/plugin-react@2.0.0(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23))': dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) - '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) - '@types/babel__core': 7.20.5 - reduce-configs: 1.1.1 - optionalDependencies: - '@rsbuild/core': 2.0.8 - transitivePeerDependencies: - - supports-color - - '@rsbuild/plugin-react@2.0.0(@rsbuild/core@2.0.1)(@rspack/core@2.0.5(@swc/helpers@0.5.21))': - dependencies: - '@rspack/plugin-react-refresh': 2.0.0(@rspack/core@2.0.5(@swc/helpers@0.5.21))(react-refresh@0.18.0) + '@rspack/plugin-react-refresh': 2.0.0(@rspack/core@2.0.6(@swc/helpers@0.5.23))(react-refresh@0.18.0) react-refresh: 0.18.0 optionalDependencies: - '@rsbuild/core': 2.0.1 + '@rsbuild/core': 2.0.11 transitivePeerDependencies: - '@rspack/core' - '@rsbuild/plugin-react@2.0.0(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23))': + '@rsbuild/plugin-solid@1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.11)(solid-js@1.9.12)': dependencies: - '@rspack/plugin-react-refresh': 2.0.0(@rspack/core@2.0.5(@swc/helpers@0.5.23))(react-refresh@0.18.0) - react-refresh: 0.18.0 - optionalDependencies: - '@rsbuild/core': 2.0.8 - transitivePeerDependencies: - - '@rspack/core' - - '@rsbuild/plugin-solid@1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.1)(solid-js@1.9.12)': - dependencies: - '@rsbuild/plugin-babel': 1.1.2(@rsbuild/core@2.0.1) + '@rsbuild/plugin-babel': 1.1.2(@rsbuild/core@2.0.11) babel-preset-solid: 1.9.10(@babel/core@7.29.0)(solid-js@1.9.12) solid-refresh: 0.7.8(solid-js@1.9.12) optionalDependencies: - '@rsbuild/core': 2.0.1 + '@rsbuild/core': 2.0.11 transitivePeerDependencies: - '@babel/core' - solid-js - supports-color - '@rsbuild/plugin-solid@1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.8)(solid-js@1.9.12)': + '@rsbuild/plugin-vue-jsx@1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.11)': dependencies: - '@rsbuild/plugin-babel': 1.1.2(@rsbuild/core@2.0.8) - babel-preset-solid: 1.9.10(@babel/core@7.29.0)(solid-js@1.9.12) - solid-refresh: 0.7.8(solid-js@1.9.12) - optionalDependencies: - '@rsbuild/core': 2.0.8 - transitivePeerDependencies: - - '@babel/core' - - solid-js - - supports-color - - '@rsbuild/plugin-vue-jsx@1.1.1(@babel/core@7.29.0)(@rsbuild/core@2.0.8)': - dependencies: - '@rsbuild/plugin-babel': 1.1.2(@rsbuild/core@2.0.8) + '@rsbuild/plugin-babel': 1.1.2(@rsbuild/core@2.0.11) '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.29.0) babel-plugin-vue-jsx-hmr: 1.0.0 optionalDependencies: - '@rsbuild/core': 2.0.8 + '@rsbuild/core': 2.0.11 transitivePeerDependencies: - '@babel/core' - supports-color - '@rsbuild/plugin-vue-jsx@2.0.0(@babel/core@7.29.0)(@rsbuild/core@2.0.8)': + '@rsbuild/plugin-vue-jsx@2.0.0(@babel/core@7.29.0)(@rsbuild/core@2.0.11)': dependencies: - '@rsbuild/plugin-babel': 1.1.2(@rsbuild/core@2.0.8) + '@rsbuild/plugin-babel': 1.1.2(@rsbuild/core@2.0.11) '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.29.0) babel-plugin-vue-jsx-hmr: 1.0.0 optionalDependencies: - '@rsbuild/core': 2.0.8 + '@rsbuild/core': 2.0.11 transitivePeerDependencies: - '@babel/core' - supports-color - '@rsbuild/plugin-vue@1.2.2(@rsbuild/core@2.0.8)(@swc/core@1.15.33(@swc/helpers@0.5.23))(esbuild@0.27.4)(vue@3.5.25(typescript@6.0.2))': + '@rsbuild/plugin-vue@1.2.2(@rsbuild/core@2.0.11)(@swc/core@1.15.33(@swc/helpers@0.5.23))(esbuild@0.27.4)(vue@3.5.25(typescript@6.0.2))': dependencies: - '@rsbuild/core': 2.0.8 + '@rsbuild/core': 2.0.11 rspack-vue-loader: 17.4.4(vue@3.5.25(typescript@6.0.2))(webpack@5.104.0(@swc/core@1.15.33(@swc/helpers@0.5.23))(esbuild@0.27.4)) webpack: 5.104.0(@swc/core@1.15.33(@swc/helpers@0.5.23))(esbuild@0.27.4) transitivePeerDependencies: @@ -31580,11 +31526,11 @@ snapshots: - vue - webpack-cli - '@rsbuild/plugin-vue@1.2.7(@rsbuild/core@2.0.8)(@rspack/core@2.0.5(@swc/helpers@0.5.23))(vue@3.5.25(typescript@6.0.2))': + '@rsbuild/plugin-vue@1.2.7(@rsbuild/core@2.0.11)(@rspack/core@2.0.6(@swc/helpers@0.5.23))(vue@3.5.25(typescript@6.0.2))': dependencies: - rspack-vue-loader: 17.5.0(@rspack/core@2.0.5(@swc/helpers@0.5.23))(vue@3.5.25(typescript@6.0.2)) + rspack-vue-loader: 17.5.0(@rspack/core@2.0.6(@swc/helpers@0.5.23))(vue@3.5.25(typescript@6.0.2)) optionalDependencies: - '@rsbuild/core': 2.0.8 + '@rsbuild/core': 2.0.11 transitivePeerDependencies: - '@rspack/core' - '@vue/compiler-sfc' @@ -31593,37 +31539,37 @@ snapshots: '@rspack/binding-darwin-arm64@2.0.0': optional: true - '@rspack/binding-darwin-arm64@2.0.5': + '@rspack/binding-darwin-arm64@2.0.6': optional: true '@rspack/binding-darwin-x64@2.0.0': optional: true - '@rspack/binding-darwin-x64@2.0.5': + '@rspack/binding-darwin-x64@2.0.6': optional: true '@rspack/binding-linux-arm64-gnu@2.0.0': optional: true - '@rspack/binding-linux-arm64-gnu@2.0.5': + '@rspack/binding-linux-arm64-gnu@2.0.6': optional: true '@rspack/binding-linux-arm64-musl@2.0.0': optional: true - '@rspack/binding-linux-arm64-musl@2.0.5': + '@rspack/binding-linux-arm64-musl@2.0.6': optional: true '@rspack/binding-linux-x64-gnu@2.0.0': optional: true - '@rspack/binding-linux-x64-gnu@2.0.5': + '@rspack/binding-linux-x64-gnu@2.0.6': optional: true '@rspack/binding-linux-x64-musl@2.0.0': optional: true - '@rspack/binding-linux-x64-musl@2.0.5': + '@rspack/binding-linux-x64-musl@2.0.6': optional: true '@rspack/binding-wasm32-wasi@2.0.0': @@ -31633,7 +31579,7 @@ snapshots: '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rspack/binding-wasm32-wasi@2.0.5': + '@rspack/binding-wasm32-wasi@2.0.6': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 @@ -31643,19 +31589,19 @@ snapshots: '@rspack/binding-win32-arm64-msvc@2.0.0': optional: true - '@rspack/binding-win32-arm64-msvc@2.0.5': + '@rspack/binding-win32-arm64-msvc@2.0.6': optional: true '@rspack/binding-win32-ia32-msvc@2.0.0': optional: true - '@rspack/binding-win32-ia32-msvc@2.0.5': + '@rspack/binding-win32-ia32-msvc@2.0.6': optional: true '@rspack/binding-win32-x64-msvc@2.0.0': optional: true - '@rspack/binding-win32-x64-msvc@2.0.5': + '@rspack/binding-win32-x64-msvc@2.0.6': optional: true '@rspack/binding@2.0.0': @@ -31671,24 +31617,18 @@ snapshots: '@rspack/binding-win32-ia32-msvc': 2.0.0 '@rspack/binding-win32-x64-msvc': 2.0.0 - '@rspack/binding@2.0.5': - optionalDependencies: - '@rspack/binding-darwin-arm64': 2.0.5 - '@rspack/binding-darwin-x64': 2.0.5 - '@rspack/binding-linux-arm64-gnu': 2.0.5 - '@rspack/binding-linux-arm64-musl': 2.0.5 - '@rspack/binding-linux-x64-gnu': 2.0.5 - '@rspack/binding-linux-x64-musl': 2.0.5 - '@rspack/binding-wasm32-wasi': 2.0.5 - '@rspack/binding-win32-arm64-msvc': 2.0.5 - '@rspack/binding-win32-ia32-msvc': 2.0.5 - '@rspack/binding-win32-x64-msvc': 2.0.5 - - '@rspack/core@2.0.0(@swc/helpers@0.5.21)': - dependencies: - '@rspack/binding': 2.0.0 + '@rspack/binding@2.0.6': optionalDependencies: - '@swc/helpers': 0.5.21 + '@rspack/binding-darwin-arm64': 2.0.6 + '@rspack/binding-darwin-x64': 2.0.6 + '@rspack/binding-linux-arm64-gnu': 2.0.6 + '@rspack/binding-linux-arm64-musl': 2.0.6 + '@rspack/binding-linux-x64-gnu': 2.0.6 + '@rspack/binding-linux-x64-musl': 2.0.6 + '@rspack/binding-wasm32-wasi': 2.0.6 + '@rspack/binding-win32-arm64-msvc': 2.0.6 + '@rspack/binding-win32-ia32-msvc': 2.0.6 + '@rspack/binding-win32-x64-msvc': 2.0.6 '@rspack/core@2.0.0(@swc/helpers@0.5.23)': dependencies: @@ -31696,32 +31636,19 @@ snapshots: optionalDependencies: '@swc/helpers': 0.5.23 - '@rspack/core@2.0.5(@swc/helpers@0.5.21)': + '@rspack/core@2.0.6(@swc/helpers@0.5.23)': dependencies: - '@rspack/binding': 2.0.5 - optionalDependencies: - '@swc/helpers': 0.5.21 - optional: true - - '@rspack/core@2.0.5(@swc/helpers@0.5.23)': - dependencies: - '@rspack/binding': 2.0.5 + '@rspack/binding': 2.0.6 optionalDependencies: '@swc/helpers': 0.5.23 '@rspack/lite-tapable@1.1.0': {} - '@rspack/plugin-react-refresh@2.0.0(@rspack/core@2.0.5(@swc/helpers@0.5.21))(react-refresh@0.18.0)': + '@rspack/plugin-react-refresh@2.0.0(@rspack/core@2.0.6(@swc/helpers@0.5.23))(react-refresh@0.18.0)': dependencies: react-refresh: 0.18.0 optionalDependencies: - '@rspack/core': 2.0.5(@swc/helpers@0.5.21) - - '@rspack/plugin-react-refresh@2.0.0(@rspack/core@2.0.5(@swc/helpers@0.5.23))(react-refresh@0.18.0)': - dependencies: - react-refresh: 0.18.0 - optionalDependencies: - '@rspack/core': 2.0.5(@swc/helpers@0.5.23) + '@rspack/core': 2.0.6(@swc/helpers@0.5.23) '@rushstack/node-core-library@5.7.0(@types/node@25.0.9)': dependencies: @@ -32262,10 +32189,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@swc/helpers@0.5.21': - dependencies: - tslib: 2.8.1 - '@swc/helpers@0.5.23': dependencies: tslib: 2.8.1 @@ -39485,12 +39408,12 @@ snapshots: optionalDependencies: vue: 3.5.25(typescript@6.0.2) - rspack-vue-loader@17.5.0(@rspack/core@2.0.5(@swc/helpers@0.5.23))(vue@3.5.25(typescript@6.0.2)): + rspack-vue-loader@17.5.0(@rspack/core@2.0.6(@swc/helpers@0.5.23))(vue@3.5.25(typescript@6.0.2)): dependencies: '@rspack/lite-tapable': 1.1.0 chalk: 4.1.2 optionalDependencies: - '@rspack/core': 2.0.5(@swc/helpers@0.5.23) + '@rspack/core': 2.0.6(@swc/helpers@0.5.23) vue: 3.5.25(typescript@6.0.2) run-applescript@7.0.0: {} From c6acfd38470294b2b23b21656c54c3037f94f4f9 Mon Sep 17 00:00:00 2001 From: Elecmonkey Date: Wed, 3 Jun 2026 21:47:50 +0800 Subject: [PATCH 8/8] fix(rsbuild): rely on preview asset middleware --- .../start-plugin-core/src/rsbuild/plugin.ts | 2 - .../src/rsbuild/server-middleware.ts | 121 +----------------- 2 files changed, 1 insertion(+), 122 deletions(-) diff --git a/packages/start-plugin-core/src/rsbuild/plugin.ts b/packages/start-plugin-core/src/rsbuild/plugin.ts index aab03cb2c4..143bb06f72 100644 --- a/packages/start-plugin-core/src/rsbuild/plugin.ts +++ b/packages/start-plugin-core/src/rsbuild/plugin.ts @@ -248,8 +248,6 @@ export function tanStackStartRsbuild( ? { setup: createServerSetup({ serverFnBasePath: serverFnBase, - clientOutputDirectory: - resolvedStartConfig.outputDirectories.client, serverOutputDirectory: resolvedStartConfig.outputDirectories.server, publicBase: resolvedStartConfig.basePaths.publicBase, diff --git a/packages/start-plugin-core/src/rsbuild/server-middleware.ts b/packages/start-plugin-core/src/rsbuild/server-middleware.ts index 19e1dcd240..70e2f234ce 100644 --- a/packages/start-plugin-core/src/rsbuild/server-middleware.ts +++ b/packages/start-plugin-core/src/rsbuild/server-middleware.ts @@ -1,5 +1,4 @@ -import { createReadStream, statSync } from 'node:fs' -import { extname, join, normalize, resolve, sep } from 'node:path' +import { resolve } from 'node:path' import { pathToFileURL } from 'node:url' import { NodeRequest, sendNodeResponse } from 'srvx/node' import { joinURL } from 'ufo' @@ -110,7 +109,6 @@ async function loadDevFetchHandler( */ export function createServerSetup(opts: { serverFnBasePath: string - clientOutputDirectory: string serverOutputDirectory: string publicBase: string }): ServerSetupFn { @@ -192,29 +190,6 @@ export function createServerSetup(opts: { return next() }) - // In preview mode, rsbuild's built-in `sirv` is rooted at - // `context.distPath`, which is the common parent of all environments' - // dist paths. With the SSR layout (`dist/client` + `dist/server`), that - // resolves to `dist/`, so requests for `/static/...` miss and fall - // through to the SSR catch-all returning HTML 404s. Mirror Vite's - // behaviour by serving client assets from the client environment's - // dist directory before our SSR catch-all takes over. - if (context.action === 'preview') { - const clientRoot = resolve(opts.clientOutputDirectory) - const publicBasePathname = getPublicBasePathname(opts.publicBase) - context.server.middlewares.use((req, res, next) => { - if (req.method !== 'GET' && req.method !== 'HEAD') return next() - const rawUrl = req.originalUrl ?? req.url ?? '/' - const filePath = resolveStaticAssetPath( - rawUrl, - publicBasePathname, - clientRoot, - ) - if (!filePath) return next() - return serveStaticFile(filePath, req, res, next) - }) - } - // Position 2: AFTER built-ins, before fallback — SSR catch-all for // page navigations. Assets are already handled by rsbuild middleware. return () => { @@ -223,100 +198,6 @@ export function createServerSetup(opts: { } } -const STATIC_ASSET_MIME: Record = { - '.js': 'application/javascript; charset=utf-8', - '.mjs': 'application/javascript; charset=utf-8', - '.cjs': 'application/javascript; charset=utf-8', - '.css': 'text/css; charset=utf-8', - '.html': 'text/html; charset=utf-8', - '.json': 'application/json; charset=utf-8', - '.map': 'application/json; charset=utf-8', - '.svg': 'image/svg+xml', - '.png': 'image/png', - '.jpg': 'image/jpeg', - '.jpeg': 'image/jpeg', - '.gif': 'image/gif', - '.webp': 'image/webp', - '.avif': 'image/avif', - '.ico': 'image/x-icon', - '.woff': 'font/woff', - '.woff2': 'font/woff2', - '.ttf': 'font/ttf', - '.otf': 'font/otf', - '.txt': 'text/plain; charset=utf-8', - '.wasm': 'application/wasm', -} - -function resolveStaticAssetPath( - rawUrl: string, - publicBasePathname: string, - clientRoot: string, -): string | undefined { - let pathname: string - try { - pathname = new URL(rawUrl, 'http://localhost').pathname - } catch { - return undefined - } - - // Strip the public base so `//static/foo.js` and `/static/foo.js` - // both resolve to `/static/foo.js`. - if (publicBasePathname !== '/' && pathname.startsWith(publicBasePathname)) { - pathname = pathname.slice(publicBasePathname.length) || '/' - } - if (!pathname.startsWith('/')) pathname = `/${pathname}` - - // Decode and refuse traversal attempts. - let decoded: string - try { - decoded = decodeURIComponent(pathname) - } catch { - return undefined - } - if (decoded.includes('\0')) return undefined - - const filePath = normalize(join(clientRoot, decoded)) - if (filePath !== clientRoot && !filePath.startsWith(clientRoot + sep)) { - return undefined - } - - let stat - try { - stat = statSync(filePath) - } catch { - return undefined - } - if (!stat.isFile()) return undefined - - return filePath -} - -function serveStaticFile( - filePath: string, - req: IncomingMessage, - res: ServerResponse, - next: (error?: unknown) => void, -) { - const stat = statSync(filePath) - const mime = STATIC_ASSET_MIME[extname(filePath).toLowerCase()] - if (mime) res.setHeader('content-type', mime) - res.setHeader('content-length', stat.size) - - if (req.method === 'HEAD') { - res.statusCode = 200 - res.end() - return - } - - const stream = createReadStream(filePath) - stream.on('error', (err) => { - stream.destroy() - next(err) - }) - res.statusCode = 200 - stream.pipe(res) -} - async function loadPreviewFetchHandler( serverOutputDirectory: string, ): Promise {