Skip to content

Commit 99c67fe

Browse files
committed
Merge branch 'main' into refactor-router-core-skip-full-route-match-build-for-location-only-link
2 parents d0092a8 + d0b472e commit 99c67fe

File tree

158 files changed

+1285
-425
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

158 files changed

+1285
-425
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Flamegraph profiles
2+
**/cpu-profile-*.md
3+
**/cpu-profile-*.html
4+
**/cpu-profile-*.pb
5+
**/heap-profile-*.html
6+
**/heap-profile-*.pb
7+
**/heap-profile-*.md
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "tanstack-react-start-flamegraph-bench",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"build": "NODE_ENV=production vite build --mode=production",
7+
"start": "NODE_ENV=production node ./tests/server.js",
8+
"start:prof": "NODE_ENV=production flame run --md-format=detailed ./tests/server.js",
9+
"bench": "pnpm build && pnpm bench:run",
10+
"bench:run": "concurrently -k -s first \"pnpm start:prof\" \"sleep 3 && node ./tests/bench.js\""
11+
},
12+
"dependencies": {
13+
"@tanstack/react-router": "workspace:*",
14+
"@tanstack/react-start": "workspace:*",
15+
"express": "^4.21.2",
16+
"react": "^19.0.0",
17+
"react-dom": "^19.0.0",
18+
"srvx": "^0.10.0"
19+
},
20+
"devDependencies": {
21+
"@platformatic/flame": "latest",
22+
"@vitejs/plugin-react": "^4.3.4",
23+
"autocannon": "^8.0.0",
24+
"concurrently": "9.2.1",
25+
"typescript": "^5.7.2",
26+
"vite": "^7.3.1"
27+
}
28+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// <reference types="vite/client" />
2+
import { hydrateRoot } from 'react-dom/client'
3+
import { StartClient } from '@tanstack/react-start/client'
4+
5+
hydrateRoot(document, <StartClient />)
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/* eslint-disable */
2+
3+
// @ts-nocheck
4+
5+
// noinspection JSUnusedGlobalSymbols
6+
7+
// This file was automatically generated by TanStack Router.
8+
// You should NOT make any changes in this file as it will be overwritten.
9+
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
10+
11+
import { Route as rootRouteImport } from './routes/__root'
12+
import { Route as IndexRouteImport } from './routes/index'
13+
import { Route as PageIdRouteImport } from './routes/page.$id'
14+
15+
const IndexRoute = IndexRouteImport.update({
16+
id: '/',
17+
path: '/',
18+
getParentRoute: () => rootRouteImport,
19+
} as any)
20+
const PageIdRoute = PageIdRouteImport.update({
21+
id: '/page/$id',
22+
path: '/page/$id',
23+
getParentRoute: () => rootRouteImport,
24+
} as any)
25+
26+
export interface FileRoutesByFullPath {
27+
'/': typeof IndexRoute
28+
'/page/$id': typeof PageIdRoute
29+
}
30+
export interface FileRoutesByTo {
31+
'/': typeof IndexRoute
32+
'/page/$id': typeof PageIdRoute
33+
}
34+
export interface FileRoutesById {
35+
__root__: typeof rootRouteImport
36+
'/': typeof IndexRoute
37+
'/page/$id': typeof PageIdRoute
38+
}
39+
export interface FileRouteTypes {
40+
fileRoutesByFullPath: FileRoutesByFullPath
41+
fullPaths: '/' | '/page/$id'
42+
fileRoutesByTo: FileRoutesByTo
43+
to: '/' | '/page/$id'
44+
id: '__root__' | '/' | '/page/$id'
45+
fileRoutesById: FileRoutesById
46+
}
47+
export interface RootRouteChildren {
48+
IndexRoute: typeof IndexRoute
49+
PageIdRoute: typeof PageIdRoute
50+
}
51+
52+
declare module '@tanstack/react-router' {
53+
interface FileRoutesByPath {
54+
'/': {
55+
id: '/'
56+
path: '/'
57+
fullPath: '/'
58+
preLoaderRoute: typeof IndexRouteImport
59+
parentRoute: typeof rootRouteImport
60+
}
61+
'/page/$id': {
62+
id: '/page/$id'
63+
path: '/page/$id'
64+
fullPath: '/page/$id'
65+
preLoaderRoute: typeof PageIdRouteImport
66+
parentRoute: typeof rootRouteImport
67+
}
68+
}
69+
}
70+
71+
const rootRouteChildren: RootRouteChildren = {
72+
IndexRoute: IndexRoute,
73+
PageIdRoute: PageIdRoute,
74+
}
75+
export const routeTree = rootRouteImport
76+
._addFileChildren(rootRouteChildren)
77+
._addFileTypes<FileRouteTypes>()
78+
79+
import type { getRouter } from './router.tsx'
80+
import type { createStart } from '@tanstack/react-start'
81+
declare module '@tanstack/react-start' {
82+
interface Register {
83+
ssr: true
84+
router: Awaited<ReturnType<typeof getRouter>>
85+
}
86+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { createRouter } from '@tanstack/react-router'
2+
import { routeTree } from './routeTree.gen'
3+
4+
export function getRouter() {
5+
const router = createRouter({
6+
routeTree,
7+
scrollRestoration: true,
8+
})
9+
10+
return router
11+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import * as React from 'react'
2+
import {
3+
HeadContent,
4+
Outlet,
5+
Scripts,
6+
createRootRoute,
7+
} from '@tanstack/react-router'
8+
9+
export const Route = createRootRoute({
10+
component: RootComponent,
11+
})
12+
13+
function RootComponent() {
14+
return (
15+
<html>
16+
<head>
17+
<meta charSet="utf-8" />
18+
<meta name="viewport" content="width=device-width, initial-scale=1" />
19+
<title>Flamegraph Benchmark</title>
20+
<HeadContent />
21+
</head>
22+
<body>
23+
<Outlet />
24+
<Scripts />
25+
</body>
26+
</html>
27+
)
28+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Link, createFileRoute } from '@tanstack/react-router'
2+
3+
export const Route = createFileRoute('/')({
4+
component: IndexComponent,
5+
})
6+
7+
function IndexComponent() {
8+
return (
9+
<div>
10+
<h1 data-testid="page-title">Flamegraph Benchmark - Index</h1>
11+
<p>Navigate to any page to start:</p>
12+
<div>
13+
{Array.from({ length: 10 }, (_, i) => (
14+
<Link
15+
key={i}
16+
to="/page/$id"
17+
params={{ id: String(i) }}
18+
style={{ marginRight: '10px' }}
19+
>
20+
Page {i}
21+
</Link>
22+
))}
23+
</div>
24+
</div>
25+
)
26+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Link, createFileRoute } from '@tanstack/react-router'
2+
3+
export const Route = createFileRoute('/page/$id')({
4+
component: PageComponent,
5+
})
6+
7+
function PageComponent() {
8+
const { id } = Route.useParams()
9+
10+
// 100 links = 100 buildLocation calls during SSR
11+
return (
12+
<div>
13+
<h1 data-testid="page-title">Page {id}</h1>
14+
<div>
15+
{Array.from({ length: 100 }, (_, i) => (
16+
<Link
17+
key={i}
18+
to="/page/$id"
19+
params={{ id: String(i % 10) }}
20+
data-testid={`link-${i}`}
21+
style={{ display: 'block', margin: '2px 0' }}
22+
>
23+
Go to Page {i % 10}
24+
</Link>
25+
))}
26+
</div>
27+
</div>
28+
)
29+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import handler from '@tanstack/react-start/server-entry'
2+
3+
export default {
4+
fetch(request: Request) {
5+
return handler.fetch(request)
6+
},
7+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import autocannon from 'autocannon'
2+
3+
const BASE_URL = 'http://localhost:3000'
4+
5+
const instance = autocannon({
6+
url: BASE_URL,
7+
connections: 100, // concurrent connections
8+
duration: 30, // seconds
9+
pipelining: 1, // requests per connection
10+
requests: [
11+
{
12+
setupRequest: (req) => {
13+
// Pick a random page for each request
14+
const randomPage = '/page/' + Math.floor(Math.random() * 1000)
15+
return { ...req, path: randomPage }
16+
},
17+
},
18+
],
19+
})
20+
21+
autocannon.track(instance, { renderProgressBar: true })
22+
23+
instance.on('done', (results) => {
24+
console.log('\n=== SSR Benchmark Results ===')
25+
console.log(`Total requests: ${results.requests.total}`)
26+
console.log(`Requests/sec: ${results.requests.average}`)
27+
console.log(`Latency (avg): ${results.latency.average}ms`)
28+
console.log(`Latency (p99): ${results.latency.p99}ms`)
29+
console.log(
30+
`Throughput: ${(results.throughput.average / 1024 / 1024).toFixed(2)} MB/s`,
31+
)
32+
33+
if (results.errors) {
34+
console.log(`Errors: ${results.errors}`)
35+
}
36+
37+
// Exit after a short delay to allow the server profiler to finish
38+
setTimeout(() => process.exit(0), 1000)
39+
})

0 commit comments

Comments
 (0)