faviconet som ikke ville dø

7. september 2026 meta designdevlog

Liten ting. Tok altfor lang tid. Faviconet, det lille ikonet i nettleserfanen, er den bitte minste ressursen på hele denne siden, og det kjempet hardere mot meg enn reverse-proxyen gjorde.

hva det skal være

Faneikonet her er et bitte lite BMK-monogram med et fjellglyf pakket inn i det, matchende lockupen i headeren. Jeg håndtegnet det ikke som et rasterbilde, jeg bygde det som en HTML-tile (static/_favicon-tile.html) med den faktiske vendorede Literata-fonten og de faktiske sidefargene, og rendret den så til PNG med Playwright, slik at glyfen faktisk bruker samme skrifttype som resten av siden i stedet for en eller annen fallback-systemfont som et SVG <text>-element stilltiende ville byttet inn. To størrelser genereres, 32px for fanen og 512px for alt som vil ha et større ikon (hjemmeskjerm-snarveier, den typen ting), pluss et apple-touch-icon på 180px.

<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png?v=2" />
<link rel="icon" type="image/png" sizes="512x512" href="/favicon-512.png?v=2" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=2" />

Legg merke til ?v=2 på slutten av hver. Den var ikke der opprinnelig. Det er arrvevet fra hele denne historien.

runde én: den bare oppdaterte seg ikke

Jeg tegnet om faviconet halvveis inn i redesignet, regenererte PNG-ene, deployet, oppdaterte siden. Gammelt ikon. Fortsatt den gamle fjellformen i fanen. Jeg antok jeg hadde rotet til bygget, sjekket filen på disk, og de nye bytene var akkurat der, riktige piksler, riktig fil, riktig sti. Nettleseren spurte bare ikke om den på nytt.

Viser seg at favicons er den ene ressurstypen der nettlesere cacher med noe nær religiøs hengivenhet, og for det meste ignorerer de vanlige cache-control-headerne du ville brukt for å knuse en cache på hva som helst annet. Chrome spesielt har historisk cachet en sides favicon lenge, uavhengig av hva serveren sier, noen ganger med behov for å tømme historikk og cache helt, noen ganger med behov for en faktisk URL-endring, ikke bare en fersk byte på samme URL. En enkel omlasting kom ikke til å røre den. Heller ikke omlasting med cache deaktivert i devtools, som var det jeg prøvde nummer to, og som normalt fikser akkurat denne klassen problemer.

runde to: å klandre feil lag

Før jeg fant ut det var nettleseren, brukte jeg en stund på å mistenke containeren i stedet, fordi denne stacken kjører bak Docker og jeg har blitt brent av forsinkede build-lag før (en faktisk annen bug tidligere i dette prosjektet involverte node_modules som ble ødelagt i en Docker-build fordi jeg ikke hadde skrevet en .dockerignore ennå). Så jeg gikk ned den stien først: bygget frontend-imaget på nytt med --no-cache, bekreftet at de nye PNG-bytene satt i frontend/build/client/favicon-32.png inni den kjørende containeren, curlet URL-en direkte mot containerens egen port for å omgå Caddy helt. Ferske bytes, hver gang, rett fra kilden. Serveren gjorde jobben sin riktig hele tiden. Det var aldri containeren. Det satt rent og skjært i min egen nettlesers favicon-cache, flere lag unna noe en deploy kunne rørt.

Det er den delen som faktisk kostet tiden: å utelukke min egen infrastruktur før jeg aksepterte at buggen bodde et sted jeg hadde null kontroll over.

fiksen

Du kan ikke be en nettlesers favicon-cache om å invalideres. Det du kan gjøre er å slutte å spørre om samme URL. Alt jeg prøvde før jeg fant ut det beholdt samme URL:

<!-- before: same URL every time, browser never re-asks for it -->
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png" />

En query-string på slutten av href-en gjør den til en annen ressurs så vidt caching angår, selv om den løser seg til akkurat samme fil på disk:

<!-- after -->
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png?v=2" />

?v=2 er hele fiksen. Neste gang jeg endrer favicon-kunsten for ekte, blir det ?v=3, og så videre. Det er samme triks som å cache-buste en CSS- eller JS-bundle med en innholdshash, bare gjort for hånd her siden et favicon er en så sjelden redigering at en hel byggeverktøy-pipeline for det føltes overkill. Ett tall, bumpet manuelt, hver gang pikslene faktisk endres.

hva jeg ville fortalt meg selv i fortiden

Sjekk den enkle, dumme, pinlige forklaringen før den interessante. "Nettleseren er bare sta om en liten PNG" er et kjedelig svar, og jeg ville at buggen skulle være noe mer teknisk tilfredsstillende, en eller annen Docker-lagcaching-finesse jeg kunne skrive en smartere fiks for. Det var det ikke. Det var en query-string på fem tegn jeg kunne lagt til i løpet av de første ti minuttene hvis jeg hadde trodd på den kjedelige forklaringen i stedet for å jage containeren rundt i en halvtime først.

tingen som gjorde det verre før det ble bedre

Del av grunnen til at jeg tvilte på nettleser-cache-teorien så lenge jeg gjorde er at jeg først testet den i et inkognitovindu, og tenkte at det ville utelukke nettleser-cachen helt, fersk profil, ingen historikk, sikkert ingen favicon-cache heller. Feil, gammelt ikon dukket opp der også første gangen, som føltes som solid bevis på at det ikke var et cache-problem i det hele tatt. Det jeg ikke skjønte før senere er at Chromes favicon-cache ikke er strengt bundet til nettleserprofilens vanlige cache eller historikk på samme måte som sideressurser er, den er nærmere en separat, lengre-levende lagring, nøkket mer på selve URL-en, og et privat vindu starter ikke pålitelig den tom heller. Så kontrolltesten min kontrollerte faktisk ikke for det jeg trodde den kontrollerte for, og den sendte meg lenger ned containerklandre-stien enn bevisene skulle tilsi.

Det er også en mindre, kjedelig grunn til at byggesiden fortjente et første blikk: de samme favicon-PNG-ene finnes kopiert inn i noen forskjellige build-utdatasteder samtidig, frontend/build/client/, SvelteKit-dev-utdataen under .svelte-kit/output/client/, og kilde-static/-mappen de alle stammer fra. Tre kopier av de samme to filene på tvers av et vanlig bygg er akkurat den typen ting som blir foreldet ett sted og ikke et annet hvis et byggetrinn hoppes over, så å utelukke "feil kopi ble servert" var ikke paranoia, det bare ikke var der den faktiske buggen bodde denne gangen.

Jeg tenkte også på å bare gi filene nytt navn helt, favicon-32-v2.png i stedet for å bumpe en query-string, som garanterer en cache-miss uten tvetydighet. Bestemte meg mot det, siden det betyr å oppdatere hver referanse til det gamle filnavnet på tvers av app.html og hvor enn annet det er lenket, versus å røre ett tall ett sted. Query-stringen gjør samme jobb for en brøkdel av redigeringen.

0 kommentarer

Logg inn for å kommentere.

Logg inn

Ingen konto?