perf(insights): defer Recharts ScatterChart imports via next/dynamic

The insights page imported seven Recharts symbols (ScatterChart, Scatter,
XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer) eagerly at
module top, which pulled the entire ~108 KiB Brotli Recharts chunk onto
the initial bundle even though every scatter card sits inside a
`length >= 5` gate below the fold.

Switching each symbol to next/dynamic with `ssr: false` matches the
existing HealthChart / MoodChart pattern in the same file. Recharts is
still loaded once via the shared chunk graph the first time any scatter
section mounts; until then, /insights ships the same JS payload as
chart-free pages.

Verified static-only — local pnpm build is blocked by the documented
Node-25 turbopack regression. Full deltas captured in
docs/audit/v15-performance.md (v1.5 phase-4 perf audit).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.7 committed 2026-05-09 16:23:32 +02:00
1 parent 210f6105a7
commit bb2b1de742
1 file changed
+34 -9
+34 -9
View File
@@ -39,15 +39,40 @@ import {
TrendingUp, TrendingUp,
} from "lucide-react"; } from "lucide-react";
import { InsightStatusCard } from "@/components/insights/insight-status-card"; import { InsightStatusCard } from "@/components/insights/insight-status-card";
import { // Recharts is ~108 KiB Brotli — defer-import the scatter primitives so they
ScatterChart, // only land in the bundle once a correlation card actually renders. Every
Scatter, // `<ResponsiveContainer>`/`<ScatterChart>`/`<Scatter>`/axis/grid/tooltip use
XAxis, // site sits inside a `length >= 5` gate and is below the fold, so the first
YAxis, // paint never waits on Recharts. v1.5 perf audit (docs/audit/v15-performance.md).
CartesianGrid, const ScatterChart = dynamic(
Tooltip, () => import("recharts").then((mod) => ({ default: mod.ScatterChart })),
ResponsiveContainer, { ssr: false },
} from "recharts"; );
const Scatter = dynamic(
() => import("recharts").then((mod) => ({ default: mod.Scatter })),
{ ssr: false },
);
const XAxis = dynamic(
() => import("recharts").then((mod) => ({ default: mod.XAxis })),
{ ssr: false },
);
const YAxis = dynamic(
() => import("recharts").then((mod) => ({ default: mod.YAxis })),
{ ssr: false },
);
const CartesianGrid = dynamic(
() => import("recharts").then((mod) => ({ default: mod.CartesianGrid })),
{ ssr: false },
);
const Tooltip = dynamic(
() => import("recharts").then((mod) => ({ default: mod.Tooltip })),
{ ssr: false },
);
const ResponsiveContainer = dynamic(
() =>
import("recharts").then((mod) => ({ default: mod.ResponsiveContainer })),
{ ssr: false },
);
import { getBpTargets } from "@/lib/analytics/bp-targets"; import { getBpTargets } from "@/lib/analytics/bp-targets";
import { import {
buildTrafficRange, buildTrafficRange,