perf: code-split routes — client delivery page loads 34KB chunk instead of 932KB bundle

- lazy-load all pages via React.lazy + Suspense
- client-facing pages (SMS links) no longer pull DashboardPage (605KB) and admin panels
- fixes 30-40s loads on slow mobile connections (Crimea customers)
This commit is contained in:
Hermes 2026-08-19 10:58:39 +02:00
parent c62606b09d
commit 5ca9bd7ebf
1 changed files with 63 additions and 19 deletions

View File

@ -1,17 +1,61 @@
import React from "react"; import React from "react";
import { Navigate, createBrowserRouter, useParams } from "react-router-dom"; import { Navigate, createBrowserRouter, useParams } from "react-router-dom";
import App from "./App"; import App from "./App";
import { ClientDeliveryPage } from "./pages/ClientDeliveryPage";
import { ClientTestPage } from "./pages/ClientTestPage";
import { ClientTestConsentPage } from "./pages/ClientTestConsentPage";
import { DashboardPage } from "./pages/DashboardPage";
import { GroupDetailPage } from "./pages/GroupDetailPage";
import { LoginPage } from "./pages/LoginPage";
import { NotFoundPage } from "./pages/NotFoundPage";
import { ForbiddenPage } from "./pages/ForbiddenPage";
import { SettingsPage } from "./pages/SettingsPage";
import { useAuth } from "./context/AuthContext"; import { useAuth } from "./context/AuthContext";
/**
* Code-splitting: client-facing pages (opened from SMS links on mobile) load a
* small chunk instead of the full 932KB bundle that includes the staff
* dashboard, admin panels, etc. This fixes 30-40s loads on slow mobile
* connections (customers in Crimea opening delivery links).
*
* Staff pages are also lazy so the login page stays light.
*/
const ClientDeliveryPage = React.lazy(() =>
import("./pages/ClientDeliveryPage").then((m) => ({ default: m.ClientDeliveryPage }))
);
const ClientTestPage = React.lazy(() =>
import("./pages/ClientTestPage").then((m) => ({ default: m.ClientTestPage }))
);
const ClientTestConsentPage = React.lazy(() =>
import("./pages/ClientTestConsentPage").then((m) => ({ default: m.ClientTestConsentPage }))
);
const DashboardPage = React.lazy(() =>
import("./pages/DashboardPage").then((m) => ({ default: m.DashboardPage }))
);
const GroupDetailPage = React.lazy(() =>
import("./pages/GroupDetailPage").then((m) => ({ default: m.GroupDetailPage }))
);
const LoginPage = React.lazy(() =>
import("./pages/LoginPage").then((m) => ({ default: m.LoginPage }))
);
const NotFoundPage = React.lazy(() =>
import("./pages/NotFoundPage").then((m) => ({ default: m.NotFoundPage }))
);
const ForbiddenPage = React.lazy(() =>
import("./pages/ForbiddenPage").then((m) => ({ default: m.ForbiddenPage }))
);
const SettingsPage = React.lazy(() =>
import("./pages/SettingsPage").then((m) => ({ default: m.SettingsPage }))
);
const PageLoader = () => (
<div
style={{
minHeight: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center",
color: "var(--color-text-muted, #888)",
fontFamily: "system-ui, sans-serif",
}}
>
Загрузка…
</div>
);
const withSuspense = (node) => <React.Suspense fallback={<PageLoader />}>{node}</React.Suspense>;
/** /**
* Protects routes that require authentication. * Protects routes that require authentication.
* Redirects to /login with return URL if no user and session is loaded. * Redirects to /login with return URL if no user and session is loaded.
@ -43,23 +87,23 @@ export const router = createBrowserRouter([
}, },
{ {
path: "login", path: "login",
element: <LoginPage />, element: withSuspense(<LoginPage />),
}, },
{ {
path: "client", path: "client",
element: <ClientDeliveryPage />, element: withSuspense(<ClientDeliveryPage />),
}, },
{ {
path: "client/:token", path: "client/:token",
element: <ClientDeliveryPage />, element: withSuspense(<ClientDeliveryPage />),
}, },
{ {
path: "client/test", path: "client/test",
element: <ClientTestPage />, element: withSuspense(<ClientTestPage />),
}, },
{ {
path: "client/test-consent", path: "client/test-consent",
element: <ClientTestConsentPage />, element: withSuspense(<ClientTestConsentPage />),
}, },
{ {
path: "delivery/:token", path: "delivery/:token",
@ -67,11 +111,11 @@ export const router = createBrowserRouter([
}, },
{ {
path: "forbidden", path: "forbidden",
element: <ForbiddenPage />, element: withSuspense(<ForbiddenPage />),
}, },
{ {
path: "dashboard", path: "dashboard",
element: ( element: withSuspense(
<RequireAuth> <RequireAuth>
<DashboardPage /> <DashboardPage />
</RequireAuth> </RequireAuth>
@ -79,7 +123,7 @@ export const router = createBrowserRouter([
}, },
{ {
path: "dashboard/group/:groupId", path: "dashboard/group/:groupId",
element: ( element: withSuspense(
<RequireAuth> <RequireAuth>
<GroupDetailPage /> <GroupDetailPage />
</RequireAuth> </RequireAuth>
@ -87,7 +131,7 @@ export const router = createBrowserRouter([
}, },
{ {
path: "settings", path: "settings",
element: ( element: withSuspense(
<RequireAuth> <RequireAuth>
<SettingsPage /> <SettingsPage />
</RequireAuth> </RequireAuth>
@ -95,7 +139,7 @@ export const router = createBrowserRouter([
}, },
{ {
path: "*", path: "*",
element: <NotFoundPage />, element: withSuspense(<NotFoundPage />),
}, },
], ],
}, },