-
Notifications
You must be signed in to change notification settings - Fork 0
Static Map Caching
Joey.Huang edited this page Jul 6, 2025
·
2 revisions
Running Page 2.0 features a revolutionary static map caching system that provides 99%+ cost reduction and instant loading for activity maps.
Activity Request β Static Map Check β CDN/Local β Fallback to API
β
[jsDelivr CDN] β [Local Files] β [Mapbox API]
- π° Zero Runtime Costs - Pre-generated maps eliminate API calls
- β‘ Instant Loading - 0ms load time for cached maps
- π Global CDN - jsDelivr provides worldwide fast delivery
- π§ Smart Preloading - Adjacent activities preloaded automatically
- π Intelligent Fallback - Seamless fallback when maps unavailable
# Optional: Force CDN-first mode (recommended for production)
NEXT_PUBLIC_PREFER_CDN=true
# Optional: Prefer local maps (development only)
NEXT_PUBLIC_PREFER_LOCAL_MAPS=trueconst IMAGE_CACHE_DURATION = 10 * 60 * 1000 // 10 minutes
const imagePreloadCache = new Map<string, CacheEntry>()
// Automatic cleanup every 5 minutes
setInterval(cleanupImageCache, 5 * 60 * 1000)- jsDelivr CDN: 7-day cache with global distribution
- Browser Cache: 10-minute cache for instant switching
- Preload Strategy: Β±2 adjacent activities preloaded
- Fallback Chain: CDN β Local β Mapbox API
// Automatic cache detection
const mapCheck = await checkStaticMapExists(activityId)
if (mapCheck.exists) {
// Use CDN URL
return `https://cdn.jsdelivr.net/gh/user/repo@master/apps/web/public/maps/${activityId}.png`
} else {
// Fallback to Mapbox API
return generateMapboxUrl(activity)
}const isProduction = process.env.NODE_ENV === 'production'
const preferCDN = process.env.NEXT_PUBLIC_PREFER_CDN === 'true' || isProduction
if (preferCDN || isProduction) {
// Always try CDN first in production
console.log(`π Trying CDN first (production mode): ${cdnUrl}`)
}// Preload adjacent activity maps for better UX
const preloadAdjacentMaps = async (activities: Activity[], currentIndex: number) => {
// Preload previous and next 2 activities
for (let i = Math.max(0, currentIndex - 2); i <= Math.min(activities.length - 1, currentIndex + 2); i++) {
if (i === currentIndex) continue // Skip current activity
const activity = activities[i]
if (!activity.startLatitude || !activity.startLongitude) continue
// Preload in background without blocking UI
preloadMapInBackground(activity)
}
}# Check cache performance
curl https://run2.miaowu.org/api/cache/stats
# Response
{
"totalMaps": 423,
"cacheHitRate": "94.2%",
"avgLoadTime": "245ms",
"cdnHits": 387,
"localHits": 36,
"apiFallbacks": 0
}// Expected logs for successful cache hit
π Checking static map for activity 15002226211
π Static map check result: {exists: true, source: 'cdn'}
β
Using cdn map: https://cdn.jsdelivr.net/gh/oiahoon/running2.0@master/apps/web/public/maps/15002226211.png
π¦ Using cached map image (instant load)- Cache Hit Rate: 90%+ expected
-
Load Time:
- Cached maps: 0-200ms
- CDN maps: 200-1000ms
- API fallback: 2000-5000ms
- Cost Reduction: 99%+ API calls eliminated
# .github/workflows/sync-data.yml
- name: Generate Static Maps
run: |
cd scripts
python generate-static-maps.py
- name: Commit Maps
run: |
git add apps/web/public/maps/
git commit -m "πΊοΈ Update static maps"
git push# Generate maps for specific activity
cd scripts && node generate-maps-manual.js [activity_id]
# Generate all missing maps
cd scripts && python generate-static-maps.py
# Test map generation
cd scripts && python test-mapbox-token.pyapps/web/public/maps/
βββ 15002226211.png # Activity external_id as filename
βββ 15002226156.png
βββ 15002226174.png
βββ ...
πΊοΈ Creating map URL for 1 activities
π― Single activity detected, trying static map firstπ§ Environment: production, preferCDN: true, preferLocal: false
π Trying CDN first (production mode): https://cdn.jsdelivr.net/gh/...
π‘ CDN response: 200 OKβ
Using cdn map for activity 15002226211: https://cdn.jsdelivr.net/gh/...
π¦ Using cached map image (instant load)π Preloaded adjacent map: https://cdn.jsdelivr.net/gh/.../15002226156.png
π Preloaded adjacent map: https://cdn.jsdelivr.net/gh/.../15002226174.pngSymptoms: All maps show Mapbox API URLs instead of CDN Debug: Check browser console for:
β οΈ Static map check failed: ReferenceError: checkStaticMapExists is not defined
Solution: Ensure proper import in components:
import { checkStaticMapExists } from '@/lib/utils/cdn'Symptoms: CDN URLs return 404 Not Found Debug:
π‘ CDN response: 404 Not Found
π Falling back to Mapbox API
Solutions:
- Wait for jsDelivr to sync (up to 24 hours)
- Check if files exist in GitHub repository
- Verify GitHub repository is public
Symptoms: Maps take 2-5 seconds to load Debug: Check Network tab for:
- CDN requests timing out
- Fallback to Mapbox API Solutions:
- Increase CDN timeout:
setTimeout(() => controller.abort(), 20000) - Enable CDN-first mode:
NEXT_PUBLIC_PREFER_CDN=true
// Check cache status
localStorage.getItem('map-cache-stats')
// Clear cache
localStorage.clear()
// Monitor performance
performance.getEntriesByType('navigation')# Test specific map availability
curl -I "https://cdn.jsdelivr.net/gh/oiahoon/running2.0@master/apps/web/public/maps/15002226211.png"
# Check server-side files
curl "https://run2.miaowu.org/api/check-maps?activityId=15002226211"
# Monitor cache statistics
curl "https://run2.miaowu.org/api/cache/stats"-
Use local preference: Set
NEXT_PUBLIC_PREFER_LOCAL_MAPS=true - Test CDN URLs manually before deployment
- Monitor console logs for cache behavior
- Clear browser cache when testing changes
-
Enable CDN-first mode:
NEXT_PUBLIC_PREFER_CDN=true -
Monitor cache hit rates via
/api/cache/stats - Set up alerts for high API usage (indicates cache misses)
- Regular map generation via GitHub Actions
- Preload strategy: Adjust preload range based on user behavior
- Cache duration: Balance between freshness and performance
- CDN timeout: Optimize based on your CDN performance
- Fallback strategy: Ensure graceful degradation
- Map Load Time: 2-5 seconds per map
- API Calls: 1 call per map view
- Cost: $X per 1000 map views
- User Experience: Loading states, delays
- Map Load Time: 0-200ms (cached), 200-1000ms (CDN)
- API Calls: <1% of original (99%+ reduction)
- Cost: Near zero for cached maps
- User Experience: Instant switching, smooth navigation
This caching system transforms the user experience from slow, costly map generation to instant, free map display! π