Files
archivmail/features/PROJ-77-admin-tabs-dynamic-import.md
sysopsandClaude Sonnet 5 d1b4497893 fix(PROJ-79): next lint kaputt seit Next-16-Upgrade repariert + 30 Findings gefixt
npm run lint rief next lint auf, das es in Next.js 16 nicht mehr gibt —
seit dem Next-16-Upgrade lief effektiv gar kein Lint mehr. Umgestellt auf
eslint . mit Flat-Config (eslint.config.mjs statt .eslintrc.json). Der
dadurch wieder sichtbare Lint-Lauf zeigte 30 Findings (25 Fehler,
5 Warnungen), alle gefixt:

- 19x react-hooks/set-state-in-effect: Loading-States wo möglich als
  echte Ableitung statt eigenem Effect-State (use-mobile.tsx komplett auf
  useSyncExternalStore umgebaut), sonst async-Wrapper mit Cancel-Guard um
  bestehende Loader — Timing/Ladeanzeige unverändert.
- react-hooks/refs (useSearch.ts): Ref-Schreibzugriff aus dem Render in
  einen Effect verschoben.
- 4x no-html-link-for-pages: <a href> durch next/link ersetzt in
  admin/login, forgot-password, signup.
- Rest (exhaustive-deps, no-img-element, unused disable) einzeln gefixt.
- 4 bewusst belassene disable-Kommentare mit Begründung (shadcn/ui-Datei,
  QR-Code-data-URL, Full-Reload nach Auth laut Projektregel).

eslint-Major-Upgrade auf 10 selbst bleibt blockiert: eslint-plugin-react/
jsx-a11y/import unterstützen ESLint 10 in ihrer aktuellen Latest-Version
noch nicht (Crash beim Laden), siehe Feature-Spec PROJ-79.

Verifiziert auf 132 (Build-Sandbox, kein Live-Deploy): npm ci/tsc/lint/
build grün, 8 Kern-Routen per Standalone-Server auf HTTP 200 geprüft.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019j28kGcaJAhBnrYX34hGdt
2026-08-05 21:14:17 +02:00

3.1 KiB
Raw Permalink Blame History

id, title, status, created
id title status created
PROJ-77 Admin-Tab-Bundle-Optimierung (dynamic import statt 19 statische Imports) Deployed 2026-08-05

Problem

src/app/admin/page.tsx (Zeile ~22-40) importiert alle 19 Admin-Tab- Komponenten statisch. Aktuell gibt es im gesamten Projekt 0 next/dynamic- Imports. Radix TabsContent unmountet zwar inaktive Tabs zur Laufzeit (kein gleichzeitiges Rendern), aber das initiale JS-Bundle enthält trotzdem den Code aller 19 Tabs, auch wenn ein Nutzer nur einen einzigen Tab je Sitzung öffnet.

Kein Crash-Bezug, reine Bundle-Größen-/Ladezeit-Optimierung.

Lösung (Vorschlag)

Jede Admin-Tab-Komponente auf next/dynamic mit Loading-State umstellen, z.B.:

const DashboardTab = dynamic(() => import('@/components/admin/tabs/DashboardTab'), {
  loading: () => <TabSkeleton />,
})

Umfang: 19 Komponenten, jeweils Import-Umstellung + einheitlicher Loading-Skeleton. Vor Umsetzung: kurzer Bundle-Size-Vergleich (next build Output) vorher/nachher, um den tatsächlichen Gewinn zu beziffern.

Implementation Notes

Umgesetzt am 2026-08-05.

Geänderte/neue Dateien

  • src/app/admin/page.tsx: 18 statische Tab-Imports (Zeile 2239) durch next/dynamic-Deklarationen ersetzt. Alle Tab-Komponenten sind Named Exports, daher jeweils dynamic(() => import("…/XyzTab").then((m) => m.XyzTab), { loading }). Eine gemeinsame const loading = () => <TabSkeleton /> wird für alle 18 Tabs wiederverwendet. ResetPasswordDialog/DeleteUserDialog (Global-Dialoge, immer sichtbar) bleiben bewusst statisch.
  • src/components/admin/TabSkeleton.tsx (neu): einheitlicher Lade-Platzhalter auf Basis der vorhandenen shadcn/ui-Skeleton- Komponente, mit aria-busy/aria-live und sr-only-Text.

Props-Typisierung: dynamic() inferiert die Props über den .then()-Rückgabewert korrekt; ein explizites ComponentType<Props> war nicht nötig. npm run build (inkl. TypeScript-Check) läuft fehlerfrei.

Bundle-Size-Vergleich (Next.js 16 / Turbopack zeigt keine Größen im Build-Output; gemessen als Summe der im prerenderten .next/server/app/admin.html referenzierten _next/static/*.js-Dateien, unkomprimiert):

Dateien Initiales JS
vorher 17 1035,6 KB
nachher 18 830,7 KB
Delta +1 204,9 KB (19,8 %)

Der Code der Tabs liegt jetzt in separaten Chunks, die erst beim Aktivieren des jeweiligen Tabs geladen werden.

Deployed auf 131 (Produktiv) am 2026-08-05.

Hinweis: dynamic() läuft hier mit Default-ssr: true, d.h. der initial aktive Tab wird weiterhin serverseitig vorgerendert — kein Flash-of-Skeleton beim ersten Laden des Dashboards.

Acceptance Criteria

  • Alle Admin-Tabs (18 Tab-Komponenten) per next/dynamic geladen, mit Loading-Skeleton.
  • npm run build Bundle-Size-Report zeigt messbare Reduktion der initialen Admin-Route-Chunk-Größe (204,9 KB / 19,8 %).
  • Funktionale Regression: alle Tabs weiterhin normal nutzbar (manueller Klick-Test durch alle Tabs) — noch zu verifizieren, kann nicht automatisiert erfolgen; offen für QA.