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,
} from "lucide-react";
import { InsightStatusCard } from "@/components/insights/insight-status-card";
import {
ScatterChart,
Scatter,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
} from "recharts";
// Recharts is ~108 KiB Brotli — defer-import the scatter primitives so they
// only land in the bundle once a correlation card actually renders. Every
// `<ResponsiveContainer>`/`<ScatterChart>`/`<Scatter>`/axis/grid/tooltip use
// site sits inside a `length >= 5` gate and is below the fold, so the first
// paint never waits on Recharts. v1.5 perf audit (docs/audit/v15-performance.md).
const ScatterChart = dynamic(
() => import("recharts").then((mod) => ({ default: mod.ScatterChart })),
{ ssr: false },
);
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 {
buildTrafficRange,