Skip to content

test: setting up a performance tracking CI#6756

Draft
Sheraff wants to merge 2 commits intomainfrom
test-performance-ci-setup
Draft

test: setting up a performance tracking CI#6756
Sheraff wants to merge 2 commits intomainfrom
test-performance-ci-setup

Conversation

@Sheraff
Copy link
Contributor

@Sheraff Sheraff commented Feb 24, 2026

we've had big performance focused pushes before, with a whole lot of benchmarking, graphs, measurements... but we don't have any form of long-term tracking. This PR proposes we set up something for the main 2 things:

  • SSR request throughput
  • client-side navigation

We're looking into using CodSpeed because we saw that tool on the rolldown repo, and it looks nice. And if they do in fact solve the noisy machine problem, then we can have some form of stable perf tracking.

SSR

For SSR so far we've been using autocannon and the working setup in e2e/react-start/flamegraph-bench to focus on a specific feature (link rendering, matching depth, raw baseline). This gives us a req/s number (main) as well as throughput and latency (secondaries).

For CodSpeed we can't really use autocannon (or i don't know how to). But we can take advantage of the fact that tanstack/start is "just a request handler" and just feed it Request objects directly. Do this inside a vitest bench and we can have a req/s stable metric. We'll need to feed some parallelism and not just "wait for one, send the next".

Client side

For client-side nav performance, we've been using

  • microbenchmarks on specific features, mostly not committed and used for dev only
  • playwright + a router that navigates automatically on useEffect to lower the impact of "headless piloting"
  • proxy metrics like the store-updates-during-navigation.test.tsx tests that measure re-renders, but that might become obsolete with signals and granular re-rendering

I think we can find a good middle ground using vitest bench and a DOM environment (probably jsdom? maybe browser mode?), and mounting a self-navigating router. Measure how much time it takes to navigate 100 routes and that should be a stable navigation latency metric.

Bundle size

We started teacking bundle size recently. Because it's the 3rd "big metric" we should look into colocating it with the other ones:

  • Is there a way to aggregate that inside codspeed too just for the sake of having a central dashboard?
  • Should it be the same github action as the performance stuff?
  • Can we move the code for it inside the new /benchmarks root too?

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 24, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR introduces a comprehensive client navigation benchmarking suite for TanStack Router across React, Solid, and Vue frameworks. It adds a GitHub Actions workflow for CodSpeed integration, benchmark implementations for each framework with shared utilities, Vitest configurations, and workspace/package configuration updates to enable benchmark execution via npm scripts.

Changes

