@@ -200,22 +200,45 @@ self.addEventListener('fetch', (event) => {
200200
201201 event . respondWith (
202202 ( async ( ) => {
203+ // Normalize URL to prevent duplicates from path variations
204+ const requestUrl = new URL ( event . request . url ) ;
205+ let pathname = requestUrl . pathname ;
206+
207+ // Normalize trailing slashes - /books/ and /books should be the same
208+ if ( pathname . length > 1 && pathname . endsWith ( '/' ) ) {
209+ pathname = pathname . slice ( 0 , - 1 ) ;
210+ }
211+
212+ // For navigation requests, ignore query params in cache key
213+ // (browser may add its own params like _x_tr_sl for translation)
214+ const cacheKey = event . request . mode === 'navigate'
215+ ? pathname
216+ : pathname + requestUrl . search ;
217+
203218 // Try cache first
204219 const cache = await caches . open ( CACHE_NAME ) ;
205- const cachedResponse = await cache . match ( event . request ) ;
220+ const cachedResponse = await cache . match ( cacheKey ) ;
206221
207222 if ( cachedResponse ) {
208223 return cachedResponse ;
209224 }
210225
211- // Not in cache, fetch from network
226+ // Not in cache, fetch from network with cache buster
212227 try {
213- const networkResponse = await fetch ( event . request ) ;
228+ // Add cache buster to bypass browser HTTP cache
229+ const bustUrl = new URL ( event . request . url ) ;
230+ bustUrl . searchParams . set ( '_cb' , Date . now ( ) ) ;
231+ const networkResponse = await fetch ( bustUrl . toString ( ) , {
232+ method : event . request . method ,
233+ headers : event . request . headers ,
234+ mode : 'cors' ,
235+ credentials : event . request . credentials
236+ } ) ;
214237
215- // Cache the response for future use
238+ // Cache the response for future use (using URL as key to prevent duplicates)
216239 if ( networkResponse . ok ) {
217240 const responseToCache = networkResponse . clone ( ) ;
218- cache . put ( event . request , responseToCache ) ;
241+ cache . put ( cacheKey , responseToCache ) ;
219242 }
220243
221244 return networkResponse ;
0 commit comments