Skip to content

fix: serve the SPA shell for ssr:false apps in rsbuild dev#76

Open
ScriptedAlchemy wants to merge 3 commits into
claude/peaceful-benz-6eae2bfrom
claude/musing-shaw-924569
Open

fix: serve the SPA shell for ssr:false apps in rsbuild dev#76
ScriptedAlchemy wants to merge 3 commits into
claude/peaceful-benz-6eae2bfrom
claude/musing-shaw-924569

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Collaborator

Problem

ssr: false (SPA mode) apps returned HTTP 404 for every route in rsbuild dev, including /. Two things combined to cause this:

  • setupMiddlewares skipped the dev request middleware whenever ssr: false (pluginOptions.customServer || !ssr ? [] : [...])
  • all web entries set html: false, so no HTML document existed in dev at all

Production worked because the SPA build prerenders an index.html shell — and the examples/spa-mode e2e suite only tested build + static serve, so this was never caught.

Fix

React Router's request handler natively supports ssr: false server builds: when build.ssr is false (and no prerender paths are configured) it renders the SPA shell for any document request — the same shell the production build prerenders into index.html. The dev server build (with isSpaMode: true) is already compiled by the node environment, which always exists. So the fix is to drop the !ssr exclusion and register the dev middleware for SPA mode too.

Unknown paths return the app shell with a 404 status, so the client-side error boundary renders — matching React Router's Vite dev behavior.

Tests

  • Unit test asserting the middleware is registered when ssr: false (tests/features.test.ts)
  • New dev-mode Playwright suite for examples/spa-mode (playwright.dev.config.ts + tests/e2e-dev/) covering /, deep links to nested routes, shell hydration data, and client-side navigation. Kept as a separate config because the dev server writes into the same build/ directory the static suite asserts against; test:e2e now runs both, so CI picks it up.
  • Full unit suite green (441 tests), both spa-mode e2e suites pass (15 static + 4 dev), tsc --noEmit clean.

Benchmarks

Removes the devRoutes: 'none' workaround on synthetic-256-spa added in #75, so benchmarks measure SPA dev route serving again. Also waits for the node environment (not just web) before fetching SPA dev routes, since route serving now goes through the server build — otherwise node compile time would be misattributed to route-fetch latency. Verified with a real run: all 8 dev route fetches return 200 (~20–165 ms), including the post-HMR-update fetch.

🤖 Generated with Claude Code

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@pkg-pr-new

pkg-pr-new Bot commented Jul 3, 2026

Copy link
Copy Markdown

Open in StackBlitz

pnpm add https://pkg.pr.new/rsbuild-plugin-react-router@e400982

commit: e400982

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR changes the rsbuild-plugin-react-router dev middleware setup so that dev-server middleware is registered whenever a custom server is not used, including SPA mode (ssr:false), rather than only when SSR is enabled. A corresponding unit test was added. Benchmark scripts (bench-builds.mts, profiles.mjs) were updated to reflect that SPA dev routes now require both web and node environments to be ready, removing the prior devRoutes: 'none' exemption. New Playwright dev-mode e2e configuration and tests were added for the SPA example, and its test:e2e script now runs both the default and dev-mode Playwright configurations.

Changes

Area Change
src/index.ts Always register dev-server middleware unless customServer is true, removing SSR gating
tests/features.test.ts New test asserting middleware registration in SPA mode
scripts/bench-builds.mts readyEnvironments unconditionally set to ['web','node']; comment updates
scripts/benchmark/profiles.mjs Removed devRoutes: 'none' from SPA profile
examples/spa-mode/playwright.dev.config.ts New Playwright config for dev-server e2e tests
examples/spa-mode/tests/e2e-dev/spa-mode-dev.test.ts New e2e suite for SPA dev-server behavior
examples/spa-mode/package.json test:e2e script runs both Playwright configs

Sequence Diagram(s)

