Skip to content

feat(start-plugin-core): support Rsbuild preview SSR middleware#7372

Open
elecmonkey wants to merge 8 commits into
TanStack:mainfrom
elecmonkey:main
Open

feat(start-plugin-core): support Rsbuild preview SSR middleware#7372
elecmonkey wants to merge 8 commits into
TanStack:mainfrom
elecmonkey:main

Conversation

@elecmonkey
Copy link
Copy Markdown

@elecmonkey elecmonkey commented May 9, 2026

Summary

Support Rsbuild preview SSR middleware.

Previously, because the output generated by rsbuild build included server-side code for SSR, rsbuild preview treated it as static assets, which caused the preview to malfunction. The middleware code shared between dev mode and preview mode has now been extracted.

Details

This updates the Rsbuild integration so Start’s server middleware is no longer dev-only.

Because the option now controls both dev and preview middleware installation, the Rsbuild option has been renamed:

rsbuild.installDevServerMiddleware

to:

rsbuild.installServerMiddleware

Summary by CodeRabbit

  • New Features

    • Added preview-mode support for the RSBuild toolchain and a project script to run it.
    • E2E tests can select the preview toolchain via an environment variable.
  • Improvements

    • Server-side rendering middleware now runs in both development and preview modes.
    • Middleware option renamed for clearer intent.
    • React integration now deduplicates react and react-dom for RSBuild.
  • Documentation

    • Added release note entry for the fix.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Refactors dev SSR middleware into a unified server-middleware usable in dev and preview, updates rsbuild schema/options, adds rsbuild preview E2E tooling, wires React dedupe overrides for rsbuild, and removes the old dev-server implementation.

Changes

Rsbuild Preview Mode Support

Layer / File(s) Summary
Configuration Schema
packages/start-plugin-core/src/rsbuild/schema.ts
Schema updated to use installServerMiddleware option (replacing installDevServerMiddleware) to reflect support for both dev and preview modes.
E2E Test Configuration
e2e/react-start/basic/package.json, e2e/react-start/basic/playwright.config.ts, e2e/react-start/custom-server-rsbuild/rsbuild.config.ts
Added preview:rsbuild script, extended Playwright modes with rsbuild preview configuration, introduced E2E_TOOLCHAIN environment variable for conditional preview command selection (rsbuild vs vite), and updated plugin configuration option names.
Unified SSR Middleware
packages/start-plugin-core/src/rsbuild/server-middleware.ts
New implementation of createServerSetup factory with type definitions, fetch handler resolution, URL utilities for preview routing, mode-gated bundle loading (dev from in-memory environment, preview from build output), static asset serving in preview, and dual middleware registration for server-function interception and SSR fallback with error handling.
Plugin Wiring
packages/start-plugin-core/src/rsbuild/plugin.ts
Updated to import createServerSetup from new server-middleware module, introduced isDev and isPreview flags to gate middleware installation for both modes, added conditional server.printUrls normalization, and wired server.setup with updated configuration option names.
Legacy Code Removal
packages/start-plugin-core/src/rsbuild/dev-server.ts
Deleted file containing dev-only createServerSetup implementation, including handleSSR middleware logic, type definitions, and middleware registrations now unified in server-middleware.ts.
React Start Plugin Optimization
packages/react-start/src/plugin/rsbuild.ts
Added reactStartRsbuildEnvironmentOverrides constant specifying module resolution deduplication for react and react-dom, wired into corePluginOpts under rsbuild.environments to apply by default.
Release Changeset
.changeset/quiet-rsbuild-preview.md
Adds a patch changeset noting the Rsbuild preview SSR fix, middleware option rename, and React dedupe behavior.

Sequence Diagram

sequenceDiagram
  participant Client
  participant Middleware as ServerMiddleware
  participant DevEnv as RsbuildDevEnv
  participant BuildOut as BuildOutput
  participant Handler as FetchHandler

  Client->>Middleware: HTTP request
  alt preview mode
    Middleware->>BuildOut: import preview bundle (index.js)
    BuildOut-->>Middleware: FetchHandler
  else dev mode
    Middleware->>DevEnv: loadBundle('index')
    DevEnv-->>Middleware: FetchHandler
  end
  Middleware->>Handler: invoke fetch(Request)
  Handler-->>Middleware: Response
  Middleware-->>Client: send response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 A preview mode hops in with style,
