New markup over an old stylesheet

Reported from a desktop browser: a stray close button beside the logo, badly
drawn, and a page that would not scroll. None of it was in the code that was
running -- it was the code the browser had not fetched.

The worker caches /static/ under a cache named for the release while the files
in it carried no version, and a page is fetched network-first. That only ever
worked because the worker used to seize every open tab the instant it installed
and wipe the old cache. 1.1.0 stopped it doing that, rightly -- it was swapping
stylesheets out from under a streaming reply -- and a momentary mismatch became
a permanent one: new markup over the previous release's CSS for as long as the
old worker lived. `.sidebar__close` had no rule there, so `.btn--icon` made it
inline-flex: visible everywhere, placed by nothing.

Every /static/ URL carries the release now, written by `templating.asset` and
precached by `sw.js:versioned` -- both halves, because caches.match compares the
query too and precaching the bare path would cache entries nothing requests.
Self-correcting: updating is enough.

The header was also a brand with a button appended and margin-left:auto doing
the placing, which holds exactly while that button is last. Two slots now: a
brand that shrinks and truncates, and a rail on the trailing edge.

Verified before changing anything: with the current stylesheet the button is
display:none at 1280 and, with thirty chats and forty messages, both scrollers
scroll. The first measurement said the thread did not -- that was
scroll-behavior: smooth reporting where it started.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-25 18:16:24 +00:00
co-authored by Claude Opus 5
parent 28390095a9
commit 201281d616
18 changed files with 216 additions and 48 deletions
+14 -1
View File
@@ -50,6 +50,18 @@ var SHELL = [
"/static/img/apple-touch-icon-180.png",
];
/* The URL a page will actually ask for.
Every `/static/` link carries `?v=<release>` -- see `templating.asset` -- and
`caches.match` compares the whole URL, query included. So precaching the bare
path would fill the cache with entries no page ever requests, and every asset
would go to the network on every load while looking perfectly cached.
`/offline` is a route rather than an asset and is left alone. */
function versioned(path) {
return path.indexOf("/static/") === 0 ? path + "?v=" + VERSION : path;
}
self.addEventListener("install", function (event) {
event.waitUntil(
caches.open(CACHE).then(function (cache) {
@@ -57,7 +69,8 @@ self.addEventListener("install", function (event) {
// and the whole feature silently off, so each entry is added on its own.
return Promise.all(
SHELL.map(function (path) {
return cache.add(new Request(path, { cache: "reload" })).catch(function () {});
return cache.add(new Request(versioned(path), { cache: "reload" }))
.catch(function () {});
})
);
})