Changeset e2ea5c4 in Klonkt


Ignore:
Timestamp:
07/21/2026 03:55:26 AM (7 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
fb30b5d
Parents:
f574435
git-author:
Robin <roboburr@…> (07/21/2026 03:55:23 AM)
git-committer:
Robin <roboburr@…> (07/21/2026 03:55:26 AM)
Message:

Fix: online visitors always get the fresh site, never a cached copy

The service worker was already network-first, but two gaps let a stale page
through while online:

  • the SW's navigation fetch used the browser HTTP cache, so it could return a heuristically-cached page even though it "fetched",
  • full HTML pages carried no Cache-Control, so the browser was free to cache them heuristically.

Now the SW fetches navigations with { cache: 'no-store' } (straight to the
network, cache is only the offline .catch fallback), and renderPage sends
Cache-Control: no-cache on full pages (revalidate; still bfcache-friendly,
partials stay no-store). Verified live: /sw.js uses no-store and GET / returns
Cache-Control: no-cache. Bumped the SW cache name v17 -> v18.

Changed files:
src/server.js

  • sw.js navigation fetch uses { cache: 'no-store' }; cache name v18

src/middleware/render.js

  • full HTML pages get Cache-Control: no-cache (partials stay no-store)

-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>

Location:
src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/middleware/render.js

    rf574435 re2ea5c4  
    7373  // (Vary also applies to intermediate caches / Cloudflare.)
    7474  res.setHeader('Vary', 'HX-Request');
    75   if (isPartial) res.setHeader('Cache-Control', 'no-store');
     75  // A full HTML page must always be revalidated so an online visitor gets the
     76  // fresh site, never a heuristically-cached copy. no-cache (not no-store) still
     77  // allows bfcache and conditional requests. Partials stay no-store (see above).
     78  res.setHeader('Cache-Control', isPartial ? 'no-store' : 'no-cache');
    7679
    7780  // Does this (non-god) user own a site? Determines whether they see an "Admin"
  • src/server.js

    rf574435 re2ea5c4  
    478478  res.set('Cache-Control', 'no-cache');
    479479  res.send(`
    480 const CACHE_VERSION = 'pcms-v17-' + new Date().toISOString().split('T')[0];
     480const CACHE_VERSION = 'pcms-v18-' + new Date().toISOString().split('T')[0];
    481481self.addEventListener('install', e => {
    482482  e.waitUntil(caches.open(CACHE_VERSION).then(c => c.addAll(['/'])));
     
    503503  try { if (new URL(e.request.url).origin !== self.location.origin) return; } catch (err) { return; }
    504504  e.respondWith(
    505     fetch(e.request).then(resp => {
     505    // { cache: 'no-store' }: go to the network for the page, bypassing the browser's
     506    // HTTP cache, so an online visitor ALWAYS gets the fresh site and never a
     507    // heuristically-cached copy served through the SW. The cache is only a
     508    // last-resort offline fallback (the .catch below).
     509    fetch(e.request, { cache: 'no-store' }).then(resp => {
    506510      // Network-first: always serve fresh when online. Also refresh the '/' offline
    507511      // fallback with the homepage we just served, so a later cold start on a flaky or
Note: See TracChangeset for help on using the changeset viewer.