rsbuild and vite now choose their mile,
Middleware unified, dev and preview sing,
React deduped — new imports take wing,
Old dev-server bows; new paths spring.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding Rsbuild preview SSR middleware support, which is the core objective of this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 9, 2026

Bundle Size Benchmarks

  • Commit: 4eed408f127b
  • Measured at: 2026-05-09T10:39:44.199Z
  • Baseline source: history:35e88f04996d
  • Dashboard: bundle-size history
Scenario Current (gzip) Delta vs baseline Initial gzip Raw Brotli Trend
react-router.minimal 87.29 KiB +139 B (+0.16%) 87.15 KiB 274.07 KiB 75.81 KiB ▁▁▁▁▁▁▁▁▁▁▁█
react-router.full 90.82 KiB +141 B (+0.15%) 90.68 KiB 285.58 KiB 78.82 KiB ▁▁▁▁▁▁▁▁▁▁▁█
solid-router.minimal 35.51 KiB +126 B (+0.35%) 35.38 KiB 106.36 KiB 31.91 KiB ▁▁▁▁▁▁▁▁▁▁▁█
solid-router.full 40.23 KiB +127 B (+0.31%) 40.10 KiB 120.58 KiB 36.14 KiB ▁▁▁▁▁▁▁▁▁▁▁█
vue-router.minimal 53.28 KiB +131 B (+0.24%) 53.15 KiB 151.51 KiB 47.83 KiB ▁▁▁▁▁▁▁▁▁▁▁█
vue-router.full 58.41 KiB +133 B (+0.22%) 58.28 KiB 167.68 KiB 52.30 KiB ▁▁▁▁▁▁▁▁▁▁▁█
react-start.minimal 101.97 KiB +141 B (+0.14%) 101.84 KiB 322.51 KiB 88.13 KiB ▁▁▁▁▁▁▁▁▁▁▃█
react-start.full 105.41 KiB +140 B (+0.13%) 105.27 KiB 332.84 KiB 91.10 KiB ▁▁▁▁▁▁▁▁▁▁▄█
react-start.rsbuild.minimal 99.60 KiB +174 B (+0.17%) 99.43 KiB 316.97 KiB 85.65 KiB ▁▁▁▁▁▁▁▁▁▁▄█
react-start.rsbuild.full 102.89 KiB +174 B (+0.17%) 102.72 KiB 327.41 KiB 88.45 KiB ▁▁▁▁▁▁▁▁▁▁▃█
solid-start.minimal 49.61 KiB +131 B (+0.26%) 49.48 KiB 152.48 KiB 43.79 KiB ▁▁▁▁▁▁▁▁▁▁▄█
solid-start.full 55.40 KiB +133 B (+0.24%) 55.27 KiB 169.39 KiB 48.70 KiB ▁▁▁▁▁▁▁▁▁▁▄█

Current gzip tracks all emitted client JS chunks. Initial gzip tracks only the entry/import graph. Trend sparkline is historical current gzip ending with this PR measurement; lower is better.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/start-plugin-core/src/rsbuild/schema.ts`:
- Around line 11-13: The rsbuild schema currently only accepts
installServerMiddleware which breaks configs using the old
installDevServerMiddleware key; update the rsbuild zod object to accept both
installServerMiddleware and installDevServerMiddleware as optional booleans,
then normalize to a single canonical property (prefer installServerMiddleware
when both present) by adding a transform/preprocess so downstream code uses only
installServerMiddleware; mark installDevServerMiddleware as deprecated in the
schema/comments/types so it remains supported for one release.

In `@packages/start-plugin-core/src/rsbuild/server-middleware.ts`:
- Around line 185-193: The HTML response in the error path of
server-middleware.ts currently injects the raw exception message (e.message)
into the <pre>, causing reflected XSS; update the error rendering inside the new
Response to never output unescaped user-controlled text by either replacing the
displayed message with a generic string (e.g., "Internal server error") or by
HTML-escaping the value first (add a small helper like escapeHtml and call it
where e or e.message is interpolated). Ensure you reference the same Response
construction site and the exception variable e so the template uses the
escaped/generic text instead of e.message directly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 42518d46-d3b2-436c-8ce5-3d554a2f3e68

📥 Commits

Reviewing files that changed from the base of the PR and between 4eed408 and e4d0a4e.

📒 Files selected for processing (8)
  • e2e/react-start/basic/package.json
  • e2e/react-start/basic/playwright.config.ts
  • e2e/react-start/custom-server-rsbuild/rsbuild.config.ts
  • packages/react-start/src/plugin/rsbuild.ts
  • packages/start-plugin-core/src/rsbuild/dev-server.ts
  • packages/start-plugin-core/src/rsbuild/plugin.ts
  • packages/start-plugin-core/src/rsbuild/schema.ts
  • packages/start-plugin-core/src/rsbuild/server-middleware.ts
💤 Files with no reviewable changes (1)
  • packages/start-plugin-core/src/rsbuild/dev-server.ts

Comment on lines 11 to 13
rsbuild: z
.object({ installDevServerMiddleware: z.boolean().optional() })
.object({ installServerMiddleware: z.boolean().optional() })
.optional(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the old option as a deprecated alias for one release.

This rename is currently a breaking change. Existing configs that still set rsbuild.installDevServerMiddleware will silently re-enable the middleware after upgrade, because only installServerMiddleware is recognized now. Please accept both keys for now and prefer the new one when both are present.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/start-plugin-core/src/rsbuild/schema.ts` around lines 11 - 13, The
rsbuild schema currently only accepts installServerMiddleware which breaks
configs using the old installDevServerMiddleware key; update the rsbuild zod
object to accept both installServerMiddleware and installDevServerMiddleware as
optional booleans, then normalize to a single canonical property (prefer
installServerMiddleware when both present) by adding a transform/preprocess so
downstream code uses only installServerMiddleware; mark
installDevServerMiddleware as deprecated in the schema/comments/types so it
remains supported for one release.

