From 11d0bd4a610ed3db2fc6dd04a90d16b59c156b7d Mon Sep 17 00:00:00 2001 From: Sheraff Date: Tue, 3 Mar 2026 18:42:56 +0100 Subject: [PATCH 1/2] test: client-nav benchmarks use a more representative app --- benchmarks/client-nav/react/app.tsx | 28 ++++++++++++---- benchmarks/client-nav/react/speed.bench.tsx | 7 ++-- benchmarks/client-nav/solid/app.tsx | 32 ++++++++++-------- benchmarks/client-nav/solid/speed.bench.tsx | 7 ++-- benchmarks/client-nav/vue/app.tsx | 36 ++++++++++++++------- benchmarks/client-nav/vue/speed.bench.tsx | 7 ++-- 6 files changed, 79 insertions(+), 38 deletions(-) diff --git a/benchmarks/client-nav/react/app.tsx b/benchmarks/client-nav/react/app.tsx index 113ba81b488..3435c9e1b15 100644 --- a/benchmarks/client-nav/react/app.tsx +++ b/benchmarks/client-nav/react/app.tsx @@ -6,6 +6,7 @@ import { createRootRoute, createRoute, createRouter, + useMatch, useParams, useSearch, } from '@tanstack/react-router' @@ -13,7 +14,7 @@ import { function runPerfSelectorComputation(seed: number) { let value = Math.trunc(seed) | 0 - for (let index = 0; index < 100; index++) { + for (let index = 0; index < 50; index++) { value = (value * 1664525 + 1013904223 + index) >>> 0 } @@ -23,21 +24,27 @@ function runPerfSelectorComputation(seed: number) { const selectors = Array.from({ length: 20 }, (_, index) => index) function Params() { - const params = useParams({ + const number = useParams({ strict: false, select: (params) => runPerfSelectorComputation(Number(params.id ?? 0)), }) - void params - return null + return runPerfSelectorComputation(number) } function Search() { - const search = useSearch({ + const number = useSearch({ strict: false, select: (search) => runPerfSelectorComputation(Number(search.id ?? 0)), }) - void search - return null + return runPerfSelectorComputation(number) +} + +function Match() { + const number = useMatch({ + strict: false, + select: (match) => runPerfSelectorComputation(Number(match.params.id ?? 0)), + }) + return runPerfSelectorComputation(number) } function Links() { @@ -60,6 +67,9 @@ function Root() { {selectors.map((selector) => ( ))} + {selectors.map((selector) => ( + + ))} ) @@ -72,7 +82,11 @@ const root = createRootRoute({ const route = createRoute({ getParentRoute: () => root, path: '/$id', + validateSearch: (search) => ({ id: search.id }), component: () =>
, + beforeLoad: () => Promise.resolve(), + loaderDeps: ({ search }) => ({ id: search.id }), + loader: () => Promise.resolve(), }) export function createTestRouter() { diff --git a/benchmarks/client-nav/react/speed.bench.tsx b/benchmarks/client-nav/react/speed.bench.tsx index 8b89db56fb8..76c99024659 100644 --- a/benchmarks/client-nav/react/speed.bench.tsx +++ b/benchmarks/client-nav/react/speed.bench.tsx @@ -27,10 +27,13 @@ describe('client-nav', () => { next = () => { const nextId = id++ + // update param every 2 navigations, + // update search every other navigation, + // this way we can test the impact of both params and search updates, + // and still observe improvements on granular re-rendering return navigate({ to: '/$id', - params: { id: nextId }, - // update search every 2 navigations, to still test them, but also measure the impact of granular re-rendering + params: { id: Math.floor((nextId + 1) / 2) }, search: { id: Math.floor(nextId / 2) }, replace: true, }) diff --git a/benchmarks/client-nav/solid/app.tsx b/benchmarks/client-nav/solid/app.tsx index 7f4fd05aa85..d102c82f8af 100644 --- a/benchmarks/client-nav/solid/app.tsx +++ b/benchmarks/client-nav/solid/app.tsx @@ -1,4 +1,4 @@ -import { For, createEffect } from 'solid-js' +import { For } from 'solid-js' import { Link, Outlet, @@ -7,6 +7,7 @@ import { createRootRoute, createRoute, createRouter, + useMatch, useParams, useSearch, } from '@tanstack/solid-router' @@ -14,7 +15,7 @@ import { function runPerfSelectorComputation(seed: number) { let value = Math.trunc(seed) | 0 - for (let index = 0; index < 100; index++) { + for (let index = 0; index < 50; index++) { value = (value * 1664525 + 1013904223 + index) >>> 0 } @@ -24,29 +25,27 @@ function runPerfSelectorComputation(seed: number) { const selectors = Array.from({ length: 20 }, (_, index) => index) function Params() { - const params = useParams({ + const number = useParams({ strict: false, select: (params) => runPerfSelectorComputation(Number(params.id ?? 0)), }) - - createEffect(() => { - void params() - }) - - return null + return runPerfSelectorComputation(number()) } function Search() { - const search = useSearch({ + const number = useSearch({ strict: false, select: (search) => runPerfSelectorComputation(Number(search.id ?? 0)), }) + return runPerfSelectorComputation(number()) +} - createEffect(() => { - void search() +function Match() { + const number = useMatch({ + strict: false, + select: (match) => runPerfSelectorComputation(Number(match.params.id ?? 0)), }) - - return null + return runPerfSelectorComputation(number()) } function Links() { @@ -63,6 +62,7 @@ function Root() { {() => } {() => } {() => } + {() => } ) @@ -75,9 +75,13 @@ const root = createRootRoute({ const route = createRoute({ getParentRoute: () => root, path: '/$id', + validateSearch: (search) => ({ id: search.id }), component: () => { return
}, + beforeLoad: () => Promise.resolve(), + loaderDeps: ({ search }) => ({ id: search.id }), + loader: () => Promise.resolve(), }) export function createTestRouter() { diff --git a/benchmarks/client-nav/solid/speed.bench.tsx b/benchmarks/client-nav/solid/speed.bench.tsx index 60790bea22f..6f809e648d7 100644 --- a/benchmarks/client-nav/solid/speed.bench.tsx +++ b/benchmarks/client-nav/solid/speed.bench.tsx @@ -32,10 +32,13 @@ describe('client-nav', () => { next = () => { const nextId = id++ + // update param every 2 navigations, + // update search every other navigation, + // this way we can test the impact of both params and search updates, + // and still observe improvements on granular re-rendering return navigate({ to: '/$id', - params: { id: nextId }, - // update search every 2 navigations, to still test them, but also measure the impact of granular re-rendering + params: { id: Math.floor((nextId + 1) / 2) }, search: { id: Math.floor(nextId / 2) }, replace: true, }) diff --git a/benchmarks/client-nav/vue/app.tsx b/benchmarks/client-nav/vue/app.tsx index 0e7d8eb3cdb..ef961d2f6c0 100644 --- a/benchmarks/client-nav/vue/app.tsx +++ b/benchmarks/client-nav/vue/app.tsx @@ -7,6 +7,7 @@ import { createRootRoute, createRoute, createRouter, + useMatch, useParams, useSearch, } from '@tanstack/vue-router' @@ -14,7 +15,7 @@ import { function runPerfSelectorComputation(seed: number) { let value = Math.trunc(seed) | 0 - for (let index = 0; index < 100; index++) { + for (let index = 0; index < 50; index++) { value = (value * 1664525 + 1013904223 + index) >>> 0 } @@ -25,29 +26,35 @@ const selectors = Array.from({ length: 20 }, (_, index) => index) const Params = Vue.defineComponent({ setup() { - const params = useParams({ + const number = useParams({ strict: false, select: (params) => runPerfSelectorComputation(Number(params.id ?? 0)), }) - return () => { - void params.value - return null - } + return () => runPerfSelectorComputation(number.value) }, }) const Search = Vue.defineComponent({ setup() { - const search = useSearch({ + const number = useSearch({ strict: false, select: (search) => runPerfSelectorComputation(Number(search.id ?? 0)), }) - return () => { - void search.value - return null - } + return () => runPerfSelectorComputation(number.value) + }, +}) + +const Match = Vue.defineComponent({ + setup() { + const number = useMatch({ + strict: false, + select: (match) => + runPerfSelectorComputation(Number(match.params.id ?? 0)), + }) + + return () => runPerfSelectorComputation(number.value) }, }) @@ -74,6 +81,9 @@ const Root = Vue.defineComponent({ {selectors.map((selector) => ( ))} + {selectors.map((selector) => ( + + ))} ) @@ -87,7 +97,11 @@ const root = createRootRoute({ const route = createRoute({ getParentRoute: () => root, path: '/$id', + validateSearch: (search) => ({ id: search.id }), component: () =>
, + beforeLoad: () => Promise.resolve(), + loaderDeps: ({ search }) => ({ id: search.id }), + loader: () => Promise.resolve(), }) export function createTestRouter() { diff --git a/benchmarks/client-nav/vue/speed.bench.tsx b/benchmarks/client-nav/vue/speed.bench.tsx index 9e4068f9751..ef67302f116 100644 --- a/benchmarks/client-nav/vue/speed.bench.tsx +++ b/benchmarks/client-nav/vue/speed.bench.tsx @@ -26,10 +26,13 @@ describe('client-nav', () => { next = () => { const nextId = id++ + // update param every 2 navigations, + // update search every other navigation, + // this way we can test the impact of both params and search updates, + // and still observe improvements on granular re-rendering return navigate({ to: '/$id', - params: { id: nextId }, - // update search every 2 navigations, to still test them, but also measure the impact of granular re-rendering + params: { id: Math.floor((nextId + 1) / 2) }, search: { id: Math.floor(nextId / 2) }, replace: true, }) From 016e842abfc145fa7396c7a6af996b02884c2d4f Mon Sep 17 00:00:00 2001 From: Sheraff Date: Tue, 3 Mar 2026 18:58:28 +0100 Subject: [PATCH 2/2] fix solid value tracking --- benchmarks/client-nav/solid/app.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/benchmarks/client-nav/solid/app.tsx b/benchmarks/client-nav/solid/app.tsx index d102c82f8af..9b85b2cbd5b 100644 --- a/benchmarks/client-nav/solid/app.tsx +++ b/benchmarks/client-nav/solid/app.tsx @@ -29,7 +29,7 @@ function Params() { strict: false, select: (params) => runPerfSelectorComputation(Number(params.id ?? 0)), }) - return runPerfSelectorComputation(number()) + return <>{runPerfSelectorComputation(number())} } function Search() { @@ -37,7 +37,7 @@ function Search() { strict: false, select: (search) => runPerfSelectorComputation(Number(search.id ?? 0)), }) - return runPerfSelectorComputation(number()) + return <>{runPerfSelectorComputation(number())} } function Match() { @@ -45,7 +45,7 @@ function Match() { strict: false, select: (match) => runPerfSelectorComputation(Number(match.params.id ?? 0)), }) - return runPerfSelectorComputation(number()) + return <>{runPerfSelectorComputation(number())} } function Links() {