sequenceDiagram
  participant Test as "spa-mode-dev.test.ts"
  participant DevServer as "rsbuild dev (port 3002)"
  Test->>DevServer: GET /
  DevServer-->>Test: HTML shell response
  Test->>DevServer: GET /about, /docs/getting-started
  DevServer-->>Test: HTML shell with hydration markers
  Test->>DevServer: Click link, navigate client-side
  DevServer-->>Test: Updated URL and heading
Loading

Estimated code review effort: 3/5 — Changes span core plugin logic, benchmark scripts, and new e2e test infrastructure, requiring verification of middleware behavior across SSR/SPA modes and benchmark correctness.

Related issues: None specified.

Related PRs: None specified.

Suggested labels: bug, testing, examples

Suggested reviewers: None specified.

🥕 A rabbit hopped through code so fine,
Turned on middleware for SPA's design,
No more 404s hiding in the dark,
Dev servers now hit their mark,
With tests and benchmarks all aligned!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Title check ✅ Passed The title clearly summarizes the main change: serving the SPA shell for ssr:false apps in rsbuild dev.
Description check ✅ Passed The description matches the changeset and accurately explains the bug, fix, tests, and benchmark updates.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/musing-shaw-924569

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
examples/spa-mode/tests/e2e-dev/spa-mode-dev.test.ts (1)

20-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Two independent route checks combined in one test.

This test validates /about and then separately navigates to /docs/getting-started within the same test case. If the /about assertion fails, the nested-route coverage never runs, and failure diagnostics conflate two unrelated route checks.

♻️ Split into separate test cases
-  test('serves the SPA shell for deep links', async ({ page }) => {
-    const response = await page.goto('/about');
-
-    expect(response?.status()).toBe(200);
-    await expect(page.locator('h1:has-text("About This Demo")')).toBeVisible();
-
-    // Nested routes resolve as document requests too.
-    await page.goto('/docs/getting-started');
-    await expect(
-      page.locator('h1:has-text("Getting Started")')
-    ).toBeVisible();
-  });
+  test('serves the SPA shell for deep links', async ({ page }) => {
+    const response = await page.goto('/about');
+
+    expect(response?.status()).toBe(200);
+    await expect(page.locator('h1:has-text("About This Demo")')).toBeVisible();
+  });
+
+  test('serves the SPA shell for nested routes', async ({ page }) => {
+    await page.goto('/docs/getting-started');
+    await expect(
+      page.locator('h1:has-text("Getting Started")')
+    ).toBeVisible();
+  });
🤖 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 `@examples/spa-mode/tests/e2e-dev/spa-mode-dev.test.ts` around lines 20 - 31,
The SPA deep-link coverage in test('serves the SPA shell for deep links')
combines two independent route checks, so split the /about assertion and the
/docs/getting-started assertion into separate test cases. Keep the existing
page.goto and expect checks, but isolate each route into its own test so
failures are independent and easier to diagnose.
🤖 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 `@examples/spa-mode/playwright.dev.config.ts`:
- Around line 29-34: The Playwright webServer setup is only probing the dev
port, so the SPA can still race before the compiler is ready. Update the
Playwright dev config by changing the readiness check in the webServer block for
the dev server command/url to wait for the actual dev-ready signal from rsbuild
rather than only checking http://localhost:3002, keeping the existing webServer
configuration structure intact.

In `@tests/features.test.ts`:
- Around line 36-49: Clear the global test stub after the SPA middleware test so
it does not leak into later cases. In the `should register the dev middleware
for SPA mode (ssr: false)` test, clean up `globalThis.__reactRouterTestConfig`
after `pluginReactRouter()`/`createStubRsbuild()` assertions, using the same
`__reactRouterTestConfig` symbol to reset the state and keep tests isolated.

---

