diff --git a/src/contexts/BlogIndexContext.tsx b/src/contexts/BlogIndexContext.tsx index fc8a977..83a71b4 100644 --- a/src/contexts/BlogIndexContext.tsx +++ b/src/contexts/BlogIndexContext.tsx @@ -5,6 +5,22 @@ import type { BlogPostSummary, BlogTag } from '../blog/types'; export const BLOG_INDEX_PAGE_SIZE = 6; +const prefetchedImages = new Set(); + +function preloadImage(url: string) { + if (typeof window === 'undefined') { + return; + } + + if (!url || prefetchedImages.has(url)) { + return; + } + + const img = new Image(); + img.src = url; + prefetchedImages.add(url); +} + interface BlogIndexContextValue { initialPosts: BlogPostSummary[]; initialTotalCount: number; @@ -76,6 +92,28 @@ export function BlogIndexProvider({ children }: { children: ReactNode }) { [initialPosts, initialTotalCount, initialTags, isLoading, error, hasInitialData], ); + useEffect(() => { + if (!hasInitialData) { + return; + } + + if (typeof window === 'undefined') { + return; + } + + const urls = initialPosts + .map((post) => post.coverImageUrl) + .filter((url): url is string => Boolean(url)); + + // Avoid re-prefetching the same set to prevent needless work + const needsPrefetch = urls.some((url) => !prefetchedImages.has(url)); + if (!needsPrefetch) { + return; + } + + urls.forEach(preloadImage); + }, [initialPosts, hasInitialData]); + return {children}; }