Skip to content

Commit b9bd9e5

Browse files
Added SPA Charts to other Page (#182)
1 parent 6080034 commit b9bd9e5

6 files changed

Lines changed: 115 additions & 12 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
import MethodologyNotes from '../components/MethodologyNotes.astro'
3+
---
4+
5+
<MethodologyNotes>
6+
<li>Each framework renders a table of 1000 rows with two UUID columns</li>
7+
<li>
8+
Measured using Lighthouse flow with Chromium via Puppeteer for accurate
9+
browser metrics
10+
</li>
11+
<li>
12+
First Paint and First Contentful Paint are measured on initial navigation
13+
</li>
14+
<li>
15+
Interaction to Next Paint is measured by clicking the first row's detail
16+
link
17+
</li>
18+
<li>Benchmarks run 5 times and results are averaged</li>
19+
<li>
20+
Next.js, TanStack Start, and React Router default to SSR with no per-route
21+
opt-out. Next.js wraps the SPA table in a <code>dynamic</code> import with <code
22+
>ssr: false</code
23+
> to prevent build-time prerendering. TanStack Start uses its built-in spa mode.
24+
React Router disables SSR entirely via <code>ssr: false</code> in its config.
25+
All other frameworks (Nuxt, SvelteKit, SolidStart, Astro) disable SSR per-route
26+
without a separate build.
27+
</li>
28+
</MethodologyNotes>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
import { spaStats } from '../lib/collections'
3+
import { getFrameworkSlug } from '../lib/utils'
4+
import MethodologyTag from './MethodologyTag.astro'
5+
import StatsTable from './StatsTable.astro'
6+
7+
const columns = [
8+
{
9+
key: 'name',
10+
header: 'Framework',
11+
nameCell: true,
12+
href: (row: Record<string, unknown>) =>
13+
row.package !== 'app-baseline-html'
14+
? `/framework/${getFrameworkSlug(row.package as string)}`
15+
: null,
16+
},
17+
{ key: 'spaFirstPaintMs', header: 'First Paint' },
18+
{ key: 'spaFCPMs', header: 'FCP' },
19+
{ key: 'spaINPMs', header: 'INP' },
20+
]
21+
22+
const tableData = spaStats
23+
---
24+
25+
<MethodologyTag>
26+
Measured on GitHub Actions (ubuntu-latest, Node 24) using Lighthouse flow with
27+
Chromium.
28+
</MethodologyTag>
29+
<StatsTable
30+
label="SPA performance by framework"
31+
columns={columns}
32+
data={tableData}
33+
/>

packages/docs/src/lib/collections.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { getCollection } from 'astro:content'
22
import { formatBytesToMB, formatTimeMs } from './utils'
33

44
const devtimeEntries = await getCollection('devtime')
5-
const runtimeEntries = await getCollection('runtime')
5+
export const runtimeEntries = await getCollection('runtime')
66

77
export const starterStats = devtimeEntries
88
.map((entry) => entry.data)
@@ -12,6 +12,19 @@ const ssrStats = runtimeEntries
1212
.map((entry) => entry.data)
1313
.sort((a, b) => a.order - b.order)
1414

15+
const spaStats = runtimeEntries
16+
.map((entry) => entry.data)
17+
.sort((a, b) => a.order - b.order)
18+
.filter((f) => f?.name != null && Number.isFinite(f.spaFirstPaintMs))
19+
.map((f) => ({
20+
name: f.name,
21+
package: f.package,
22+
isFocused: f.isFocused,
23+
spaFirstPaintMs: `${f.spaFirstPaintMs}ms`,
24+
spaFCPMs: `${f.spaFCPMs}ms`,
25+
spaINPMs: `${f.spaINPMs}ms`,
26+
}))
27+
1528
const depsStats = starterStats.map((f) => ({
1629
name: f.name,
1730
package: f.package,
@@ -87,4 +100,4 @@ export const coreJsTableData = starterStats.map((f) => {
87100
}
88101
})
89102

90-
export { ssrStats, depsStats, buildInstallData }
103+
export { ssrStats, spaStats, depsStats, buildInstallData }

packages/docs/src/pages/framework/[slug].astro

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import BackLink from '../../components/BackLink.astro'
44
import DevTimeChart from '../../components/DevTimeChart.astro'
55
import MethodologyTag from '../../components/MethodologyTag.astro'
66
import PageHeader from '../../components/PageHeader.astro'
7+
import SPAStatsMethodologyNotes from '../../components/SPAStatsMethodologyNotes.astro'
78
import SSRStatsMethodologyNotes from '../../components/SSRStatsMethodologyNotes.astro'
89
import StatsTable from '../../components/StatsTable.astro'
910
import Layout from '../../layouts/Layout.astro'
@@ -164,6 +165,24 @@ const ssrData = [
164165
]
165166
: []),
166167
]
168+
169+
const spaColumns = [
170+
{ key: 'name', header: 'Framework', nameCell: true },
171+
{ key: 'spaFirstPaintMs', header: 'First Paint' },
172+
{ key: 'spaFCPMs', header: 'FCP' },
173+
{ key: 'spaINPMs', header: 'INP' },
174+
]
175+
176+
const spaData = runtime
177+
? [
178+
{
179+
name: runtime.name,
180+
spaFirstPaintMs: `${runtime.spaFirstPaintMs}ms`,
181+
spaFCPMs: `${runtime.spaFCPMs}ms`,
182+
spaINPMs: `${runtime.spaINPMs}ms`,
183+
},
184+
]
185+
: []
167186
---
168187

169188
<Layout title={`${devtime.name} — Framework Tracker`}>
@@ -303,6 +322,17 @@ const ssrData = [
303322
data={ssrData}
304323
/>
305324
<SSRStatsMethodologyNotes />
325+
<h3>SPA Performance</h3>
326+
<MethodologyTag>
327+
Measured on GitHub Actions (ubuntu-latest, Node 24) using Lighthouse
328+
flow with Chromium.
329+
</MethodologyTag>
330+
<StatsTable
331+
label="SPA performance"
332+
columns={spaColumns}
333+
data={spaData}
334+
/>
335+
<SPAStatsMethodologyNotes />
306336
</>
307337
)
308338
}

