FeaturesBlockManOSUpdated March 26, 2026
Route-level code splitting for the dashboard
Route-level code splitting for the dashboard
Released in v1.0.47 · PERF-01
What changed
All 15 dashboard pages now use next/dynamic to lazy-load their client components. Previously every page statically imported its client component, which caused the browser to download the JS for every dashboard feature on the first page load — even modules the user may never visit.
With route-level code splitting, each feature's JavaScript is delivered as a separate chunk and fetched only when the user navigates to that route.
How it works
Each dashboard page.tsx follows the same pattern:
import nextDynamic from "next/dynamic";
import { Skeleton } from "@/components/ui/skeleton";
const BudgetDashboardClient = nextDynamic(
() => import("./client").then((m) => ({ default: m.BudgetDashboardClient })),
{
ssr: false,
loading: () => (
<div className="space-y-4">
<Skeleton className="h-10 w-64" />
<Skeleton className="h-64 w-full" />
<Skeleton className="h-64 w-full" />
</div>
),
}
);
Key decisions
| Option | Value | Reason |
|---|---|---|
ssr | false | All dashboard components use useSession and tRPC hooks, which cannot run during server-side rendering |
.then((m) => ({ default: m.ExportName })) | Named → default re-export | next/dynamic requires a default export; this adapter pattern handles named exports correctly |
loading | <Skeleton /> placeholder | Shown instantly while the chunk is in-flight, preventing layout shift and giving immediate visual feedback |
Affected routes
| Route | Lazily loaded component |
|---|---|
/dashboard/budget | BudgetDashboardClient |
/dashboard/bank-reconciliation | BankReconciliationClient |
/dashboard/gdpr | GdprDashboardClient |
/dashboard/irish-legislation | IrishLegislationClient |
/dashboard/sinking-fund | SinkingFundClient |
/dashboard/agm | AgmClient |
/dashboard/communications | CommunicationsClient |
/dashboard/compliance | ComplianceDashboardClient |
/dashboard/maintenance | MaintenanceDashboardClient |
/dashboard/documents | DocumentsClient |
/dashboard/service-charges | ServiceChargeDashboardClient |
/dashboard/reports | ReportsDashboardClient |
/dashboard/ppm | PpmDashboardClient |
/dashboard/psra | PsraClient |
/dashboard/annual-plan | AnnualPlanClient |
Skeleton loading component
A new Skeleton UI component (@/components/ui/skeleton) was added to support the loading states. It renders animated placeholder shapes that match the rough layout of each dashboard page, displayed while the route chunk is fetching.
User experience
- First navigation to any dashboard route — the page shell renders immediately from the server; the Skeleton placeholder appears while the feature chunk loads; the full component mounts once the download completes.
- Subsequent navigations — chunks are cached by the browser and module system, so revisiting a route is instant.
- Users who never visit a route — never download its JavaScript bundle at all.