Skip to content

Commit 4a1fa86

Browse files
committed
fix(admin): move ssr:false dynamic charts to client module
Next 16 requires next/dynamic with ssr:false to be invoked inside a client component. Extract GrowthArea + CountBar into components/charts/lazy.tsx ('use client') and import from the server page.
1 parent 95d291f commit 4a1fa86

3 files changed

Lines changed: 40 additions & 34 deletions

File tree

apps/admin/next-env.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/// <reference types="next" />
22
/// <reference types="next/image-types/global" />
3-
import "./.next/dev/types/routes.d.ts";
3+
import "./.next/types/routes.d.ts";
44

55
// NOTE: This file should not be edited
66
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

apps/admin/src/app/[locale]/page.tsx

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,8 @@ import {
77
CardTitle,
88
} from "@starter-saas/ui/components/card";
99
import { Building2, CreditCard, TrendingUp, Users } from "lucide-react";
10-
import dynamic from "next/dynamic";
10+
import { CountBar, GrowthArea } from "@/components/charts/lazy";
1111
import { PageHeader } from "@/components/layout/page-header";
12-
13-
// Recharts is ~60kb gz and only runs in the browser — defer it off the
14-
// critical path so first-byte for admins doesn't ship the chart engine.
15-
const GrowthArea = dynamic(
16-
() =>
17-
import("@/components/charts/area-chart").then((m) => ({
18-
default: m.GrowthArea,
19-
})),
20-
{
21-
ssr: false,
22-
loading: () => <ChartSkeleton />,
23-
},
24-
);
25-
const CountBar = dynamic(
26-
() =>
27-
import("@/components/charts/bar-chart").then((m) => ({
28-
default: m.CountBar,
29-
})),
30-
{
31-
ssr: false,
32-
loading: () => <ChartSkeleton />,
33-
},
34-
);
35-
36-
function ChartSkeleton() {
37-
return (
38-
<div
39-
aria-hidden
40-
className="h-[260px] w-full animate-pulse rounded-md bg-muted/40"
41-
/>
42-
);
43-
}
4412
import {
4513
fetchAuditByAction,
4614
fetchKpis,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Client-side dynamic wrappers for the recharts components. Kept in a
2+
// dedicated client module so the dynamic-import + ssr:false escape hatch
3+
// is allowed (next/dynamic with ssr:false can only be called inside a
4+
// "use client" boundary).
5+
"use client";
6+
7+
import dynamic from "next/dynamic";
8+
9+
function ChartSkeleton() {
10+
return (
11+
<div
12+
aria-hidden
13+
className="h-[260px] w-full animate-pulse rounded-md bg-muted/40"
14+
/>
15+
);
16+
}
17+
18+
export const GrowthArea = dynamic(
19+
() =>
20+
import("@/components/charts/area-chart").then((m) => ({
21+
default: m.GrowthArea,
22+
})),
23+
{
24+
ssr: false,
25+
loading: () => <ChartSkeleton />,
26+
},
27+
);
28+
29+
export const CountBar = dynamic(
30+
() =>
31+
import("@/components/charts/bar-chart").then((m) => ({
32+
default: m.CountBar,
33+
})),
34+
{
35+
ssr: false,
36+
loading: () => <ChartSkeleton />,
37+
},
38+
);

0 commit comments

Comments
 (0)