fix(app-shell): Haengende Lazy-Routen ("Dashboard loads forever") — instabile Zustands-Selektoren #381

Closed
opened 2026-09-14 06:27:45 +00:00 by Leopoldadmin · 0 comments
Owner

Bug

Alle Core-Lazy-Routen im AppShell-Baum (/dashboard, /approvals, /delegations, /profile, /system-dashboard, /outbox) blieben beim Direkt-Aufruf/Reload ewig im Route-Suspense-Spinner haengen ("Seite wird geladen"), obwohl die Chunks nachweislich in ~16ms luden und KEINE JS-Fehler auftraten. Plugin-Routen und der StartLayout-Baum funktionierten.

Root Cause (Bisekt-Beweis)

Sidebar.tsx selektierte useWorkspaceStore(s => s.moduleMenuOrder()) und useWorkspace.ts selektierte s => s.visibleModuleKeys(). Beide Store-Methoden erzeugen bei JEDEM Aufruf ein NEUES Objekt (new Map(...) bzw. new Set(...)). Fuer React-18-useSyncExternalStore (Zustand 4.5.7) ist das ein instabiler getSnapshot: jeder Snapshot gilt als "geaendert" -> synchroner Re-Render-Loop -> die ausstehenden Suspense-Commits der Route-lazy-Pages kamen nie zur Landung.

Bisekt-Kette: minimale AppShell (nur main+Outlet) -> alles rendert; +Sidebar allein -> Hang kehrt zurueck; Import-Bisect: Chunks resolved (LAZY-DEBUG-Log), React committed nie.

Fix (Commit 3fd0c69)

Stabile context-Referenz selektieren und Map/Set per useMemo ableiten (Sidebar.tsx + useWorkspace.ts).

Verifikation

  • tsc exit=0
  • Lokaler Preview-Test (frischer Kontext): /dashboard h1='Dashboard', /outbox Admin-Gate gerendert, KEIN Spinner (vorher: haengender Spinner, h1=null)
  • PROD nach Frontend-Deploy, frischer Kontext: /dashboard rendert (spinner=false, mainTextLen=45)
  • PROD, echter Form-Login: /outbox vollstaendig gerendert — h1='Event Outbox', Stats (Published 158 / Failed 0), 35 Registry-Karten, Maintenance-Buttons, mainTextLen=1699, kein Spinner

Klaraerte damit auch den alten Incident "Dashboard loads forever" (als Cache-Problem vermutet, Thread #3) — der Spinner-Hang war der Selector-Bug.

## Bug Alle Core-Lazy-Routen im AppShell-Baum (/dashboard, /approvals, /delegations, /profile, /system-dashboard, /outbox) blieben beim Direkt-Aufruf/Reload ewig im Route-Suspense-Spinner haengen ("Seite wird geladen"), obwohl die Chunks nachweislich in ~16ms luden und KEINE JS-Fehler auftraten. Plugin-Routen und der StartLayout-Baum funktionierten. ## Root Cause (Bisekt-Beweis) `Sidebar.tsx` selektierte `useWorkspaceStore(s => s.moduleMenuOrder())` und `useWorkspace.ts` selektierte `s => s.visibleModuleKeys()`. Beide Store-Methoden erzeugen bei JEDEM Aufruf ein NEUES Objekt (`new Map(...)` bzw. `new Set(...)`). Fuer React-18-useSyncExternalStore (Zustand 4.5.7) ist das ein instabiler getSnapshot: jeder Snapshot gilt als "geaendert" -> synchroner Re-Render-Loop -> die ausstehenden Suspense-Commits der Route-lazy-Pages kamen nie zur Landung. Bisekt-Kette: minimale AppShell (nur main+Outlet) -> alles rendert; +Sidebar allein -> Hang kehrt zurueck; Import-Bisect: Chunks resolved (LAZY-DEBUG-Log), React committed nie. ## Fix (Commit 3fd0c69) Stabile `context`-Referenz selektieren und Map/Set per `useMemo` ableiten (Sidebar.tsx + useWorkspace.ts). ## Verifikation - tsc exit=0 - Lokaler Preview-Test (frischer Kontext): /dashboard h1='Dashboard', /outbox Admin-Gate gerendert, KEIN Spinner (vorher: haengender Spinner, h1=null) - PROD nach Frontend-Deploy, frischer Kontext: /dashboard rendert (spinner=false, mainTextLen=45) - PROD, echter Form-Login: /outbox vollstaendig gerendert — h1='Event Outbox', Stats (Published 158 / Failed 0), 35 Registry-Karten, Maintenance-Buttons, mainTextLen=1699, kein Spinner Klaraerte damit auch den alten Incident "Dashboard loads forever" (als Cache-Problem vermutet, Thread #3) — der Spinner-Hang war der Selector-Bug.
Leopoldadmin added the bug label 2026-09-14 06:27:45 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Leopoldadmin/leocrm#381