[Website] Fix service worker cache purging to support multi-tab scenarios#3414
Draft
brandonpayton wants to merge 4 commits intotrunkfrom
Draft
[Website] Fix service worker cache purging to support multi-tab scenarios#3414brandonpayton wants to merge 4 commits intotrunkfrom
brandonpayton wants to merge 4 commits intotrunkfrom
Conversation
self.serviceWorker.state has been available in Firefox since v120 (Nov 2023). Update the misleading comment and make the @ts-ignore annotation more descriptive. The guard is kept as a safety net.
After a service worker update, old tabs still hold references to hashed asset URLs from the previous build. These assets are gone from the current cache and the server, causing 404s and "Failed to initialize WordPress" errors. Search all previous playground-cache-* caches before going to the network so old tabs can still find their assets. Also add purgeExcessOldCaches() which keeps the most recent old cache instead of purging everything, bounding storage to ~3 versions.
Switch from purgeEverythingFromPreviousRelease() to purgeExcessOldCaches() so old tabs can still resolve their hashed asset URLs from the previous build's cache.
brandonpayton
commented
Mar 18, 2026
Member
Author
brandonpayton
left a comment
There was a problem hiding this comment.
I'm not sure what I think about this yet but would like to explore it.
| // hashed asset URLs from the previous build. Search older | ||
| // caches before going to the network so those tabs don't 404. | ||
| const previousVersionResponse = await matchInPreviousVersionCaches(request); | ||
| if (previousVersionResponse) { |
Member
Author
There was a problem hiding this comment.
I'm not sure if all packages produce a hashed filename. I have a vague memory of at least one exception to the name-with-hash approach, but it might have been for Node.js deps consumed by Studio builds. We need to make sure.
Comment on lines
+181
to
+183
| // Keep the last entry (typically the most recent old cache) | ||
| // and delete the rest. | ||
| const toDelete = oldNames.slice(0, -1); |
Member
Author
There was a problem hiding this comment.
It's a bit weak to depend up on the last being "typically the most recent". We need to look more closely at this.
f17dca7 to
c14345a
Compare
The test was skipped because it used an outdated UI flow (the "Add Playground" modal no longer exists). Rewrite the test to create a new site via URL query parameters instead, which is the current pattern for specifying WordPress version and language.
c14345a to
2912b06
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
cacheFirstFetchnow falls back toprevious-version
playground-cache-*caches before going to thenetwork, so old tabs can still resolve their hashed asset URLs
purgeExcessOldCaches()instead ofpurgeEverythingFromPreviousRelease(), keeping the most recent oldcache (bounded to ~3 versions total)
this issue
Problem
When a new version of Playground is deployed, the service worker
immediately activates (
skipWaiting()) and purges all old cachedassets. Existing browser tabs still hold references to old hashed asset
URLs (e.g.,
php_8_3-2286e20c.js). These assets are gone from bothcache and server, causing 404s and "Failed to initialize WordPress"
errors.
This particularly affects users with multiple Playground tabs open
during a deploy.
Approach
Two complementary changes:
Fallback cache search:
cacheFirstFetchchecks all olderplayground-cache-*caches after a miss in the current build'scache, before going to the network. This lets old tabs find their
hashed assets in the previous version's cache.
Retain one old cache:
purgeExcessOldCaches()replaces theprevious purge-everything behavior. It keeps the most recent old
cache and deletes the rest, so old tabs have somewhere to find their
assets. The surviving cache gets cleaned up on the next deploy.
Only the cache-first path needs the fallback —
networkFirstFetch(used for
remote.htmland/) already fetches fresh content.Test plan
npx nx test playground-remotepassesnpx nx lint playground-remotepassesnpx nx e2e playground-website— deployment tests, including there-enabled multi-tab test
the first tab doesn't crash