Skip to content

Fix stale service worker asset caching#372

Merged
Producdevity merged 3 commits into
stagingfrom
fix/stale-static-asset-cache
May 25, 2026
Merged

Fix stale service worker asset caching#372
Producdevity merged 3 commits into
stagingfrom
fix/stale-static-asset-cache

Conversation

@Producdevity
Copy link
Copy Markdown
Owner

@Producdevity Producdevity commented May 25, 2026

Description

Fixes #358

This keeps service worker registration in the App Router setup and renames the worker to /sw.js, matching the Next.js PWA docs. It also removes the old registration script and narrows the cache-control headers so missing Next static assets do not get immutable caching.

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactor
  • Other (please describe):

How Has This Been Tested?

  • Local build
  • Lint
  • Typecheck
  • Unit tests
  • Manual testing

Screenshots (if applicable)

N/A

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have made corresponding changes to the documentation
  • I have checked that all checks (lint, typecheck, test) pass

Notes for reviewers

After deploy, purge Cloudflare/Vercel cached /_next/static/* responses, or do a full cache purge, because stale immutable 404s can survive outside the codebase.

Summary by CodeRabbit

  • New Features

    • Improved offline behavior: network failures fall back to cached content.
    • More robust notification handling and smarter focus/open behavior on clicks.
  • Bug Fixes

    • Service worker registration now respects production/HTTPS gating and avoids mis-registration.
    • Development HTML responses no longer get cached unexpectedly.
  • Chores

    • Reworked service worker registration flow and simplified cache version syncing.
  • Tests

    • Added tests covering registration gating and sync/unregister behaviors.

Review Change Stack

@vercel
Copy link
Copy Markdown

vercel Bot commented May 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
emuready Ready Ready Preview, Comment May 25, 2026 10:28am

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 1e88929a-adb1-4d01-9746-55fb67dcd6fd

📥 Commits

Reviewing files that changed from the base of the PR and between fa42266 and a961564.

📒 Files selected for processing (2)
  • public/sw.js
  • scripts/sync-version.js

Walkthrough

Replaces inline service-worker scripts with a React ServiceWorkerRegistrar, hardens public/sw.js (fetch/push/notificationclick), updates Next.js cache-control headers for /sw.js and dev HTML, and centralizes cache-version syncing for the service worker asset.

Changes

Service Worker Registration Refactor

Layer / File(s) Summary
Service Worker Registrar component and orchestration
src/app/ServiceWorkerRegistrar.tsx
New Registrar with shouldRegisterServiceWorker() gating and syncServiceWorker() that unregisters unexpected workers, clears app caches (emuready_*), and registers /sw.js when allowed.
Registrar tests
src/app/ServiceWorkerRegistrar.test.tsx
Vitest suite mocking navigator.serviceWorker and caches, exercising gating and sync behaviors for enabled/disabled scenarios.
Service worker script enhancements
public/sw.js
Adds normalizePathname(), makes fetch fallback to cache on network errors, validates push payloads with try/catch and title/body checks, and matches clients by normalized pathname on notificationclick.
Cache control headers and version sync
next.config.ts, scripts/sync-version.js
Adds Header type, sets Cache-Control: no-store, no-cache, must-revalidate for /sw.js, changes dev HTML caching rule to /:path* with accept-header predicate, and refactors sync-version.js to update public/sw.js via a versionTargets loop.
Layout integration and cleanup
src/app/layout.tsx, src/app/robots.ts
Removes inline /sw-register.js usage from <head>, imports and renders ServiceWorkerRegistrar in <body> with enabled={env.ENABLE_SW}, and removes /sw-register.js from robots disallow list.

Sequence Diagram

sequenceDiagram
  participant Layout
  participant Registrar
  participant Sync as syncServiceWorker
  participant Navigator as navigator.serviceWorker
  participant CacheAPI as caches
  Layout->>Registrar: render(enabled)
  Registrar->>Sync: useEffect -> syncServiceWorker(enabled)
  Sync->>Sync: shouldRegisterServiceWorker(enabled, location)
  alt Disabled or Invalid Host
    Sync->>Navigator: unregister all registrations
    Sync->>CacheAPI: delete app caches (emuready_*)
  else Enabled and Valid
    Sync->>Navigator: unregister unexpected workers (not /sw.js)
    Sync->>Navigator: register /sw.js (scope: /, updateViaCache: 'none')
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: fixing stale service worker asset caching as described in the PR objectives.
Description check ✅ Passed The description includes required sections, references issue #358, identifies the bug fix type, documents testing performed, and provides reviewer notes about cache purging.
Linked Issues check ✅ Passed Changes address issue #358 by: renaming worker to /sw.js matching Next.js PWA docs, removing old registration script, removing immutable caching headers from missing static assets, and restructuring registration in ServiceWorkerRegistrar.
Out of Scope Changes check ✅ Passed All changes directly address issue #358: service worker file reorganization, registration refactoring, cache control header fixes, and cache version synchronization are all within scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/stale-static-asset-cache
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/stale-static-asset-cache

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@public/sw.js`:
- Line 281: Guard against missing notification or data before reading url:
change the code that constructs targetUrl (the line creating targetUrl in the
service worker) to first obtain a safeUrl from event.notification and its data
(e.g., use event.notification && event.notification.data &&
event.notification.data.url or optional chaining event.notification?.data?.url)
falling back to '/' and then call new URL(safeUrl, self.location.origin) to
avoid throwing when notification.data is absent.
- Around line 194-214: The cache update (cache.put(event.request,
modifiedResponse)) is started but not awaited, so the service worker may stop
before it completes; wrap or include the cache.put promise in event.waitUntil so
the worker stays alive until the cache write finishes — e.g., after creating
modifiedResponse and before returning response in the fetchPromise chain, call
event.waitUntil(...) with the cache.put(...) promise (or include the cache.put
in a Promise returned from fetchPromise) while still returning the original
response from fetchPromise; reference fetchPromise, modifiedResponse, cache.put,
event.waitUntil and event.respondWith to locate where to attach the waitUntil.

In `@scripts/sync-version.js`:
- Around line 19-33: The script currently assumes the file contains a matching
CACHE_NAME and a numeric-only version, so replace() can silently no-op; update
versionRegex to accept prerelease characters (e.g. change const versionRegex =
/const CACHE_NAME = 'emuready_v([\d.]+)'/ to a pattern that allows
hyphens/letters like /const CACHE_NAME = 'emuready_v([\dA-Za-z.-]+)'/), and add
a fail-fast check: inside the loop after const match =
content.match(versionRegex) throw a descriptive Error (including target.path and
the expected CACHE_NAME pattern) if !match so the script exits when the service
worker doesn't match the expected pattern; keep the existing replacement/write
logic and updatedTargets push otherwise.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2708fe6f-9f69-4af4-9070-cee41596c081

📥 Commits

Reviewing files that changed from the base of the PR and between 05c261f and fa42266.

📒 Files selected for processing (8)
  • next.config.ts
  • public/sw-register.js
  • public/sw.js
  • scripts/sync-version.js
  • src/app/ServiceWorkerRegistrar.test.tsx
  • src/app/ServiceWorkerRegistrar.tsx
  • src/app/layout.tsx
  • src/app/robots.ts
💤 Files with no reviewable changes (2)
  • src/app/robots.ts
  • public/sw-register.js

Comment thread public/sw.js
Comment thread public/sw.js Outdated
Comment thread scripts/sync-version.js Outdated
@Producdevity Producdevity merged commit 8642726 into staging May 25, 2026
8 checks passed
@Producdevity Producdevity deleted the fix/stale-static-asset-cache branch May 25, 2026 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Emuready not loading

1 participant