debug: add comprehensive logging for image caching

Add debug logs prefixed with [image-preload], [image-cache], [sw-image-cache],
and [reader-header] to track:
- When images are preloaded
- Service Worker availability and controller status
- Image fetch success/failure
- Service Worker intercepting and caching image requests
- Image loading in ReaderHeader component
- Cache hits/misses in Service Worker

This will help debug why images aren't available offline.
This commit is contained in:
Gigi
2025-10-31 00:52:29 +01:00
parent aeedc622b1
commit 0b7891419b
3 changed files with 122 additions and 6 deletions

View File

@@ -37,6 +37,17 @@ const ReaderHeader: React.FC<ReaderHeaderProps> = ({
onHighlightCountClick
}) => {
const cachedImage = useImageCache(image)
// Debug: Log image loading state
React.useEffect(() => {
if (image) {
console.log('[reader-header] Image provided:', image)
if (cachedImage) {
console.log('[reader-header] Using cached image URL:', cachedImage)
}
}
}, [image, cachedImage])
const { textColor } = useAdaptiveTextColor(cachedImage)
const formattedDate = published ? format(new Date(published * 1000), 'MMM d, yyyy') : null
const isLongSummary = summary && summary.length > 150
@@ -80,7 +91,21 @@ const ReaderHeader: React.FC<ReaderHeaderProps> = ({
<>
<div className="reader-hero-image">
{cachedImage ? (
<img src={cachedImage} alt={title || 'Article image'} />
<img
src={cachedImage}
alt={title || 'Article image'}
onLoad={() => {
console.log('[reader-header] ✅ Image loaded successfully:', cachedImage)
}}
onError={(e) => {
console.error('[reader-header] ❌ Image failed to load:', cachedImage, {
error: e,
target: e.currentTarget,
naturalWidth: e.currentTarget.naturalWidth,
naturalHeight: e.currentTarget.naturalHeight
})
}}
/>
) : (
<div className="reader-hero-placeholder">
<FontAwesomeIcon icon={faNewspaper} />

View File

@@ -12,6 +12,34 @@ export function useImageCache(
// Service Worker handles everything - just return the URL as-is
// The Service Worker will intercept fetch requests and cache them
// Make sure images use standard <img src> tags for SW interception
// Debug: Log when image URL is provided
if (imageUrl) {
console.log('[image-cache] useImageCache hook called with URL:', imageUrl)
// Check if Service Worker is available
if ('serviceWorker' in navigator) {
if (navigator.serviceWorker.controller) {
console.log('[image-cache] ✅ Service Worker controller is active')
} else {
console.warn('[image-cache] ⚠️ Service Worker not controlling page - checking registration...')
navigator.serviceWorker.getRegistration().then((reg) => {
if (reg) {
console.log('[image-cache] Service Worker registered but not controlling:', {
active: !!reg.active,
installing: !!reg.installing,
waiting: !!reg.waiting
})
} else {
console.warn('[image-cache] ❌ No Service Worker registration found')
}
})
}
} else {
console.warn('[image-cache] ❌ Service Workers not supported in this browser')
}
}
return imageUrl
}
@@ -34,18 +62,49 @@ export function useCacheImageOnLoad(
* images are cached before going offline
*/
export function preloadImage(imageUrl: string | undefined): void {
if (!imageUrl) return
if (!imageUrl) {
console.log('[image-preload] Skipping - no image URL provided')
return
}
console.log('[image-preload] Preloading image:', imageUrl)
// Check if Service Worker is available
if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
console.log('[image-preload] ✅ Service Worker is active')
} else {
console.warn('[image-preload] ⚠️ Service Worker not active - images may not cache')
}
// Create a link element with rel=prefetch or use Image object to trigger fetch
// Service Worker will intercept and cache the request
const img = new Image()
img.onload = () => {
console.log('[image-preload] ✅ Image loaded successfully:', imageUrl)
}
img.onerror = (err) => {
console.error('[image-preload] ❌ Image failed to load:', imageUrl, err)
}
img.src = imageUrl
console.log('[image-preload] Created Image() object with src:', imageUrl)
// Also try using fetch to explicitly trigger Service Worker
// This ensures the image is cached even if <img> tag hasn't rendered yet
fetch(imageUrl, { mode: 'no-cors' }).catch(() => {
// Ignore errors - image might not be CORS-enabled, but SW will still cache it
// The Image() approach above will work for most cases
})
fetch(imageUrl, { mode: 'no-cors' })
.then((response) => {
console.log('[image-preload] ✅ Fetch successful for image:', imageUrl, {
status: response.status,
type: response.type,
url: response.url
})
})
.catch((err) => {
console.warn('[image-preload] ⚠️ Fetch failed (may be CORS issue, Image() should still work):', imageUrl, err)
// Ignore errors - image might not be CORS-enabled, but SW will still cache it
// The Image() approach above will work for most cases
})
}

View File

@@ -31,6 +31,15 @@ registerRoute(
/\.(jpg|jpeg|png|gif|webp|svg)$/i.test(url.pathname)
// Cache all images, not just cross-origin ones
// This ensures article images from any source get cached
if (isImage) {
console.log('[sw-image-cache] Intercepting image request:', {
url: url.href,
destination: request.destination,
method: request.method
})
}
return isImage
},
new StaleWhileRevalidate({
@@ -43,6 +52,29 @@ registerRoute(
new CacheableResponsePlugin({
statuses: [0, 200],
}),
{
cacheKeyWillBeUsed: async ({ request }) => {
console.log('[sw-image-cache] Cache key generated for:', request.url)
return request
},
cacheWillUpdate: async ({ response }) => {
console.log('[sw-image-cache] Caching response:', {
url: response.url,
status: response.status,
type: response.type,
ok: response.ok
})
return response.ok ? response : null
},
cachedResponseWillBeUsed: async ({ cachedResponse, request }) => {
if (cachedResponse) {
console.log('[sw-image-cache] ✅ Serving from cache:', request.url)
} else {
console.log('[sw-image-cache] ❌ No cached response found:', request.url)
}
return cachedResponse || null
}
}
],
})
)