perf(PROJ-77): Admin-Tabs per next/dynamic laden statt statisch importieren
18 Admin-Tab-Komponenten wurden bisher alle statisch in src/app/admin/page.tsx importiert, unabhängig davon welcher Tab tatsächlich geöffnet wird. Umstellung auf next/dynamic mit gemeinsamem TabSkeleton-Loading-State reduziert das initiale JS-Bundle der Admin-Route um 204,9 KB (-19,8%). Initial aktiver Tab bleibt weiterhin serverseitig vorgerendert (ssr: true), kein Skeleton-Flash beim ersten Laden. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019j28kGcaJAhBnrYX34hGdt
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
209fdeb8ad
commit
e59b11743a
+79
-19
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import dynamic from "next/dynamic";
|
||||
import { useAuth } from "@/hooks/useAuth";
|
||||
import { useLDAPConfig } from "@/hooks/useLDAPConfig";
|
||||
import { useTenantLDAPConfig } from "@/hooks/useTenantLDAPConfig";
|
||||
@@ -18,26 +19,85 @@ import { Navbar } from "@/components/navbar";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
|
||||
// Tab components
|
||||
import { DashboardTab } from "@/components/admin/tabs/DashboardTab";
|
||||
import { ServicesTab } from "@/components/admin/tabs/ServicesTab";
|
||||
import { UsersTab } from "@/components/admin/tabs/UsersTab";
|
||||
import { AuditTab } from "@/components/admin/tabs/AuditTab";
|
||||
import { ImportTab } from "@/components/admin/tabs/ImportTab";
|
||||
import { SecurityTab } from "@/components/admin/tabs/SecurityTab";
|
||||
import { LDAPTab } from "@/components/admin/tabs/LDAPTab";
|
||||
import { TenantLDAPTab } from "@/components/admin/tabs/TenantLDAPTab";
|
||||
import { TenantsTab } from "@/components/admin/tabs/TenantsTab";
|
||||
import { CertTab } from "@/components/admin/tabs/CertTab";
|
||||
import { ModulesTab } from "@/components/admin/ModulesTab";
|
||||
import { IMAPSettingsTab } from "@/components/admin/tabs/IMAPSettingsTab";
|
||||
import { RetentionTab } from "@/components/admin/tabs/RetentionTab";
|
||||
import { ArchivingRulesTab } from "@/components/admin/tabs/ArchivingRulesTab";
|
||||
import { RoutingRulesTab } from "@/components/admin/tabs/RoutingRulesTab";
|
||||
import { QuotaTab } from "@/components/admin/tabs/QuotaTab";
|
||||
import { SMTPOutTab } from "@/components/admin/tabs/SMTPOutTab";
|
||||
import { DSGVOTab } from "@/components/admin/tabs/DSGVOTab";
|
||||
import { ResetPasswordDialog, DeleteUserDialog } from "@/components/admin/UserDialogs";
|
||||
import { TabSkeleton } from "@/components/admin/TabSkeleton";
|
||||
|
||||
// Tab components — dynamisch nachgeladen (PROJ-77), damit das initiale
|
||||
// Admin-Bundle nicht den Code aller 19 Tabs enthält.
|
||||
const loading = () => <TabSkeleton />;
|
||||
|
||||
const DashboardTab = dynamic(
|
||||
() => import("@/components/admin/tabs/DashboardTab").then((m) => m.DashboardTab),
|
||||
{ loading }
|
||||
);
|
||||
const ServicesTab = dynamic(
|
||||
() => import("@/components/admin/tabs/ServicesTab").then((m) => m.ServicesTab),
|
||||
{ loading }
|
||||
);
|
||||
const UsersTab = dynamic(
|
||||
() => import("@/components/admin/tabs/UsersTab").then((m) => m.UsersTab),
|
||||
{ loading }
|
||||
);
|
||||
const AuditTab = dynamic(
|
||||
() => import("@/components/admin/tabs/AuditTab").then((m) => m.AuditTab),
|
||||
{ loading }
|
||||
);
|
||||
const ImportTab = dynamic(
|
||||
() => import("@/components/admin/tabs/ImportTab").then((m) => m.ImportTab),
|
||||
{ loading }
|
||||
);
|
||||
const SecurityTab = dynamic(
|
||||
() => import("@/components/admin/tabs/SecurityTab").then((m) => m.SecurityTab),
|
||||
{ loading }
|
||||
);
|
||||
const LDAPTab = dynamic(
|
||||
() => import("@/components/admin/tabs/LDAPTab").then((m) => m.LDAPTab),
|
||||
{ loading }
|
||||
);
|
||||
const TenantLDAPTab = dynamic(
|
||||
() => import("@/components/admin/tabs/TenantLDAPTab").then((m) => m.TenantLDAPTab),
|
||||
{ loading }
|
||||
);
|
||||
const TenantsTab = dynamic(
|
||||
() => import("@/components/admin/tabs/TenantsTab").then((m) => m.TenantsTab),
|
||||
{ loading }
|
||||
);
|
||||
const CertTab = dynamic(
|
||||
() => import("@/components/admin/tabs/CertTab").then((m) => m.CertTab),
|
||||
{ loading }
|
||||
);
|
||||
const ModulesTab = dynamic(
|
||||
() => import("@/components/admin/ModulesTab").then((m) => m.ModulesTab),
|
||||
{ loading }
|
||||
);
|
||||
const IMAPSettingsTab = dynamic(
|
||||
() => import("@/components/admin/tabs/IMAPSettingsTab").then((m) => m.IMAPSettingsTab),
|
||||
{ loading }
|
||||
);
|
||||
const RetentionTab = dynamic(
|
||||
() => import("@/components/admin/tabs/RetentionTab").then((m) => m.RetentionTab),
|
||||
{ loading }
|
||||
);
|
||||
const ArchivingRulesTab = dynamic(
|
||||
() => import("@/components/admin/tabs/ArchivingRulesTab").then((m) => m.ArchivingRulesTab),
|
||||
{ loading }
|
||||
);
|
||||
const RoutingRulesTab = dynamic(
|
||||
() => import("@/components/admin/tabs/RoutingRulesTab").then((m) => m.RoutingRulesTab),
|
||||
{ loading }
|
||||
);
|
||||
const QuotaTab = dynamic(
|
||||
() => import("@/components/admin/tabs/QuotaTab").then((m) => m.QuotaTab),
|
||||
{ loading }
|
||||
);
|
||||
const SMTPOutTab = dynamic(
|
||||
() => import("@/components/admin/tabs/SMTPOutTab").then((m) => m.SMTPOutTab),
|
||||
{ loading }
|
||||
);
|
||||
const DSGVOTab = dynamic(
|
||||
() => import("@/components/admin/tabs/DSGVOTab").then((m) => m.DSGVOTab),
|
||||
{ loading }
|
||||
);
|
||||
|
||||
export default function AdminPage() {
|
||||
const { user, loading: authLoading } = useAuth("domain_admin", "/admin/login");
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
"use client";
|
||||
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
|
||||
/**
|
||||
* Einheitlicher Lade-Platzhalter für dynamisch nachgeladene Admin-Tabs.
|
||||
* Wird von next/dynamic als `loading`-Komponente verwendet (PROJ-77).
|
||||
*/
|
||||
export function TabSkeleton() {
|
||||
return (
|
||||
<div className="mt-4 space-y-4" aria-busy="true" aria-live="polite">
|
||||
<span className="sr-only">Inhalt wird geladen …</span>
|
||||
<Skeleton className="h-8 w-48" />
|
||||
<div className="space-y-2">
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-5/6" />
|
||||
<Skeleton className="h-4 w-2/3" />
|
||||
</div>
|
||||
<Skeleton className="h-48 w-full" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user