perf: route- and modal-level code splitting (React.lazy)
The whole app shipped in one bundle, so the logged-out landing and every page pulled all module code. Split into lazy chunks: - main.tsx: lazy App + the public leaves (WatchPage, Privacy, Terms), so a public /watch share link never downloads the authenticated app. - App.tsx: each module page (Feed, Channels, Playlists, Stats, Scheduler, Config, Users, Settings, Notifications, Messages, Downloads, ChannelPage) and the About/ReleaseNotes/Onboarding modals load on demand behind <Suspense>. - Heavy modals lazy in their parents: PlayerModal (Feed, Playlists), DownloadDialog (DownloadButton — kept out of the feed chunk), and the VideoEditor/ShareDialog/ProfileEditor (DownloadCenter). - Extracted focusAccessRequestsTab + the tab constants to lib/adminUsersTab so callers can pre-select the admin tab without statically importing the now lazy-loaded AdminUsers page (which would defeat the split). Build now emits ~25 chunks. Landing no longer downloads any module code (~350 KB deferred); dev landing Perf 93->95. Verified in a real browser: every page + the video editor load with no console errors.
This commit is contained in:
parent
18a33b96c8
commit
2344902a7f
10 changed files with 167 additions and 117 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { useMemo, useState } from "react";
|
||||
import { lazy, Suspense, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
|
|
@ -16,10 +16,12 @@ import {
|
|||
import clsx from "clsx";
|
||||
import Tabs, { usePersistedTab } from "./Tabs";
|
||||
import Modal from "./Modal";
|
||||
import DownloadDialog from "./DownloadDialog";
|
||||
import ProfileEditor from "./ProfileEditor";
|
||||
import VideoEditor from "./VideoEditor";
|
||||
import ShareDialog from "./ShareDialog";
|
||||
// Lazy: these dialogs/editors open on demand, so they stay out of the Downloads page chunk until
|
||||
// used (the video editor in particular is heavy — filmstrip + scrubber).
|
||||
const DownloadDialog = lazy(() => import("./DownloadDialog"));
|
||||
const ProfileEditor = lazy(() => import("./ProfileEditor"));
|
||||
const VideoEditor = lazy(() => import("./VideoEditor"));
|
||||
const ShareDialog = lazy(() => import("./ShareDialog"));
|
||||
import { useConfirm } from "./ConfirmProvider";
|
||||
import { useLiveQuery } from "../lib/useLiveQuery";
|
||||
import { api, type DownloadJob, type Me } from "../lib/api";
|
||||
|
|
@ -582,19 +584,21 @@ export default function DownloadCenter({ me }: { me: Me }) {
|
|||
|
||||
{tab === "system" && me.role === "admin" && <AdminSystem />}
|
||||
|
||||
{addSource && (
|
||||
<DownloadDialog
|
||||
source={addSource}
|
||||
onClose={() => {
|
||||
setAddSource(null);
|
||||
setAddUrl("");
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{manage && <ProfileEditor onClose={() => setManage(false)} />}
|
||||
{renameJob && <RenameModal job={renameJob} onClose={() => setRenameJob(null)} />}
|
||||
{shareJob && <ShareDialog job={shareJob} onClose={() => setShareJob(null)} />}
|
||||
{editJob && <VideoEditor job={editJob} onClose={() => setEditJob(null)} />}
|
||||
<Suspense fallback={null}>
|
||||
{addSource && (
|
||||
<DownloadDialog
|
||||
source={addSource}
|
||||
onClose={() => {
|
||||
setAddSource(null);
|
||||
setAddUrl("");
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{manage && <ProfileEditor onClose={() => setManage(false)} />}
|
||||
{renameJob && <RenameModal job={renameJob} onClose={() => setRenameJob(null)} />}
|
||||
{shareJob && <ShareDialog job={shareJob} onClose={() => setShareJob(null)} />}
|
||||
{editJob && <VideoEditor job={editJob} onClose={() => setEditJob(null)} />}
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue