Add route code splitting and Vite vendor chunk splitting
This commit is contained in:
@@ -188,7 +188,7 @@ Issues are grouped by category and ordered roughly by severity. Each entry descr
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### TASK-010 — No code splitting: all pages bundled into the main chunk
|
### TASK-010 — No code splitting: all pages bundled into the main chunk (done)
|
||||||
|
|
||||||
**Where found:** `frontend/src/App.tsx` — all page imports are static (`import { DashboardPage } from "./pages/DashboardPage"`). `frontend/vite.config.ts` has no `build.rollupOptions.manualChunks`.
|
**Where found:** `frontend/src/App.tsx` — all page imports are static (`import { DashboardPage } from "./pages/DashboardPage"`). `frontend/vite.config.ts` has no `build.rollupOptions.manualChunks`.
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,8 @@
|
|||||||
* All unmatched paths redirect to `/`.
|
* All unmatched paths redirect to `/`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { FluentProvider } from "@fluentui/react-components";
|
import { lazy, Suspense } from "react";
|
||||||
|
import { FluentProvider, Spinner } from "@fluentui/react-components";
|
||||||
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
|
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
|
||||||
import { lightTheme } from "./theme/customTheme";
|
import { lightTheme } from "./theme/customTheme";
|
||||||
import { AuthProvider } from "./providers/AuthProvider";
|
import { AuthProvider } from "./providers/AuthProvider";
|
||||||
@@ -28,15 +29,16 @@ import { RequireAuth } from "./components/RequireAuth";
|
|||||||
import { SetupGuard } from "./components/SetupGuard";
|
import { SetupGuard } from "./components/SetupGuard";
|
||||||
import { ErrorBoundary } from "./components/ErrorBoundary";
|
import { ErrorBoundary } from "./components/ErrorBoundary";
|
||||||
import { MainLayout } from "./layouts/MainLayout";
|
import { MainLayout } from "./layouts/MainLayout";
|
||||||
import { SetupPage } from "./pages/SetupPage";
|
|
||||||
import { LoginPage } from "./pages/LoginPage";
|
const SetupPage = lazy(() => import("./pages/SetupPage").then((m) => ({ default: m.SetupPage })));
|
||||||
import { DashboardPage } from "./pages/DashboardPage";
|
const LoginPage = lazy(() => import("./pages/LoginPage").then((m) => ({ default: m.LoginPage })));
|
||||||
import { MapPage } from "./pages/MapPage";
|
const DashboardPage = lazy(() => import("./pages/DashboardPage").then((m) => ({ default: m.DashboardPage })));
|
||||||
import { JailsPage } from "./pages/JailsPage";
|
const MapPage = lazy(() => import("./pages/MapPage").then((m) => ({ default: m.MapPage })));
|
||||||
import { JailDetailPage } from "./pages/JailDetailPage";
|
const JailsPage = lazy(() => import("./pages/JailsPage").then((m) => ({ default: m.JailsPage })));
|
||||||
import { ConfigPage } from "./pages/ConfigPage";
|
const JailDetailPage = lazy(() => import("./pages/JailDetailPage").then((m) => ({ default: m.JailDetailPage })));
|
||||||
import { HistoryPage } from "./pages/HistoryPage";
|
const ConfigPage = lazy(() => import("./pages/ConfigPage").then((m) => ({ default: m.ConfigPage })));
|
||||||
import { BlocklistsPage } from "./pages/BlocklistsPage";
|
const HistoryPage = lazy(() => import("./pages/HistoryPage").then((m) => ({ default: m.HistoryPage })));
|
||||||
|
const BlocklistsPage = lazy(() => import("./pages/BlocklistsPage").then((m) => ({ default: m.BlocklistsPage })));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Root application component — mounts providers and top-level routes.
|
* Root application component — mounts providers and top-level routes.
|
||||||
@@ -46,48 +48,50 @@ function App(): React.JSX.Element {
|
|||||||
<FluentProvider theme={lightTheme}>
|
<FluentProvider theme={lightTheme}>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<BrowserRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>
|
<BrowserRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>
|
||||||
<AuthProvider>
|
<Suspense fallback={<Spinner size="large" label="Loading…" />}>
|
||||||
<Routes>
|
<AuthProvider>
|
||||||
{/* Setup wizard — always accessible; redirects to /login if already done */}
|
<Routes>
|
||||||
<Route path="/setup" element={<SetupPage />} />
|
{/* Setup wizard — always accessible; redirects to /login if already done */}
|
||||||
|
<Route path="/setup" element={<SetupPage />} />
|
||||||
|
|
||||||
{/* Login — requires setup to be complete */}
|
{/* Login — requires setup to be complete */}
|
||||||
<Route
|
<Route
|
||||||
path="/login"
|
path="/login"
|
||||||
element={
|
element={
|
||||||
<SetupGuard>
|
<SetupGuard>
|
||||||
<LoginPage />
|
<LoginPage />
|
||||||
</SetupGuard>
|
</SetupGuard>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Protected routes — require setup AND authentication */}
|
{/* Protected routes — require setup AND authentication */}
|
||||||
<Route
|
<Route
|
||||||
element={
|
element={
|
||||||
<SetupGuard>
|
<SetupGuard>
|
||||||
<RequireAuth>
|
<RequireAuth>
|
||||||
<TimezoneProvider>
|
<TimezoneProvider>
|
||||||
<MainLayout />
|
<MainLayout />
|
||||||
</TimezoneProvider>
|
</TimezoneProvider>
|
||||||
</RequireAuth>
|
</RequireAuth>
|
||||||
</SetupGuard>
|
</SetupGuard>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Route index element={<DashboardPage />} />
|
<Route index element={<DashboardPage />} />
|
||||||
<Route path="/map" element={<MapPage />} />
|
<Route path="/map" element={<MapPage />} />
|
||||||
<Route path="/jails" element={<JailsPage />} />
|
<Route path="/jails" element={<JailsPage />} />
|
||||||
<Route path="/jails/:name" element={<JailDetailPage />} />
|
<Route path="/jails/:name" element={<JailDetailPage />} />
|
||||||
<Route path="/config" element={<ConfigPage />} />
|
<Route path="/config" element={<ConfigPage />} />
|
||||||
<Route path="/history" element={<HistoryPage />} />
|
<Route path="/history" element={<HistoryPage />} />
|
||||||
<Route path="/blocklists" element={<BlocklistsPage />} />
|
<Route path="/blocklists" element={<BlocklistsPage />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
{/* Fallback — redirect unknown paths to dashboard */}
|
{/* Fallback — redirect unknown paths to dashboard */}
|
||||||
<Route path="*" element={<Navigate to="/" replace />} />
|
<Route path="*" element={<Navigate to="/" replace />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</BrowserRouter>
|
</Suspense>
|
||||||
</ErrorBoundary>
|
</BrowserRouter>
|
||||||
|
</ErrorBoundary>
|
||||||
</FluentProvider>
|
</FluentProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,4 +35,41 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
build: {
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
manualChunks(id: string) {
|
||||||
|
if (id.includes("/node_modules/")) {
|
||||||
|
if (
|
||||||
|
id.includes("/node_modules/react/") ||
|
||||||
|
id.includes("/node_modules/react-dom/") ||
|
||||||
|
id.includes("/node_modules/react-router-dom/")
|
||||||
|
) {
|
||||||
|
return "react-vendor";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
id.includes("/node_modules/@fluentui/") ||
|
||||||
|
id.includes("/node_modules/@griffel/") ||
|
||||||
|
id.includes("/node_modules/@radix-ui/")
|
||||||
|
) {
|
||||||
|
return "ui-vendor";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id.includes("/node_modules/recharts/")) {
|
||||||
|
return "chart-vendor";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
id.includes("/node_modules/d3-") ||
|
||||||
|
id.includes("/node_modules/topojson-client/") ||
|
||||||
|
id.includes("/node_modules/world-atlas/")
|
||||||
|
) {
|
||||||
|
return "geo-vendor";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user