diff --git a/apps/nextjs/src/components/layout/header/lazy-spotlight.tsx b/apps/nextjs/src/components/layout/header/lazy-spotlight.tsx index aff8496e9..5fbc9f5ed 100644 --- a/apps/nextjs/src/components/layout/header/lazy-spotlight.tsx +++ b/apps/nextjs/src/components/layout/header/lazy-spotlight.tsx @@ -1,14 +1,21 @@ "use client"; import { useEffect, useState } from "react"; +import dynamic from "next/dynamic"; import { useHotkeys } from "@mantine/hooks"; import { hotkeys } from "@homarr/definitions"; -import { Spotlight } from "@homarr/spotlight/component"; import { hasPendingSpotlightOpen, openSpotlight, spotlightOpenEvent } from "@homarr/spotlight/open"; +const loadSpotlight = () => import("@homarr/spotlight/component"); +const Spotlight = dynamic(() => loadSpotlight().then(({ Spotlight: Component }) => Component), { + ssr: false, + loading: () => null, +}); + export const LazySpotlight = () => { const [isMounted, setIsMounted] = useState(false); + const [isPreloaded, setIsPreloaded] = useState(false); useHotkeys( isMounted @@ -25,27 +32,41 @@ export const LazySpotlight = () => { ); useEffect(() => { + let isActive = true; const mount = () => setIsMounted(true); window.addEventListener(spotlightOpenEvent, mount); if (hasPendingSpotlightOpen()) mount(); + const preload = () => { + void loadSpotlight().then( + () => { + if (isActive) setIsPreloaded(true); + }, + () => undefined, + ); + }; let idleId: number | undefined; const delayId = window.setTimeout(() => { - idleId = window.requestIdleCallback?.(mount, { timeout: 1_000 }); - if (idleId === undefined) mount(); + idleId = window.requestIdleCallback?.(preload, { timeout: 1_000 }); + if (idleId === undefined) preload(); }, 1_000); return () => { + isActive = false; window.removeEventListener(spotlightOpenEvent, mount); window.clearTimeout(delayId); if (idleId !== undefined) window.cancelIdleCallback?.(idleId); }; }, []); - return isMounted ? ( + return isMounted || isPreloaded ? ( <> -