Cohort / File(s) Summary
CI & Workspace Configuration
.github/workflows/codspeed.yml, pnpm-workspace.yaml, package.json
Added GitHub Actions workflow to run CodSpeed benchmarks via pnpm nx bench, expanded pnpm workspace to include benchmarks/* packages, and added root benchmark:client-nav npm script.
Benchmark Infrastructure
benchmarks/client-nav/package.json, benchmarks/client-nav/tsconfig.json, benchmarks/client-nav/shared.ts
Established benchmark workspace package with scripts, TypeScript configuration, and shared constants (LINK_COUNT, HOOK_COUNT, TARGET_ID) plus utility functions (heavySelect, parseIntOrZero) used across framework implementations.
React Benchmark
benchmarks/client-nav/react/client-nav.bench.tsx, benchmarks/client-nav/react/vitest.config.ts
Implemented React Router navigation benchmark creating route tree with root/nested routes, memory history initialization, programmatic navigation loop, and CodSpeed/Vitest integration.
Solid Benchmark
benchmarks/client-nav/solid/client-nav.bench.tsx, benchmarks/client-nav/solid/vitest.config.ts
Implemented Solid Router navigation benchmark with route tree, param/search validation, auto-navigation effect, and Solid-specific Vitest/CodSpeed configuration with inline dependency handling.
Vue Benchmark
benchmarks/client-nav/vue/client-nav.bench.ts, benchmarks/client-nav/vue/vitest.config.ts
Implemented Vue Router navigation benchmark with dynamic routes, memory history, mount/unmount lifecycle, and Vue-specific Vitest/CodSpeed configuration.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • schiller-manuel

Poem

🐰 Hops through benchmarks, three frameworks strong,
React, Solid, Vue all racing along,
From root to hundred IDs they bound,
Performance measured without a sound,
CodSpeed whispers what routers can do!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly reflects the main purpose of the changeset: setting up performance benchmarking infrastructure with CodSpeed CI integration across multiple frameworks.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch test-performance-ci-setup

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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

@nx-cloud
Copy link

nx-cloud bot commented Feb 24, 2026

View your CI Pipeline Execution ↗ for commit baa7b23

Command Status Duration Result
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1m 59s View ↗

☁️ Nx Cloud last updated this comment at 2026-02-25 18:28:45 UTC

@github-actions
Copy link

github-actions bot commented Feb 24, 2026

Bundle Size Benchmarks

  • Commit: 79b664e64410
  • Measured at: 2026-02-25T18:26:09.870Z
  • Baseline source: history:9a4161acff05
  • Dashboard: bundle-size history
Scenario Current (gzip) Delta vs baseline Raw Brotli Trend
react-router.minimal 86.57 KiB +37 B (+0.04%) 272.38 KiB 75.30 KiB █▁▁▁▁▁▁▁▁▁▃
react-router.full 89.60 KiB +47 B (+0.05%) 282.71 KiB 77.92 KiB █▁▁▁▁▁▁▁▁▁▃
solid-router.minimal 35.87 KiB +24 B (+0.07%) 107.49 KiB 32.26 KiB █▁▁▁▁▁▃▃▃▃▄
solid-router.full 40.20 KiB +24 B (+0.06%) 120.54 KiB 36.11 KiB █▁▁▂▂▂▃▃▃▃▄
vue-router.minimal 51.74 KiB +31 B (+0.06%) 147.46 KiB 46.49 KiB █▁▁▂▂▂▄▄▄▄▅
vue-router.full 56.53 KiB +20 B (+0.03%) 163.05 KiB 50.80 KiB █▁▁▁▁▁▂▂▂▂▃
react-start.minimal 99.10 KiB +21 B (+0.02%) 311.51 KiB 85.70 KiB █▁▁▁▁▁▁▁▁▁▂
react-start.full 102.47 KiB +53 B (+0.05%) 321.29 KiB 88.61 KiB █▁▁▁▁▁▁▁▁▁▃
solid-start.minimal 48.18 KiB +25 B (+0.05%) 145.06 KiB 42.59 KiB █▁▁▂▂▂▃▃▃▃▄
solid-start.full 53.66 KiB +41 B (+0.07%) 160.97 KiB 47.34 KiB █▁▁▁▁▁▃▃▃▃▄

Trend sparkline is historical gzip bytes ending with this PR measurement; lower is better.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 24, 2026

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@6756

@tanstack/eslint-plugin-router

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

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@6756

@tanstack/nitro-v2-vite-plugin

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

@tanstack/react-router

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

@tanstack/react-router-devtools

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

@tanstack/react-router-ssr-query

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

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@6756

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@6756

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@6756

@tanstack/router-cli

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

@tanstack/router-core

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

@tanstack/router-devtools

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

@tanstack/router-devtools-core

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

@tanstack/router-generator

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

@tanstack/router-plugin

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

@tanstack/router-ssr-query-core

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

@tanstack/router-utils

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

@tanstack/router-vite-plugin

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

@tanstack/solid-router

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

@tanstack/solid-router-devtools

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

@tanstack/solid-router-ssr-query

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

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@6756

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@6756

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@6756

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@6756

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-fn-stubs@6756

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@6756

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@6756

@tanstack/start-static-server-functions

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

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@6756

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@6756

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@6756

@tanstack/vue-router

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

@tanstack/vue-router-devtools

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

@tanstack/vue-router-ssr-query

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

@tanstack/vue-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start@6756

@tanstack/vue-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-client@6756

@tanstack/vue-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-server@6756

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@6756

commit: baa7b23

Copy link
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: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@benchmarks/client-nav/package.json`:
- Around line 11-14: The package.json dependencies use "workspace:^" for
internal TanStack packages; update the three dependency versions
"@tanstack/react-router", "@tanstack/solid-router", and "@tanstack/vue-router"
from "workspace:^" to "workspace:*" so they use the workspace protocol for
internal packages in benchmarks/client-nav/package.json.

In `@benchmarks/client-nav/react/client-nav.bench.tsx`:
- Around line 109-135: The Promise currently creates timeoutId and intervalId
inside its scope and only clears them when the interval observes the expected
href, leaving the interval running if the timeout fires and the cleanup() never
clears timers; move timeoutId and intervalId declarations to the outer scope
(above the new Promise) so both the timeout handler and the cleanup function can
access them, ensure the timeout handler clears the interval
(clearInterval(intervalId)) before rejecting, and update cleanup() to clear both
timers (clearTimeout(timeoutId) and clearInterval(intervalId)) in addition to
calling reactRoot.unmount() and container.remove().

In `@benchmarks/client-nav/solid/client-nav.bench.tsx`:
- Around line 117-142: The Promise-created timers (timeoutId and intervalId)
must be declared outside the Promise so cleanup can access them; update the done
Promise logic (which currently checks router.state.location.href against
expectedHref/TARGET_ID) so the timeout handler also clears the interval
(window.clearInterval) before rejecting, and ensure the cleanup function
(alongside dispose() and container.remove()) clears both timers with
null/undefined checks using window.clearTimeout(timeoutId) and
window.clearInterval(intervalId) to satisfy TypeScript strict mode; use the
existing symbols timeoutId, intervalId, done, cleanup, dispose, container.remove
and router.state.location.href to locate and modify the code.
- Around line 55-62: The mapped Link elements inside Array.from({ length:
LINK_COUNT }, (_, index) => ...) lack a key prop causing suboptimal list
reconciliation; update the mapping that returns the Link components (the Link
JSX in client-nav.bench.tsx) to include a stable key (e.g., key={index} or
key={String(index)}) using the index or id so Solid can properly track items
during rendering and improve performance.

In `@benchmarks/client-nav/vue/client-nav.bench.ts`:
- Around line 120-137: The timeout handler in the Promise created for navigation
benchmarking only rejects but doesn't clear the interval, causing the intervalId
to keep running; update the timeout callback (the function that uses timeoutId)
to call window.clearInterval(intervalId) before calling reject so that interval
polling (created for checking router.state.location.href against
expectedHref/TARGET_ID) is stopped when the timeout fires.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a4161a and 57af3b6.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • .github/workflows/codspeed.yml
  • benchmarks/client-nav/package.json
  • benchmarks/client-nav/react/client-nav.bench.tsx
  • benchmarks/client-nav/react/vitest.config.ts
  • benchmarks/client-nav/shared.ts
  • benchmarks/client-nav/solid/client-nav.bench.tsx
  • benchmarks/client-nav/solid/vitest.config.ts
  • benchmarks/client-nav/tsconfig.json
  • benchmarks/client-nav/vue/client-nav.bench.ts
  • benchmarks/client-nav/vue/vitest.config.ts
  • package.json
  • pnpm-workspace.yaml

@Sheraff Sheraff marked this pull request as draft February 24, 2026 22:40
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