Comment thread packages/start-plugin-core/src/rsbuild/server-middleware.ts Outdated
# Conflicts:
#	packages/start-plugin-core/src/rsbuild/schema.ts
@nx-cloud
Copy link
Copy Markdown
Contributor

nx-cloud Bot commented May 24, 2026

View your CI Pipeline Execution ↗ for commit 0b3d961

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ❌ Failed 10m 3s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 2m 6s View ↗

☁️ Nx Cloud last updated this comment at 2026-05-25 06:30:47 UTC

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 24, 2026

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/@tanstack/arktype-adapter@7372

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/@tanstack/eslint-plugin-router@7372

@tanstack/eslint-plugin-start

npm i https://pkg.pr.new/@tanstack/eslint-plugin-start@7372

@tanstack/history

npm i https://pkg.pr.new/@tanstack/history@7372

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/@tanstack/nitro-v2-vite-plugin@7372

@tanstack/react-router

npm i https://pkg.pr.new/@tanstack/react-router@7372

@tanstack/react-router-devtools

npm i https://pkg.pr.new/@tanstack/react-router-devtools@7372

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/@tanstack/react-router-ssr-query@7372

@tanstack/react-start

npm i https://pkg.pr.new/@tanstack/react-start@7372

@tanstack/react-start-client

npm i https://pkg.pr.new/@tanstack/react-start-client@7372

@tanstack/react-start-rsc

npm i https://pkg.pr.new/@tanstack/react-start-rsc@7372

@tanstack/react-start-server

npm i https://pkg.pr.new/@tanstack/react-start-server@7372

@tanstack/router-cli

npm i https://pkg.pr.new/@tanstack/router-cli@7372

@tanstack/router-core

npm i https://pkg.pr.new/@tanstack/router-core@7372

@tanstack/router-devtools

npm i https://pkg.pr.new/@tanstack/router-devtools@7372

@tanstack/router-devtools-core

npm i https://pkg.pr.new/@tanstack/router-devtools-core@7372

@tanstack/router-generator

npm i https://pkg.pr.new/@tanstack/router-generator@7372

@tanstack/router-plugin

npm i https://pkg.pr.new/@tanstack/router-plugin@7372

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/@tanstack/router-ssr-query-core@7372

@tanstack/router-utils

npm i https://pkg.pr.new/@tanstack/router-utils@7372

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/@tanstack/router-vite-plugin@7372

@tanstack/solid-router

npm i https://pkg.pr.new/@tanstack/solid-router@7372

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/@tanstack/solid-router-devtools@7372

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/@tanstack/solid-router-ssr-query@7372

@tanstack/solid-start

npm i https://pkg.pr.new/@tanstack/solid-start@7372

@tanstack/solid-start-client

npm i https://pkg.pr.new/@tanstack/solid-start-client@7372

@tanstack/solid-start-server

npm i https://pkg.pr.new/@tanstack/solid-start-server@7372

@tanstack/start-client-core

npm i https://pkg.pr.new/@tanstack/start-client-core@7372

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/@tanstack/start-fn-stubs@7372