packages/docs/src/pages/index.astro

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import DetailsLink from '../components/DetailsLink.astro'
88
import FocusedToggle from '../components/FocusedToggle.astro'
99
import PageHeader from '../components/PageHeader.astro'
1010
import SPACharts from '../components/SPACharts.astro'
11+
import SPAStatsTable from '../components/SPAStatsTable.astro'
1112
import SSRCharts from '../components/SSRCharts.astro'
1213
import SSRStatsTable from '../components/SSRStatsTable.astro'
1314
import Layout from '../layouts/Layout.astro'
@@ -58,20 +59,11 @@ import Layout from '../layouts/Layout.astro'
5859
/>
5960
<h2>Runtime Performance</h2>
6061
<h3>SSR Performance</h3>
61-
<SSRStatsTable />
6262
<SSRCharts />
6363
<DetailsLink href="/run-time#ssr-performance" label="SSR in Run Time Stats" />
6464
<h3>SPA Performance</h3>
6565
<SPACharts />
66-
<p class="methodology-note">
67-
Next.js, TanStack Start, and React Router default to SSR with no per-route
68-
opt-out. Next.js wraps the SPA table in a <code>dynamic</code> import with <code
69-
>ssr: false</code
70-
> to prevent build-time prerendering. TanStack Start uses its built-in spa mode.
71-
React Router disables SSR entirely via <code>ssr: false</code> in its config.
72-
All other frameworks (Nuxt, SvelteKit, SolidStart, Astro) disable SSR per-route
73-
without a separate build.
74-
</p>
66+
<DetailsLink href="/run-time#spa-performance" label="SPA in Run Time Stats" />
7567
</Layout>
7668

7769
<style>

packages/docs/src/pages/run-time.astro

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
---
22
import FocusedToggle from '../components/FocusedToggle.astro'
33
import PageHeader from '../components/PageHeader.astro'
4+
import SPACharts from '../components/SPACharts.astro'
5+
import SPAStatsMethodologyNotes from '../components/SPAStatsMethodologyNotes.astro'
6+
import SPAStatsTable from '../components/SPAStatsTable.astro'
47
import SSRStatsMethodologyNotes from '../components/SSRStatsMethodologyNotes.astro'
58
import SSRStatsTable from '../components/SSRStatsTable.astro'
69
import Layout from '../layouts/Layout.astro'
@@ -12,4 +15,8 @@ import Layout from '../layouts/Layout.astro'
1215
<h2 id="ssr-performance">SSR Performance</h2>
1316
<SSRStatsTable />
1417
<SSRStatsMethodologyNotes />
18+
<h2 id="spa-performance">SPA Performance</h2>
19+
<SPACharts />
20+
<SPAStatsTable />
21+
<SPAStatsMethodologyNotes />
1522
</Layout>

0 commit comments

Comments
 (0)