perf(charts): one shared async boundary for the whole recharts surface

Every next/dynamic chart import used to point at its own module, so
Turbopack emitted a separate chunk group per boundary — the production
build carried EIGHT ~312 KB copies of the recharts module graph, and
/insights (the worst-LCP route) downloaded two of them (~92 KB gz of
pure duplication, one fully unused at load).

All chart loaders now resolve the single chart-runtime barrel
(src/components/charts/chart-runtime.ts), which owns the only path to
recharts: one shared chunk group, recharts exists exactly once in the
build (verified: 8 -> 1 recharts-fingerprinted chunks), cached across
routes. Charts stay recharts and stay pixel-identical; every call site
keeps its own matching skeleton and ssr:false flag.

Riders of the same rule:
- the mood-trio barrel (mood-charts.ts, the v1.16.7 precedent this
  generalises) folds into the runtime and is removed
- the vitals sparkline body extracts to delta-sparkline.tsx and loads
  through the runtime; the tile keeps the fixed 40 px band, so the
  async gap is an identically-sized empty box
- /cycle's BBT chart (the last static recharts import on a live route)
  defers through the runtime with a card-matching skeleton

H3
This commit is contained in:
Marc-André Bombeck committed 2026-07-07 12:32:43 +02:00
1 parent 788aac5837
commit e260b2d5c4
20 files changed
+165 -74

No files matched your search

@@ -32,7 +32,7 @@ import { StatusItem, usePublicVersion, useSystemStatus } from "./_shared";
// working — same pattern the insights page uses for the scatter chart.
const HostMetricsChart = dynamic(
() =>
import("./host-metrics-chart").then((mod) => ({
import("@/components/charts/chart-runtime").then((mod) => ({
default: mod.HostMetricsChart,
})),
{