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:
2026-04-21 10:24:31 +02:00
parent 228608ef2c
commit 44088b35d7
13 changed files with 487 additions and 57 deletions
+19
View File
@@ -25,6 +25,25 @@ export default defineConfig({
conditions: ['require', 'node', 'default'],
},
},
build: {
rollupOptions: {
output: {
// Split heavy vendor modules into their own chunks so they cache
// independently from the app shell. LiveKit + libsodium change
// rarely, so this keeps the hot-path app chunk small on rebuilds
// and lets the browser cache the big binaries across app updates.
manualChunks: (id) => {
if (id.includes('node_modules/livekit-client')) return 'vendor-livekit';
if (id.includes('node_modules/libsodium-wrappers-sumo')) return 'vendor-sodium';
if (id.includes('node_modules/@supabase')) return 'vendor-supabase';
if (id.includes('node_modules/react-router') || id.includes('node_modules/react-dom') || id.includes('node_modules/react/')) {
return 'vendor-react';
}
return undefined;
},
},
},
},
clearScreen: false,
server: {
port: 1420,