@tanstack/start-plugin-core

npm i https://pkg.pr.new/@tanstack/start-plugin-core@7372

@tanstack/start-server-core

npm i https://pkg.pr.new/@tanstack/start-server-core@7372

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/@tanstack/start-static-server-functions@7372

@tanstack/start-storage-context

npm i https://pkg.pr.new/@tanstack/start-storage-context@7372

@tanstack/valibot-adapter

npm i https://pkg.pr.new/@tanstack/valibot-adapter@7372

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/@tanstack/virtual-file-routes@7372

@tanstack/vue-router

npm i https://pkg.pr.new/@tanstack/vue-router@7372

@tanstack/vue-router-devtools

npm i https://pkg.pr.new/@tanstack/vue-router-devtools@7372

@tanstack/vue-router-ssr-query

npm i https://pkg.pr.new/@tanstack/vue-router-ssr-query@7372

@tanstack/vue-start

npm i https://pkg.pr.new/@tanstack/vue-start@7372

@tanstack/vue-start-client

npm i https://pkg.pr.new/@tanstack/vue-start-client@7372

@tanstack/vue-start-server

npm i https://pkg.pr.new/@tanstack/vue-start-server@7372

@tanstack/zod-adapter

npm i https://pkg.pr.new/@tanstack/zod-adapter@7372

commit: 0b3d961

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 24, 2026

Merging this PR will not alter performance

✅ 5 untouched benchmarks
⏩ 1 skipped benchmark1


Comparing elecmonkey:main (0b3d961) with main (a82cec6)

Open in CodSpeed

Footnotes

  1. 1 benchmark was skipped, so the baseline result was used instead. If it was deleted from the codebase, click here and archive it to remove it from the performance reports.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
e2e/react-start/basic/package.json (1)

31-31: 💤 Low value

Consider moving unrelated dependency updates to a separate PR.

The updates to tailwind-merge (line 31) and vite (line 49) appear unrelated to this PR's objective of supporting Rsbuild preview SSR middleware. While these updates might be routine maintenance, including them in this PR:

  • Complicates review by introducing additional risk surface
  • Makes it harder to isolate issues if problems arise
  • Obscures the PR's focused intent

Consider moving these dependency updates to a separate maintenance PR unless they are specifically required for the Rsbuild preview functionality.

Also applies to: 49-49

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/react-start/basic/package.json` at line 31, The change updates unrelated
dependencies ("tailwind-merge" and "vite") in package.json which should be
isolated; revert or remove the "tailwind-merge": "^3.6.0" and the updated "vite"
entry from this branch and move those dependency bumps into a separate
maintenance PR (or a dedicated commit) so this PR only contains the Rsbuild
preview SSR middleware changes; update package.json to the previous versions for
both the "tailwind-merge" and "vite" entries (or undo their edits) and ensure
package-lock / yarn.lock is regenerated in the separate PR if you re-apply the
bumps later.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@e2e/react-start/basic/package.json`:
- Line 31: The change updates unrelated dependencies ("tailwind-merge" and
"vite") in package.json which should be isolated; revert or remove the
"tailwind-merge": "^3.6.0" and the updated "vite" entry from this branch and
move those dependency bumps into a separate maintenance PR (or a dedicated
commit) so this PR only contains the Rsbuild preview SSR middleware changes;
update package.json to the previous versions for both the "tailwind-merge" and
"vite" entries (or undo their edits) and ensure package-lock / yarn.lock is
regenerated in the separate PR if you re-apply the bumps later.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 25c0ed05-ae70-447b-8ea2-299a69b91ca1

📥 Commits

Reviewing files that changed from the base of the PR and between 947911f and 7681919.

📒 Files selected for processing (2)
  • e2e/react-start/basic/package.json
  • packages/start-plugin-core/src/rsbuild/plugin.ts

@elecmonkey elecmonkey marked this pull request as draft May 25, 2026 02:29
@elecmonkey elecmonkey marked this pull request as ready for review May 25, 2026 02:54
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/start-plugin-core/src/rsbuild/server-middleware.ts (1)

157-181: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Return JSON 500s for server-function requests by route, not by request content-type.

This catch path is shared by page SSR and serverFnBase calls, but it only emits JSON when the request body is JSON. GET server functions and form posts can therefore fall through to next(e) and get an HTML error page instead of the response shape the client expects.

