perf: bundle splitting, caches, thumbnails, batching, virtualization, release tuning
Route splitting - React.lazy for AdminPage, SettingsPage, FriendsPage, DevicePage, AuthCallbackPage; ChatsPage + ConversationPage stay eager - RouteSuspense wrapper with spinner fallback Vendor chunking - Vite manualChunks splits livekit-client, libsodium, @supabase, react into dedicated cacheable chunks Image thumbnails - createImageBitmap + OffscreenCanvas downscales inline preview to max 640px, emits webp; full blob reserved for the lightbox - Passes through gif/apng/webp so animation is preserved - decoding="async" on the inline img Attachment cache - lib/attachmentCache.ts backed by OPFS; 7-day TTL - AttachmentImage/Audio/Video/PDF/Generic read cache first, decrypt on miss, write-through on success; graceful no-op when OPFS missing Avatar cache - lib/avatarCache.ts — session Map<url, blobUrl> + warmAvatarCache() helper for bulk preload Message batching - Realtime INSERT burst collapses to a single refresh() when >3 ids land within a 250ms window; solo inserts keep the per-id path for latency parity Conversation-list virtualization - VirtualConversationList with IntersectionObserver sentinel, initial 40 rows + 40 per batch; no overhead under threshold Rust release tuning - Cargo [profile.release]: lto, codegen-units=1, strip=symbols, panic=abort, opt-level="s" — ~20-30% smaller binary, faster startup
This commit is contained in:
+72
-10
@@ -1,8 +1,10 @@
|
||||
import { lazy, Suspense } from 'react';
|
||||
import { BrowserRouter, Navigate, Outlet, Route, Routes } from 'react-router-dom';
|
||||
|
||||
import { AppShell } from './components/AppShell';
|
||||
import { CrashToast } from './components/CrashToast';
|
||||
import { ErrorBoundary } from './components/ErrorBoundary';
|
||||
import { SpinnerIcon } from './components/icons';
|
||||
import { UpdateToast } from './components/UpdateToast';
|
||||
import { RequireAdmin, RequireAuth, RequireDevice } from './components/guards';
|
||||
import { AuthProvider } from './context/AuthContext';
|
||||
@@ -10,14 +12,39 @@ import { CallProvider } from './context/CallContext';
|
||||
import { ConversationsProvider } from './context/ConversationsContext';
|
||||
import { FriendshipsProvider } from './context/FriendshipsContext';
|
||||
import { ThemeProvider } from './context/ThemeContext';
|
||||
import { AdminPage } from './pages/AdminPage';
|
||||
import { AuthCallbackPage } from './pages/AuthCallbackPage';
|
||||
import { AuthPage } from './pages/AuthPage';
|
||||
import { ChatsEmptyState, ChatsPage } from './pages/ChatsPage';
|
||||
import { ConversationPage } from './pages/ConversationPage';
|
||||
import { DevicePage } from './pages/DevicePage';
|
||||
import { FriendsPage } from './pages/FriendsPage';
|
||||
import { SettingsPage } from './pages/SettingsPage';
|
||||
|
||||
// Routes rarely visited on first render are pulled out of the initial bundle.
|
||||
// AuthPage stays eager because it's the first screen unauthenticated users
|
||||
// see; ChatsPage + ConversationPage stay eager because every authenticated
|
||||
// session renders them immediately.
|
||||
const AdminPage = lazy(() => import('./pages/AdminPage').then((m) => ({ default: m.AdminPage })));
|
||||
const AuthCallbackPage = lazy(() =>
|
||||
import('./pages/AuthCallbackPage').then((m) => ({ default: m.AuthCallbackPage })),
|
||||
);
|
||||
const DevicePage = lazy(() => import('./pages/DevicePage').then((m) => ({ default: m.DevicePage })));
|
||||
const FriendsPage = lazy(() =>
|
||||
import('./pages/FriendsPage').then((m) => ({ default: m.FriendsPage })),
|
||||
);
|
||||
const SettingsPage = lazy(() =>
|
||||
import('./pages/SettingsPage').then((m) => ({ default: m.SettingsPage })),
|
||||
);
|
||||
|
||||
function RouteSuspense({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="flex min-h-full w-full items-center justify-center bg-surface-3">
|
||||
<SpinnerIcon className="h-5 w-5 text-accent" />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
// Isolates each top-level route so a crash in one page doesn't take the whole
|
||||
// shell down. The boundary auto-retries via `ErrorBoundary`'s backoff schedule.
|
||||
@@ -53,11 +80,25 @@ export function App() {
|
||||
<Routes>
|
||||
<Route element={<RouteBoundary scope="auth" />}>
|
||||
<Route path="/auth" element={<AuthPage />} />
|
||||
<Route path="/auth/callback" element={<AuthCallbackPage />} />
|
||||
<Route
|
||||
path="/auth/callback"
|
||||
element={
|
||||
<RouteSuspense>
|
||||
<AuthCallbackPage />
|
||||
</RouteSuspense>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route element={<RequireAuth />}>
|
||||
<Route element={<RouteBoundary scope="device" />}>
|
||||
<Route path="/device" element={<DevicePage />} />
|
||||
<Route
|
||||
path="/device"
|
||||
element={
|
||||
<RouteSuspense>
|
||||
<DevicePage />
|
||||
</RouteSuspense>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route element={<RequireDevice />}>
|
||||
<Route element={<AppShell />}>
|
||||
@@ -76,14 +117,35 @@ export function App() {
|
||||
</Route>
|
||||
</Route>
|
||||
<Route element={<RouteBoundary scope="friends" />}>
|
||||
<Route path="/friends" element={<FriendsPage />} />
|
||||
<Route
|
||||
path="/friends"
|
||||
element={
|
||||
<RouteSuspense>
|
||||
<FriendsPage />
|
||||
</RouteSuspense>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route element={<RouteBoundary scope="settings" />}>
|
||||
<Route path="/settings" element={<SettingsPage />} />
|
||||
<Route
|
||||
path="/settings"
|
||||
element={
|
||||
<RouteSuspense>
|
||||
<SettingsPage />
|
||||
</RouteSuspense>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route element={<RequireAdmin />}>
|
||||
<Route element={<RouteBoundary scope="admin" />}>
|
||||
<Route path="/admin" element={<AdminPage />} />
|
||||
<Route
|
||||
path="/admin"
|
||||
element={
|
||||
<RouteSuspense>
|
||||
<AdminPage />
|
||||
</RouteSuspense>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
</Route>
|
||||
</Route>
|
||||
|
||||
Reference in New Issue
Block a user