Nitpick comments:
In `@examples/spa-mode/tests/e2e-dev/spa-mode-dev.test.ts`:
- Around line 20-31: The SPA deep-link coverage in test('serves the SPA shell
for deep links') combines two independent route checks, so split the /about
assertion and the /docs/getting-started assertion into separate test cases. Keep
the existing page.goto and expect checks, but isolate each route into its own
test so failures are independent and easier to diagnose.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2a8979cb-f831-4ede-81dd-dd2189270b5a

📥 Commits

Reviewing files that changed from the base of the PR and between c93ec98 and 629dd83.

📒 Files selected for processing (7)
  • examples/spa-mode/package.json
  • examples/spa-mode/playwright.dev.config.ts
  • examples/spa-mode/tests/e2e-dev/spa-mode-dev.test.ts
  • scripts/bench-builds.mts
  • scripts/benchmark/profiles.mjs
  • src/index.ts
  • tests/features.test.ts
💤 Files with no reviewable changes (1)
  • scripts/benchmark/profiles.mjs

Comment on lines +29 to +34
webServer: {
command: 'pnpm run dev --port 3002',
url: 'http://localhost:3002',
reuseExistingServer: !process.env.CI,
timeout: 120000,
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does rsbuild dev server's HTTP port become available before all configured environments (e.g. node) finish compiling?

💡 Result:

Yes, the Rsbuild development server's HTTP port becomes available before the compilation of all configured environments is finished [1]. When you start the Rsbuild dev server—either via the command line or the JavaScript API (e.g., rsbuild.startDevServer() or devServer.listen())—the server initializes and binds to its designated port independently of the compilation process [2][3][4]. The development server process does not wait for all internal build tasks or environment compilations to complete before it starts listening for requests [1]. Because the server starts listening before compilation is necessarily finished, accessing the server while initial builds are still in progress may result in compilation-related delays or "compiling" states being served to the client [1][5]. To programmatically detect when the development compilation has actually finished, you should use the onDevCompileDone hook rather than relying on the dev server's startup status [1]. If your workflow requires ensuring compilation is complete before proceeding (for instance, in testing or automation environments), it is recommended to listen for this specific hook [1]: rsbuild.onDevCompileDone( => { console.log('Compilation finished'); });

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the Playwright config and related benchmark/startup wait logic.
git ls-files 'examples/spa-mode/*' 'examples/**/playwright*.ts' 'examples/**/benchmark*' 'examples/**/wait*' 'examples/**/scripts*' | sed -n '1,200p'

echo '---'
# Inspect the target file with line numbers.
if [ -f examples/spa-mode/playwright.dev.config.ts ]; then
  cat -n examples/spa-mode/playwright.dev.config.ts
fi

echo '---'
# Search for readiness checks and environment waits in the repo.
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' \
  -e 'onDevCompileDone|wait.*node|wait.*web|webServer|reuseExistingServer|localhost:3002|benchmark' \
  examples . | sed -n '1,240p'

Repository: rstackjs/rsbuild-plugin-react-router

Length of output: 27141


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- SPA example docs / scripts ---'
sed -n '1,220p' examples/spa-mode/package.json
echo '---'
sed -n '1,220p' examples/spa-mode/README.md

echo '--- Search for startup/readiness hooks in SPA and benchmark scripts ---'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' \
  -e 'onDevCompileDone|wait.*compile|wait.*node|wait.*web|devBuild|loadBundle|startDevServer|listen\(' \
  examples/spa-mode scripts benchmarks .github/workflows/benchmark.yml tests | sed -n '1,260p'

Repository: rstackjs/rsbuild-plugin-react-router

Length of output: 15715


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- examples/spa-mode/rsbuild.config.ts ---'
cat -n examples/spa-mode/rsbuild.config.ts

echo '--- benchmarks/README.md excerpt ---'
sed -n '40,60p' benchmarks/README.md

echo '--- searches for spa-mode node environment / SSR toggles ---'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' \
  -e 'ssr:\s*false|environments:\s*\{|node:\s*\{|web:\s*\{' \
  examples/spa-mode examples/*/rsbuild.config.ts src tests | sed -n '1,260p'

Repository: rstackjs/rsbuild-plugin-react-router

Length of output: 8861


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- src/index.ts excerpt around SPA/dev environment setup ---'
sed -n '760,880p' src/index.ts

echo '--- tests/features.test.ts excerpt for SPA dev middleware ---'
sed -n '1,90p' tests/features.test.ts

echo '--- examples/spa-mode/tests/e2e-dev/spa-mode-dev.test.ts ---'
cat -n examples/spa-mode/tests/e2e-dev/spa-mode-dev.test.ts

Repository: rstackjs/rsbuild-plugin-react-router

Length of output: 9831


Add a startup wait before Playwright checks the dev server
webServer.url only probes that rsbuild dev is reachable; SPA dev still brings up the middleware and node environment asynchronously, so the first navigation can race compiler readiness. Use a readiness check that waits for the dev-ready signal instead of the bare port probe.

🤖 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 `@examples/spa-mode/playwright.dev.config.ts` around lines 29 - 34, The
Playwright webServer setup is only probing the dev port, so the SPA can still
race before the compiler is ready. Update the Playwright dev config by changing
the readiness check in the webServer block for the dev server command/url to
wait for the actual dev-ready signal from rsbuild rather than only checking
http://localhost:3002, keeping the existing webServer configuration structure
intact.

Comment thread tests/features.test.ts
Comment on lines +36 to +49
it('should register the dev middleware for SPA mode (ssr: false)', async () => {
(globalThis as { __reactRouterTestConfig?: unknown }).__reactRouterTestConfig =
{ ssr: false };
const rsbuild = await createStubRsbuild({
rsbuildConfig: {},
});

rsbuild.addPlugins([pluginReactRouter()]);
const config = await rsbuild.unwrapConfig();

expect(config.dev.setupMiddlewares).toHaveLength(1);
expect(config.dev.setupMiddlewares[0]).toBeInstanceOf(Function);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for cleanup of __reactRouterTestConfig in the test file
rg -n '__reactRouterTestConfig' tests/features.test.ts -B2 -A2

Repository: rstackjs/rsbuild-plugin-react-router

Length of output: 433


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the test file for any setup/teardown that clears the global stub,
# and show all references to the stub in context.
printf '\n== file outline ==\n'
wc -l tests/features.test.ts
printf '\n== cleanup hooks and stub references ==\n'
rg -n 'beforeEach|afterEach|beforeAll|afterAll|__reactRouterTestConfig|ssr:' tests/features.test.ts -B3 -A4

Repository: rstackjs/rsbuild-plugin-react-router

Length of output: 637


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for all uses of the stub and surrounding test structure in the file.
sed -n '1,220p' tests/features.test.ts | cat -n

Repository: rstackjs/rsbuild-plugin-react-router

Length of output: 9257


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the file sections around any before/after hooks and the later tests that
# may depend on the default SPA/SSR config.
rg -n 'beforeEach|afterEach|beforeAll|afterAll|__reactRouterTestConfig|pluginReactRouter\(' tests/features.test.ts -B4 -A8

Repository: rstackjs/rsbuild-plugin-react-router

Length of output: 5275


Clear __reactRouterTestConfig after this test The global stub is left behind as { ssr: false }, so later tests can inherit SPA mode and become order-dependent.

🤖 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 `@tests/features.test.ts` around lines 36 - 49, Clear the global test stub
after the SPA middleware test so it does not leak into later cases. In the
`should register the dev middleware for SPA mode (ssr: false)` test, clean up
`globalThis.__reactRouterTestConfig` after
`pluginReactRouter()`/`createStubRsbuild()` assertions, using the same
`__reactRouterTestConfig` symbol to reset the state and keep tests isolated.

@ScriptedAlchemy ScriptedAlchemy changed the base branch from main to claude/peaceful-benz-6eae2b July 3, 2026 21:11
@ScriptedAlchemy ScriptedAlchemy force-pushed the claude/musing-shaw-924569 branch from a5b36d5 to e400982 Compare July 3, 2026 21:11
@ScriptedAlchemy ScriptedAlchemy force-pushed the claude/peaceful-benz-6eae2b branch from b3c7fea to 7d2914b Compare July 3, 2026 21:30
ScriptedAlchemy and others added 3 commits July 3, 2026 21:33
SPA mode apps returned 404 for every route in dev because the plugin
skipped its dev middleware when ssr:false and all web entries disable
HTML generation, so no HTML document existed. React Router's request
handler natively renders the SPA shell for ssr:false builds, and the
dev server build (isSpaMode: true) is already compiled by the node
environment, so register the middleware for SPA mode too.

- Add a dev-mode Playwright suite to examples/spa-mode (separate
  config since the dev server writes into the build/ directory the
  static suite asserts against)
- Remove the devRoutes: 'none' benchmark override from PR #75 and
  wait for the node environment before fetching SPA dev routes, since
  route serving now depends on the server build

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review cleanup: derive playwright.dev.config.ts from the sibling static
config instead of copying it, reuse the testGlobal pattern in
features.test.ts, fold the hydration-payload assertions into the shell
test to drop a duplicate navigation, and remove the per-profile
benchmark devRoutes override mechanism now that nothing produces it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The benchmark harness waits for an explicit, caller-provided set of
dev environments (['web', 'node'] for every fixture variant — SPA dev
route serving goes through the node server build too, so 'node' must
be ready before route fetches). The ready-line pattern captures any
environment name, and a startup timeout now reports which expected
environments were still awaited vs. observed instead of hanging
silently.

Also aligns the SPA-mode feature test with the server.setup
registration that now includes ssr:false apps.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ScriptedAlchemy ScriptedAlchemy force-pushed the claude/musing-shaw-924569 branch from e400982 to b3fce8d Compare July 3, 2026 21:36
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

Compared PR head b3fce8d against base 7d2914b.

Dev Rollup

Group Fixtures Base total Head total Delta Base ready Head ready Ready delta Base routes Head routes Route delta Base update/HMR Head update/HMR Update delta Speedup
All dev fixtures 7 29.98s 29.38s -2.0% 19.87s 19.52s -1.8% 4.08s 4.06s -0.4% 3.30s 3.21s -2.5% 1.02x
Large app 1 14.10s 13.92s -1.3% 8.44s 8.45s +0.1% 2.02s 2.00s -0.8% 1.80s 1.79s -0.3% 1.01x
Standard fixtures 6 15.88s 15.46s -2.7% 11.43s 11.07s -3.2% 2.06s 2.06s -0.1% 1.49s 1.42s -5.2% 1.03x

Production Build Benchmarks

Rendered 7 production build benchmarks.

Benchmark Runs Base total Head total Delta Head mean Head p95 Speedup Head RSS p95
large-355-ssr-esm 5 8.77s 8.68s -1.0% 8.74s 9.01s 1.01x 1521 MB
synthetic-1024-ssr-esm 5 4.20s 4.15s -1.4% 4.19s 4.49s 1.01x 629 MB
synthetic-1024-ssr-esm-split 5 5.63s 5.62s -0.3% 5.65s 5.86s 1.00x 820 MB
synthetic-256-sourcemaps 10 2.17s 2.15s -0.9% 2.16s 2.28s 1.01x 438 MB
synthetic-256-ssr-esm 10 2.05s 2.04s -0.3% 2.06s 2.24s 1.00x 419 MB
synthetic-256-ssr-esm-split 10 2.47s 2.48s +0.3% 2.49s 2.61s 1.00x 440 MB
synthetic-48-ssr-esm 10 1.36s 1.35s -1.3% 1.37s 1.55s 1.01x 312 MB

full Dev Fixture Summary

Rendered 7 dev benchmark fixtures from the full profile.

Benchmark Runs Base total Head total Delta Base ready Head ready Base routes Head routes Base update/HMR Head update/HMR Update delta Head mean Head p95 Speedup Head RSS p95
large-355-ssr-esm 5 14.10s 13.92s -1.3% 8.44s 8.45s 2.02s 2.00s 1.80s 1.79s -0.3% 14.12s 15.28s 1.01x -
synthetic-1024-ssr-esm 5 4.65s 4.52s -2.7% 3.34s 3.21s 0.60s 0.59s 0.48s 0.48s -0.4% 4.51s 4.57s 1.03x -
synthetic-1024-ssr-esm-split 5 4.70s 4.55s -3.2% 3.39s 3.25s 0.61s 0.59s 0.51s 0.48s -5.3% 4.58s 4.69s 1.03x -
synthetic-256-sourcemaps 10 2.03s 2.00s -1.6% 1.51s 1.49s 0.25s 0.25s 0.15s 0.15s +0.2% 1.99s 2.07s 1.02x -
synthetic-256-ssr-esm 10 1.82s 1.75s -3.8% 1.27s 1.24s 0.23s 0.25s 0.15s 0.13s -17.0% 1.74s 1.78s 1.04x -
synthetic-256-ssr-esm-split 10 1.78s 1.76s -1.0% 1.27s 1.25s 0.24s 0.25s 0.15s 0.13s -15.5% 1.76s 1.82s 1.01x -
synthetic-48-ssr-esm 10 0.92s 0.89s -3.0% 0.66s 0.64s 0.13s 0.13s 0.05s 0.05s +0.2% 0.89s 0.92s 1.03x -

large-355-ssr-esm Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 1786 1693.0ms 1800.7ms +6.4% 1800.7ms 12.8ms 11
node route:module 1785 891.5ms 890.1ms -0.2% 890.1ms 6.0ms 10
web route:client-entry 1786 362.7ms 346.3ms -4.5% 346.3ms 5.3ms 11
node manifest:transform 5 122.3ms 161.9ms +32.4% 161.9ms 55.9ms 5
web manifest:stage 11 14.4ms 15.9ms +10.4% 15.9ms 1.9ms 11
web manifest:transform 5 0.5ms 0.5ms 0.0% 0.5ms 0.1ms 5

synthetic-1024-ssr-esm Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 5130 2096.7ms 2024.5ms -3.4% 2024.5ms 16.5ms 10
node route:module 5130 962.2ms 939.4ms -2.4% 939.4ms 6.9ms 10
web route:client-entry 5130 614.5ms 584.4ms -4.9% 584.4ms 5.9ms 10
node manifest:transform 5 215.0ms 241.8ms +12.5% 241.8ms 73.7ms 5
node module:client-only-stub 5 112.8ms 117.1ms +3.8% 117.1ms 41.8ms 5
web manifest:stage 10 54.3ms 51.1ms -5.9% 51.1ms 7.1ms 10
web manifest:transform 5 0.5ms 0.5ms 0.0% 0.5ms 0.1ms 5

synthetic-1024-ssr-esm-split Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 5130 2072.6ms 2031.8ms -2.0% 2031.8ms 18.2ms 10
node route:module 5130 956.6ms 924.8ms -3.3% 924.8ms 5.2ms 10
web route:client-entry 5130 632.0ms 658.2ms +4.1% 658.2ms 7.1ms 10
node manifest:transform 5 195.8ms 216.2ms +10.4% 216.2ms 47.9ms 5
node module:client-only-stub 5 82.6ms 338.5ms +309.8% 338.5ms 194.3ms 5
web manifest:stage 10 54.8ms 51.4ms -6.2% 51.4ms 8.2ms 10
web manifest:transform 5 0.5ms 0.5ms 0.0% 0.5ms 0.1ms 5

synthetic-256-sourcemaps Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 2581 1433.2ms 1451.3ms +1.3% 1451.3ms 21.0ms 21
node route:module 2580 600.7ms 614.5ms +2.3% 614.5ms 4.6ms 20
web route:client-entry 2581 404.3ms 406.3ms +0.5% 406.3ms 5.8ms 21
node module:client-only-stub 10 229.9ms 153.4ms -33.3% 153.4ms 41.5ms 10
node manifest:transform 10 160.4ms 160.1ms -0.2% 160.1ms 20.9ms 10
web manifest:stage 21 21.9ms 21.3ms -2.7% 21.3ms 1.4ms 21
web manifest:transform 10 1.0ms 1.0ms 0.0% 1.0ms 0.1ms 10

synthetic-256-ssr-esm Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 2581 1349.3ms 1418.8ms +5.2% 1418.8ms 17.9ms 21
node route:module 2580 578.6ms 548.0ms -5.3% 548.0ms 4.3ms 20
web route:client-entry 2581 382.9ms 421.6ms +10.1% 421.6ms 5.7ms 21
node manifest:transform 10 150.4ms 153.3ms +1.9% 153.3ms 20.2ms 10
node module:client-only-stub 10 66.1ms 147.4ms +123.0% 147.4ms 66.0ms 10
web manifest:stage 21 23.0ms 21.5ms -6.5% 21.5ms 1.4ms 21
web manifest:transform 10 1.0ms 1.0ms 0.0% 1.0ms 0.1ms 10

synthetic-256-ssr-esm-split Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 2584 1349.5ms 1445.3ms +7.1% 1445.3ms 22.7ms 24
node route:module 2580 550.8ms 565.2ms +2.6% 565.2ms 4.5ms 20
web route:client-entry 2584 378.2ms 397.7ms +5.2% 397.7ms 6.5ms 24
node module:client-only-stub 10 238.4ms 237.7ms -0.3% 237.7ms 95.9ms 10
node manifest:transform 10 179.9ms 180.0ms +0.1% 180.0ms 24.9ms 10
web manifest:stage 24 22.3ms 23.8ms +6.7% 23.8ms 1.4ms 24
web manifest:transform 10 1.0ms 1.0ms 0.0% 1.0ms 0.1ms 10

synthetic-48-ssr-esm Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 500 501.7ms 436.6ms -13.0% 436.6ms 9.0ms 20
node route:module 500 168.7ms 160.2ms -5.0% 160.2ms 4.4ms 20
web route:client-entry 500 104.3ms 118.1ms +13.2% 118.1ms 3.4ms 20
node module:client-only-stub 10 76.0ms 86.0ms +13.2% 86.0ms 12.6ms 10
node manifest:transform 10 58.1ms 59.8ms +2.9% 59.8ms 6.8ms 10
web manifest:stage 20 5.2ms 5.5ms +5.8% 5.5ms 0.4ms 20
web manifest:transform 10 1.0ms 1.0ms 0.0% 1.0ms 0.1ms 10

Synthetic Rsbuild App

Rendered 2 production build benchmarks.

Benchmark Runs Base total Head total Delta Head mean Head p95 Speedup Head RSS p95
complex app 2 113.82s 119.49s +5.0% 119.49s - 0.95x -
complex app 2 78.83s 83.24s +5.6% 83.24s - 0.95x -

Rendered 1 dev benchmark fixture from the embedded complex app.

Benchmark Runs Base total Head total Delta Base ready Head ready Base routes Head routes Base update/HMR Head update/HMR Update delta Head mean Head p95 Speedup Head RSS p95
complex app 2 100.09s 103.78s +3.7% 91.02s 94.65s 3.00s 2.97s 3.38s 3.51s +3.7% 103.78s - 0.96x -

Profile: full; mode: dev; iterations: 10; warmup: 0.
The uploaded benchmark artifact includes diagnostics/summary.md and diagnostics/summary.json with runner metadata, per-run timing samples, CPU/RSS samples, and plugin timing hot spots.
Workflow run

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant