From 5d6ef066a97c26218dcda0735160e6fa2d4f198a Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 21 Oct 2024 08:58:03 -0700 Subject: [PATCH 1/3] Cancel images on mouse-leave --- src/components/ui/link.tsx | 59 +++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/src/components/ui/link.tsx b/src/components/ui/link.tsx index 22fcafe..33df2b8 100644 --- a/src/components/ui/link.tsx +++ b/src/components/ui/link.tsx @@ -17,13 +17,16 @@ function sleep(ms: number) { } async function prefetchImages(href: string) { - if (!href.startsWith("/") || href.startsWith("/order")) { + if (!href.startsWith("/") || href.startsWith("/order") || href === "/") { return []; } const url = new URL(href, window.location.href); - const imageResponse = await fetch(`/api/prefetch-images${url.pathname}`, { - priority: "low", - }); + const imageResponse = await fetch( + `/api/prefetch-images${url.pathname || "/"}`, + { + priority: "low", + }, + ); // only throw in dev if (!imageResponse.ok && process.env.NODE_ENV === "development") { throw new Error("Failed to prefetch images"); @@ -36,6 +39,7 @@ const seen = new Set(); export const Link: typeof NextLink = (({ children, ...props }) => { const [images, setImages] = useState([]); + const [preloading, setPreloading] = useState<(() => void)[]>([]); const linkRef = useRef(null); const router = useRouter(); let prefetchTimeout: NodeJS.Timeout | null = null; // Track the timeout ID @@ -85,21 +89,21 @@ export const Link: typeof NextLink = (({ children, ...props }) => { { + onMouseEnter={() => { router.prefetch(String(props.href)); + if (preloading.length) return; + const p: (() => void)[] = []; for (const image of images) { - if (image.loading === "lazy" || seen.has(image.srcset)) { - continue; - } - const img = new Image(); - img.decoding = "async"; - img.fetchPriority = "low"; - img.sizes = image.sizes; - seen.add(image.srcset); - img.srcset = image.srcset; - img.src = image.src; - img.alt = image.alt; + const remove = prefetchImage(image); + if (remove) p.push(remove); + } + setPreloading(p); + }} + onMouseLeave={() => { + for (const remove of preloading) { + remove(); } + setPreloading([]); }} onMouseDown={(e) => { const url = new URL(String(props.href), window.location.href); @@ -121,3 +125,26 @@ export const Link: typeof NextLink = (({ children, ...props }) => { ); }) as typeof NextLink; + +function prefetchImage(image: PrefetchImage) { + if (image.loading === "lazy" || seen.has(image.srcset)) { + return; + } + const img = new Image(); + img.decoding = "async"; + img.fetchPriority = "low"; + img.sizes = image.sizes; + seen.add(image.srcset); + img.srcset = image.srcset; + img.src = image.src; + img.alt = image.alt; + let done = false; + img.onload = img.onerror = () => { + done = true; + }; + return () => { + if (done) return; + img.src = img.srcset = ""; + seen.delete(image.srcset); + }; +} \ No newline at end of file From 9b76140acdb49eb2baa64a0e0823787b4a5e3dbe Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 21 Oct 2024 08:59:01 -0700 Subject: [PATCH 2/3] Cancel images on mouse-leave --- src/components/ui/link.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/components/ui/link.tsx b/src/components/ui/link.tsx index 33df2b8..332214a 100644 --- a/src/components/ui/link.tsx +++ b/src/components/ui/link.tsx @@ -21,12 +21,9 @@ async function prefetchImages(href: string) { return []; } const url = new URL(href, window.location.href); - const imageResponse = await fetch( - `/api/prefetch-images${url.pathname || "/"}`, - { - priority: "low", - }, - ); + const imageResponse = await fetch(`/api/prefetch-images${url.pathname}`, { + priority: "low", + }); // only throw in dev if (!imageResponse.ok && process.env.NODE_ENV === "development") { throw new Error("Failed to prefetch images"); From ac098a19c2373bd266b37d088388fca344c5896c Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 21 Oct 2024 08:59:15 -0700 Subject: [PATCH 3/3] Cancel images on mouse-leave --- src/components/ui/link.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ui/link.tsx b/src/components/ui/link.tsx index 332214a..059b93f 100644 --- a/src/components/ui/link.tsx +++ b/src/components/ui/link.tsx @@ -144,4 +144,4 @@ function prefetchImage(image: PrefetchImage) { img.src = img.srcset = ""; seen.delete(image.srcset); }; -} \ No newline at end of file +}