Add route code splitting and Vite vendor chunk splitting

This commit is contained in:
2026-04-20 19:53:56 +02:00
parent 27369b43d6
commit 1d6564aa32
3 changed files with 91 additions and 50 deletions

View File

@@ -19,7 +19,8 @@
* 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 { lightTheme } from "./theme/customTheme";
import { AuthProvider } from "./providers/AuthProvider";
@@ -28,15 +29,16 @@ import { RequireAuth } from "./components/RequireAuth";
import { SetupGuard } from "./components/SetupGuard";
import { ErrorBoundary } from "./components/ErrorBoundary";
import { MainLayout } from "./layouts/MainLayout";
import { SetupPage } from "./pages/SetupPage";
import { LoginPage } from "./pages/LoginPage";
import { DashboardPage } from "./pages/DashboardPage";
import { MapPage } from "./pages/MapPage";
import { JailsPage } from "./pages/JailsPage";
import { JailDetailPage } from "./pages/JailDetailPage";
import { ConfigPage } from "./pages/ConfigPage";
import { HistoryPage } from "./pages/HistoryPage";
import { BlocklistsPage } from "./pages/BlocklistsPage";
const SetupPage = lazy(() => import("./pages/SetupPage").then((m) => ({ default: m.SetupPage })));
const LoginPage = lazy(() => import("./pages/LoginPage").then((m) => ({ default: m.LoginPage })));
const DashboardPage = lazy(() => import("./pages/DashboardPage").then((m) => ({ default: m.DashboardPage })));
const MapPage = lazy(() => import("./pages/MapPage").then((m) => ({ default: m.MapPage })));
const JailsPage = lazy(() => import("./pages/JailsPage").then((m) => ({ default: m.JailsPage })));
const JailDetailPage = lazy(() => import("./pages/JailDetailPage").then((m) => ({ default: m.JailDetailPage })));
const ConfigPage = lazy(() => import("./pages/ConfigPage").then((m) => ({ default: m.ConfigPage })));
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.
@@ -46,48 +48,50 @@ function App(): React.JSX.Element {
<FluentProvider theme={lightTheme}>
<ErrorBoundary>
<BrowserRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>
<AuthProvider>
<Routes>
{/* Setup wizard — always accessible; redirects to /login if already done */}
<Route path="/setup" element={<SetupPage />} />
<Suspense fallback={<Spinner size="large" label="Loading…" />}>
<AuthProvider>
<Routes>
{/* Setup wizard — always accessible; redirects to /login if already done */}
<Route path="/setup" element={<SetupPage />} />
{/* Login — requires setup to be complete */}
<Route
path="/login"
element={
<SetupGuard>
<LoginPage />
</SetupGuard>
}
/>
{/* Login — requires setup to be complete */}
<Route
path="/login"
element={
<SetupGuard>
<LoginPage />
</SetupGuard>
}
/>
{/* Protected routes — require setup AND authentication */}
<Route
element={
<SetupGuard>
<RequireAuth>
<TimezoneProvider>
<MainLayout />
</TimezoneProvider>
</RequireAuth>
</SetupGuard>
}
>
<Route index element={<DashboardPage />} />
<Route path="/map" element={<MapPage />} />
<Route path="/jails" element={<JailsPage />} />
<Route path="/jails/:name" element={<JailDetailPage />} />
<Route path="/config" element={<ConfigPage />} />
<Route path="/history" element={<HistoryPage />} />
<Route path="/blocklists" element={<BlocklistsPage />} />
</Route>
{/* Protected routes — require setup AND authentication */}
<Route
element={
<SetupGuard>
<RequireAuth>
<TimezoneProvider>
<MainLayout />
</TimezoneProvider>
</RequireAuth>
</SetupGuard>
}
>
<Route index element={<DashboardPage />} />
<Route path="/map" element={<MapPage />} />
<Route path="/jails" element={<JailsPage />} />
<Route path="/jails/:name" element={<JailDetailPage />} />
<Route path="/config" element={<ConfigPage />} />
<Route path="/history" element={<HistoryPage />} />
<Route path="/blocklists" element={<BlocklistsPage />} />
</Route>
{/* Fallback — redirect unknown paths to dashboard */}
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</AuthProvider>
</BrowserRouter>
</ErrorBoundary>
{/* Fallback — redirect unknown paths to dashboard */}
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</AuthProvider>
</Suspense>
</BrowserRouter>
</ErrorBoundary>
</FluentProvider>
);
}

View File

@@ -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";
}
}
},
},
},
},
});