diff --git a/next.config.ts b/next.config.ts index 1d0afeba7c..517c438532 100644 --- a/next.config.ts +++ b/next.config.ts @@ -42,6 +42,7 @@ const nextConfig: NextConfig = { devIndicators: false, experimental: { cpus: 1, + optimizePackageImports: ["lucide-react"], }, poweredByHeader: false, turbopack: { diff --git a/src/app/documents/[id]/loading.tsx b/src/app/documents/[id]/loading.tsx new file mode 100644 index 0000000000..81ca711676 --- /dev/null +++ b/src/app/documents/[id]/loading.tsx @@ -0,0 +1,7 @@ +export default function Loading() { + return ( +
+
+
+ ); +} diff --git a/src/app/documents/[id]/page.tsx b/src/app/documents/[id]/page.tsx index 0950bc1fb1..17f79250aa 100644 --- a/src/app/documents/[id]/page.tsx +++ b/src/app/documents/[id]/page.tsx @@ -1,4 +1,4 @@ -import { DocumentViewer } from "@/components/DocumentViewer"; +import { DocumentViewerLazy as DocumentViewer } from "@/components/document-viewer-lazy"; export default async function DocumentPage({ params, diff --git a/src/app/loading.tsx b/src/app/loading.tsx new file mode 100644 index 0000000000..81ca711676 --- /dev/null +++ b/src/app/loading.tsx @@ -0,0 +1,7 @@ +export default function Loading() { + return ( +
+
+
+ ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx index 40d4f1a758..e6d9b98a0e 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,4 +1,4 @@ -import { ClinicalDashboard } from "@/components/clinical-dashboard"; +import { ClinicalDashboardLazy as ClinicalDashboard } from "@/components/clinical-dashboard-lazy"; import { isAppModeId, isAppModeVisible, type AppModeId } from "@/lib/app-modes"; type HomeProps = { diff --git a/src/components/ClinicalDashboard.tsx b/src/components/ClinicalDashboard.tsx index 45a17cf9df..e366a8467a 100644 --- a/src/components/ClinicalDashboard.tsx +++ b/src/components/ClinicalDashboard.tsx @@ -53,6 +53,7 @@ import { import { type CSSProperties, FormEvent, + memo, useCallback, useEffect, useMemo, @@ -509,7 +510,7 @@ function subscribeAuthEmail(onStoreChange: () => void) { }; } -function SourceImage({ +const SourceImage = memo(function SourceImage({ endpoint, caption, className = "max-h-52", @@ -609,7 +610,7 @@ function SourceImage({ className={cn(className, "w-full rounded-lg object-contain")} /> ); -} +}); function ScopeAndGovernanceNotice({ scope, diff --git a/src/components/clinical-dashboard-lazy.tsx b/src/components/clinical-dashboard-lazy.tsx new file mode 100644 index 0000000000..70bd7aafc0 --- /dev/null +++ b/src/components/clinical-dashboard-lazy.tsx @@ -0,0 +1,11 @@ +"use client"; + +import dynamic from "next/dynamic"; + +// `ssr: false` requires a Client Component in the App Router; this wrapper +// keeps the heavy dashboard bundle browser-only for the server-rendered +// home page. +export const ClinicalDashboardLazy = dynamic( + () => import("@/components/clinical-dashboard").then((m) => m.ClinicalDashboard), + { ssr: false }, +); diff --git a/src/components/document-viewer-lazy.tsx b/src/components/document-viewer-lazy.tsx new file mode 100644 index 0000000000..f910a6c2b7 --- /dev/null +++ b/src/components/document-viewer-lazy.tsx @@ -0,0 +1,10 @@ +"use client"; + +import dynamic from "next/dynamic"; + +// `ssr: false` requires a Client Component in the App Router; this wrapper +// keeps the viewer bundle browser-only for the server-rendered document page. +export const DocumentViewerLazy = dynamic( + () => import("@/components/DocumentViewer").then((m) => m.DocumentViewer), + { ssr: false }, +);