Fix console errors: SW partial response caching, deprecated meta tag, unused preload#1726
Fix console errors: SW partial response caching, deprecated meta tag, unused preload#1726
Conversation
Dependency Reviewβ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
β¦ta tag and unused preload - Fix service worker cache.put() error on status 206 (partial responses) by adding response.status !== 206 check before caching - Remove deprecated X-UA-Compatible meta tag (IE/Chrome Frame discontinued) - Remove unused preload for black-trigram.png (loaded by React component, not consumed fast enough causing browser warning) - Update docs/ deployed files with same fixes - Add tests for partial response filtering, deprecated meta tag removal, and preload removal Co-authored-by: pethers <1726836+pethers@users.noreply.github.com> Agent-Logs-Url: https://github.com/Hack23/blacktrigram/sessions/8ab46ff8-8857-4b9b-8ccb-3b7d507d1fd3
πΈ Automated UI Screenshotsπ Screenshots Captured (8)
π¦ Download Screenshotsπ₯ Download all screenshots from workflow artifacts
π€ Generated by Playwright automation |
There was a problem hiding this comment.
Pull request overview
Fixes production console warnings/errors by hardening Service Worker caching against HTTP 206 (Partial Content) responses and cleaning up deprecated/unused HTML tags in the deployed entrypoints.
Changes:
- Update SW fetch caching to skip HTTP 206 responses (Range requests) before calling
cache.put(). - Remove deprecated
X-UA-Compatiblemeta tag and an unusedpreloadlink fromindex.html(anddocs/index.html). - Add unit tests asserting the 206 filter and the absence of the removed HTML tags.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
public/sw.js |
Excludes 206 responses from being cached to prevent cache.put() errors. |
docs/sw.js |
Mirrors the SW 206 exclusion in the docs deployment. |
index.html |
Removes deprecated X-UA-Compatible and an unused image preload link. |
docs/index.html |
Mirrors index.html cleanup for docs deployment. |
src/test/service-worker.test.ts |
Adds tests covering the 206 filter and HTML cleanup expectations. |
Comments suppressed due to low confidence (1)
public/sw.js:92
cache.put(event.request, ...)will reject for non-GET requests (Cache API only supports GET). Since this fetch handler runs for all requests, add a guard likeevent.request.method === "GET"(or early-return) before attempting to cache to avoid future console errors/unhandled rejections if the app ever makes POST/PUT requests.
// Only cache successful, complete, non-opaque responses
// Skip partial responses (206) as Cache API does not support them
if (response.ok && response.status !== 206 && response.type !== "opaque") {
// Clone response for caching (responses can only be used once)
const responseClone = response.clone();
// Cache for offline fallback only
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseClone);
});
public/sw.js
Outdated
| // Only cache successful, complete, non-opaque responses | ||
| // Skip partial responses (206) as Cache API does not support them | ||
| if (response.ok && response.status !== 206 && response.type !== "opaque") { | ||
| // Clone response for caching (responses can only be used once) | ||
| const responseClone = response.clone(); | ||
|
|
There was a problem hiding this comment.
The caching side-effect (caches.open(...).then(cache => cache.put(...))) doesnβt handle rejections. Even with the 206 filter, cache.put can still reject (e.g., quota errors, non-GET requests), which can show up as unhandled promise rejections in the SW. Consider adding a .catch(...) (and/or wrapping the cache write in event.waitUntil(...)) to suppress console noise and ensure the SW stays alive long enough to complete the cache write.
docs/sw.js
Outdated
| // Only cache successful, complete, non-opaque responses | ||
| // Skip partial responses (206) as Cache API does not support them | ||
| if (response.ok && response.status !== 206 && response.type !== "opaque") { | ||
| // Clone response for caching (responses can only be used once) | ||
| const responseClone = response.clone(); | ||
|
|
There was a problem hiding this comment.
Same as public/sw.js: cache.put(event.request, ...) will reject for non-GET requests. Add a guard (e.g., event.request.method === "GET") before caching so a future POST/PUT request doesnβt trigger SW console errors.
src/test/service-worker.test.ts
Outdated
|
|
||
| // Cache API rejects put() with status 206 (Partial Content) | ||
| // The SW must filter these out before calling cache.put() | ||
| expect(swSource).toContain('response.status !== 206'); |
There was a problem hiding this comment.
The test is asserting an exact string ('response.status !== 206'), which is fragile to harmless refactors/formatting. A regex assertion (e.g., matching status compared to 206 with arbitrary whitespace) or a more behavioral test approach would reduce churn while still ensuring 206 responses arenβt cached.
| expect(swSource).toContain('response.status !== 206'); | |
| expect(swSource).toMatch(/response\.status\s*!==?\s*206/); |
src/test/service-worker.test.ts
Outdated
| it('should not preload assets that are loaded by React components', () => { | ||
| // Preloading assets used by React components causes "not used within a few seconds" warnings | ||
| // because React takes time to bootstrap and mount the component that uses the asset | ||
| expect(indexHtml).not.toContain('rel="preload"'); |
There was a problem hiding this comment.
expect(indexHtml).not.toContain('rel="preload"') is case/quote sensitive and can miss <link rel='preload'> or different attribute ordering. Using a case-insensitive regex for rel\s*=\s*["']preload["'] (or checking for <link tags with rel preload) would make the test reliably enforce the intent.
| expect(indexHtml).not.toContain('rel="preload"'); | |
| // Use a case-insensitive regex to catch rel='preload' with any quotes/spacing/case | |
| expect(indexHtml).not.toMatch(/rel\s*=\s*["']preload["']/i); |
πΈ Automated UI Screenshotsπ Screenshots Captured (8)
π¦ Download Screenshotsπ₯ Download all screenshots from workflow artifacts
π€ Generated by Playwright automation |
|
@copilot apply changes based on the comments in this thread |
β¦rites, regex-based test assertions - Add event.request.method === "GET" guard before caching in sw.js - Add .catch() to cache.put() promise to suppress quota/write errors - Use regex assertions in tests for 206 status and preload checks - Add tests for GET-only caching and cache write error handling - Apply same fixes to docs/sw.js Co-authored-by: pethers <1726836+pethers@users.noreply.github.com> Agent-Logs-Url: https://github.com/Hack23/blacktrigram/sessions/809ecb62-8166-4fc0-9380-a90d075a6322
Applied all 4 review comments in
|
public/sw.js
Outdated
| caches.open(CACHE_NAME).then((cache) => { | ||
| cache.put(event.request, responseClone); | ||
| }).catch(() => { | ||
| // Silently ignore cache write failures (e.g., quota exceeded) | ||
| }); |
There was a problem hiding this comment.
The .catch() here only handles failures from caches.open(...). If cache.put(...) rejects (e.g., quota exceeded, request/response not cacheable), that rejection is currently unhandled because the cache.put promise is not returned or caught. Return cache.put(...) from the .then(...) callback (or attach a .catch() directly to cache.put) so cache write failures are actually suppressed as intended.
| caches.open(CACHE_NAME).then((cache) => { | |
| cache.put(event.request, responseClone); | |
| }).catch(() => { | |
| // Silently ignore cache write failures (e.g., quota exceeded) | |
| }); | |
| caches.open(CACHE_NAME) | |
| .then((cache) => { | |
| return cache.put(event.request, responseClone); | |
| }) | |
| .catch(() => { | |
| // Silently ignore cache write failures (e.g., quota exceeded) | |
| }); |
docs/sw.js
Outdated
| caches.open(CACHE_NAME).then((cache) => { | ||
| cache.put(event.request, responseClone); | ||
| }).catch(() => { | ||
| // Silently ignore cache write failures (e.g., quota exceeded) | ||
| }); |
There was a problem hiding this comment.
Same issue as in public/sw.js: the .catch() is attached to caches.open(...) but the cache.put(...) promise is not returned/caught, so cache.put rejections can still surface as unhandled promise rejections in the SW. Return cache.put(...) from the .then(...) (or catch on cache.put) to reliably suppress cache write failures.
| caches.open(CACHE_NAME).then((cache) => { | |
| cache.put(event.request, responseClone); | |
| }).catch(() => { | |
| // Silently ignore cache write failures (e.g., quota exceeded) | |
| }); | |
| caches | |
| .open(CACHE_NAME) | |
| .then((cache) => cache.put(event.request, responseClone)) | |
| .catch(() => { | |
| // Silently ignore cache write failures (e.g., quota exceeded) | |
| }); |
src/test/service-worker.test.ts
Outdated
| // unhandled promise rejections in the service worker | ||
| expect(swSource).toMatch(/\.catch\s*\(/); |
There was a problem hiding this comment.
This test only asserts that some .catch( exists in sw.js, but it doesnβt verify that cache.put(...) failures are actually handled (which requires returning the cache.put promise from the .then(...) or catching the cache.put promise directly). Consider tightening the assertion to specifically match cache.put(...).catch or then((cache) => return cache.put(...)) so the test guards against the unhandled-rejection regression itβs meant to prevent.
| // unhandled promise rejections in the service worker | |
| expect(swSource).toMatch(/\.catch\s*\(/); | |
| // unhandled promise rejections in the service worker. Ensure that | |
| // cache.put(...) is part of a handled promise chain. | |
| expect(swSource).toMatch(/cache\.put\([^)]*\)\.catch\s*\(|then\(\s*cache\s*=>\s*cache\.put\(/); |
src/test/service-worker.test.ts
Outdated
| it('should not preload assets that are loaded by React components', () => { | ||
| // Preloading assets used by React components causes "not used within a few seconds" warnings | ||
| // because React takes time to bootstrap and mount the component that uses the asset | ||
| // Use a case-insensitive regex to catch rel='preload' with any quotes/spacing/case | ||
| expect(indexHtml).not.toMatch(/rel\s*=\s*["']preload["']/i); |
There was a problem hiding this comment.
This assertion forbids any <link rel="preload"> in index.html, including legitimate preloads (e.g., critical fonts/CSS) that might be added later. Since the change is specifically removing the unused logo preload, it would be more maintainable to assert the absence of that specific preload (e.g., black-trigram.png with rel=preload) rather than banning all preload usage.
| it('should not preload assets that are loaded by React components', () => { | |
| // Preloading assets used by React components causes "not used within a few seconds" warnings | |
| // because React takes time to bootstrap and mount the component that uses the asset | |
| // Use a case-insensitive regex to catch rel='preload' with any quotes/spacing/case | |
| expect(indexHtml).not.toMatch(/rel\s*=\s*["']preload["']/i); | |
| it('should not preload logo asset that is loaded by React components', () => { | |
| // Preloading assets used exclusively by React components (like the black trigram logo) | |
| // can cause "not used within a few seconds" warnings because React takes time to bootstrap | |
| // and mount the component that uses the asset. | |
| // Assert specifically that black-trigram.png is not preloaded with rel="preload", | |
| // while allowing other legitimate preloads (e.g., critical fonts or CSS). | |
| expect(indexHtml).not.toMatch( | |
| /<link[^>]+rel\s*=\s*["']preload["'][^>]+href\s*=\s*["'][^"']*black-trigram\.png["']/i | |
| ); |
πΈ Automated UI Screenshotsπ Screenshots Captured (8)
π¦ Download Screenshotsπ₯ Download all screenshots from workflow artifacts
π€ Generated by Playwright automation |
|
@copilot apply changes based on the comments in this thread |
- Return cache.put() from .then() callback so its rejections are caught by the .catch() handler in both public/sw.js and docs/sw.js - Tighten test assertion to verify cache.put() is in a handled promise chain - Narrow preload test to only assert black-trigram.png is not preloaded, allowing legitimate future preloads (e.g., critical fonts/CSS) Co-authored-by: pethers <1726836+pethers@users.noreply.github.com> Agent-Logs-Url: https://github.com/Hack23/blacktrigram/sessions/5860e0ea-df8c-4c08-9252-899271be367f
Applied all 4 review comments in
|
docs/sw.js
Outdated
| caches | ||
| .open(CACHE_NAME) | ||
| .then((cache) => { | ||
| return cache.put(event.request, responseClone); | ||
| }) | ||
| .catch(() => { | ||
| // Silently ignore cache write failures (e.g., quota exceeded) | ||
| }); |
There was a problem hiding this comment.
Same as public/sw.js: the cache write promise chain isnβt passed to event.waitUntil(...), so the SW may terminate before cache.put() completes, making offline caching unreliable. Consider event.waitUntil(caches.open(...).then(...).catch(...)) around this chain.
| caches | |
| .open(CACHE_NAME) | |
| .then((cache) => { | |
| return cache.put(event.request, responseClone); | |
| }) | |
| .catch(() => { | |
| // Silently ignore cache write failures (e.g., quota exceeded) | |
| }); | |
| event.waitUntil( | |
| caches | |
| .open(CACHE_NAME) | |
| .then((cache) => { | |
| return cache.put(event.request, responseClone); | |
| }) | |
| .catch(() => { | |
| // Silently ignore cache write failures (e.g., quota exceeded) | |
| }) | |
| ); |
public/sw.js
Outdated
| caches | ||
| .open(CACHE_NAME) | ||
| .then((cache) => { | ||
| return cache.put(event.request, responseClone); | ||
| }) | ||
| .catch(() => { | ||
| // Silently ignore cache write failures (e.g., quota exceeded) | ||
| }); |
There was a problem hiding this comment.
The cache write is started asynchronously but the fetch event doesnβt use event.waitUntil(...) to extend the service worker lifetime for caches.open(...).then(cache.put...). That can make offline caching unreliable because the SW may terminate once respondWith resolves, before the cache.put() finishes. Wrap the cache-write promise chain in event.waitUntil(...) (still with the .catch(...) to swallow quota/write errors).
src/test/service-worker.test.ts
Outdated
| expect(swSource).toMatch(/cache\.put\([^)]*\);\s*\n\s*}\)\s*\n\s*\.catch\s*\(|then\(\s*\(cache\)\s*=>\s*\{\s*\n\s*return cache\.put\(/); | ||
|
|
There was a problem hiding this comment.
This testβs regex doesnβt actually guarantee that cache.put() is in a handled promise chain: the second alternative matches then(... return cache.put( even if there is no subsequent .catch(...). Consider splitting into clearer assertions (e.g., one that return cache.put( appears inside the caches.open(...).then(...) callback, and another that the chain includes a .catch( after it), or tighten the regex so it requires .catch after the then block.
| expect(swSource).toMatch(/cache\.put\([^)]*\);\s*\n\s*}\)\s*\n\s*\.catch\s*\(|then\(\s*\(cache\)\s*=>\s*\{\s*\n\s*return cache\.put\(/); | |
| expect(swSource).toMatch(/caches\.open\([^)]*\)\s*\.then\(\s*(?:\(\s*cache\s*\)|cache)\s*=>\s*\{/); | |
| expect(swSource).toMatch(/cache\.put\([^)]*\)[\s\S]*?\.catch\s*\(/); |
πΈ Automated UI Screenshotsπ Screenshots Captured (8)
π¦ Download Screenshotsπ₯ Download all screenshots from workflow artifacts
π€ Generated by Playwright automation |
|
@copilot apply changes based on the comments in this thread |
- public/sw.js + docs/sw.js: Wrap caches.open().then(cache.put()).catch() in event.waitUntil() to keep SW alive until cache write completes - src/test/service-worker.test.ts: Split into clearer assertions for caches.open().then() structure, return cache.put() with .catch(), and event.waitUntil() wrapper Co-authored-by: pethers <1726836+pethers@users.noreply.github.com> Agent-Logs-Url: https://github.com/Hack23/blacktrigram/sessions/bee6acf2-a8ba-4741-9559-9d61f576f1a3
Applied all 3 review comments in
|
src/test/service-worker.test.ts
Outdated
| // cache.put(...) is returned inside caches.open().then() and followed by .catch(), | ||
| // and the entire chain is wrapped in event.waitUntil() to keep the SW alive. | ||
| expect(swSource).toMatch(/event\.waitUntil\s*\(/); | ||
| expect(swSource).toMatch(/caches\s*\n?\s*\.open\([^)]*\)\s*\n?\s*\.then\(\s*\(cache\)\s*=>\s*\{/); | ||
| expect(swSource).toMatch(/return cache\.put\([^)]*\)[\s\S]*?\.catch\s*\(/); |
There was a problem hiding this comment.
The regex in this test is more prescriptive about formatting than necessary (e.g., it requires .then((cache) => { with parentheses and a block). This makes the test likely to fail on harmless refactors (implicit return, then(cache => ...), or different whitespace) even if the SW still correctly returns cache.put() and handles errors. Consider relaxing the pattern to assert the behavioral requirements (open cache β return cache.put(...) β .catch(...) within event.waitUntil) without enforcing a specific arrow-function formatting.
| // cache.put(...) is returned inside caches.open().then() and followed by .catch(), | |
| // and the entire chain is wrapped in event.waitUntil() to keep the SW alive. | |
| expect(swSource).toMatch(/event\.waitUntil\s*\(/); | |
| expect(swSource).toMatch(/caches\s*\n?\s*\.open\([^)]*\)\s*\n?\s*\.then\(\s*\(cache\)\s*=>\s*\{/); | |
| expect(swSource).toMatch(/return cache\.put\([^)]*\)[\s\S]*?\.catch\s*\(/); | |
| // cache.put(...) is invoked as part of the caches.open().then() chain, | |
| // followed by .catch(), and the entire chain is wrapped in event.waitUntil() | |
| // to keep the SW alive during the async work. | |
| expect(swSource).toMatch(/event\.waitUntil\s*\(/); | |
| expect(swSource).toMatch(/caches\s*\.\s*open\([^)]*\)[\s\S]*?\.then\([\s\S]*cache\.put\([^)]*\)[\s\S]*?\.catch\s*\(/); |
|
@copilot apply changes based on the comments in this thread |
πΈ Automated UI Screenshotsπ Screenshots Captured (8)
π¦ Download Screenshotsπ₯ Download all screenshots from workflow artifacts
π€ Generated by Playwright automation |
Replace 3 prescriptive assertions (requiring specific parentheses, block style, and return keyword) with 2 behavioral assertions that verify: - event.waitUntil() wraps the chain - caches.open().then() contains cache.put() followed by .catch() Co-authored-by: pethers <1726836+pethers@users.noreply.github.com> Agent-Logs-Url: https://github.com/Hack23/blacktrigram/sessions/ca681c44-a97e-4ec4-b2f1-8afe011f4195
Applied in |
πΈ Automated UI Screenshotsπ Screenshots Captured (8)
π¦ Download Screenshotsπ₯ Download all screenshots from workflow artifacts
π€ Generated by Playwright automation |
response.status !== 206checkevent.request.method === "GET"prevents non-GET cache failurescache.put()from.then()β rejections properly propagate to.catch()handlerevent.waitUntil()β keeps SW alive until cache write completesevent.waitUntil(),caches.open().then()βcache.put()β.catch()chain without enforcing specific formattingpublic/sw.jsanddocs/sw.jsβ¨ Let Copilot coding agent set things up for you β coding agent works faster and does higher quality work when set up for your repo.