Possible fix
       } catch (e) {
         console.error('[tanstack-start] SSR error:', e)
 
+        const url = req.originalUrl ?? req.url ?? '/'
+        const isServerFnRequest =
+          url === serverFnBase || url.startsWith(`${serverFnBase}/`)
+
         const webReq = new NodeRequest({ req, res })
-        if (webReq.headers.get('content-type')?.includes('application/json')) {
+        if (
+          isServerFnRequest ||
+          webReq.headers.get('content-type')?.includes('application/json')
+        ) {
           return sendNodeResponse(
             res,
             new Response(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/start-plugin-core/src/rsbuild/server-middleware.ts` around lines 157
- 181, The current catch block in server-middleware uses the request
Content-Type to decide whether to return a JSON 500, which is wrong for
distinguishing SSR pages vs server-function calls; update the condition around
NodeRequest/new NodeRequest and sendNodeResponse so it detects server-function
routes instead of content-type (e.g., add or call an
isServerFunctionRequest(req|webReq) helper that checks the request path/method
against the server-function route pattern used by serverFnBase or your router),
and only emit the JSON error response for those server-function requests
(otherwise continue to return next(e) for regular SSR page errors).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/start-plugin-core/src/rsbuild/server-middleware.ts`:
- Around line 264-266: The current check in the middleware trims
publicBasePathname from pathname using pathname.startsWith(publicBasePathname),
which incorrectly matches sibling prefixes (e.g., "/app" matching "/app2");
update the predicate to only strip when pathname === publicBasePathname or when
pathname has publicBasePathname followed by a "/" boundary (e.g., pathname ===
publicBasePathname || pathname.startsWith(publicBasePathname + "/")), then
perform the slice as before (pathname =
pathname.slice(publicBasePathname.length) || '/'); also apply the same
boundary-aware predicate to the other code path that handles restorePreviewUrl
so both preview branches use identical logic.

---

Outside diff comments:
In `@packages/start-plugin-core/src/rsbuild/server-middleware.ts`:
- Around line 157-181: The current catch block in server-middleware uses the
request Content-Type to decide whether to return a JSON 500, which is wrong for
distinguishing SSR pages vs server-function calls; update the condition around
NodeRequest/new NodeRequest and sendNodeResponse so it detects server-function
routes instead of content-type (e.g., add or call an
isServerFunctionRequest(req|webReq) helper that checks the request path/method
against the server-function route pattern used by serverFnBase or your router),
and only emit the JSON error response for those server-function requests
(otherwise continue to return next(e) for regular SSR page errors).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8e40c862-cbdc-4f49-93c7-126237273b03

📥 Commits

Reviewing files that changed from the base of the PR and between 7681919 and 0b3d961.

📒 Files selected for processing (2)
  • packages/start-plugin-core/src/rsbuild/plugin.ts
  • packages/start-plugin-core/src/rsbuild/server-middleware.ts

Comment on lines +264 to +266
if (publicBasePathname !== '/' && pathname.startsWith(publicBasePathname)) {
pathname = pathname.slice(publicBasePathname.length) || '/'
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make public-base stripping path-segment aware.

pathname.startsWith(publicBasePathname) also matches sibling prefixes like /app2 when the configured public base is /app, so preview can resolve the wrong asset path. Require an exact match or a / boundary before trimming. If you touch this branch, it would be worth using the same predicate in restorePreviewUrl too so both preview code paths stay consistent.

Possible fix
-  if (publicBasePathname !== '/' && pathname.startsWith(publicBasePathname)) {
+  const hasPublicBasePrefix =
+    pathname === publicBasePathname ||
+    pathname.startsWith(`${publicBasePathname}/`)
+
+  if (publicBasePathname !== '/' && hasPublicBasePrefix) {
     pathname = pathname.slice(publicBasePathname.length) || '/'
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/start-plugin-core/src/rsbuild/server-middleware.ts` around lines 264
- 266, The current check in the middleware trims publicBasePathname from
pathname using pathname.startsWith(publicBasePathname), which incorrectly
matches sibling prefixes (e.g., "/app" matching "/app2"); update the predicate
to only strip when pathname === publicBasePathname or when pathname has
publicBasePathname followed by a "/" boundary (e.g., pathname ===
publicBasePathname || pathname.startsWith(publicBasePathname + "/")), then
perform the slice as before (pathname =
pathname.slice(publicBasePathname.length) || '/'); also apply the same
boundary-aware predicate to the other code path that handles restorePreviewUrl
so both preview branches use identical logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant