Public: anyone can read this; the crew can change it.

The same twenty icons, once each: the front door stops re-sending its drawings #154

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

Pushed. Pull description follows.

shipped production is serving it deploy 76ab860

opened this

Pushed. Pull description follows.

---

icon() inlined its whole Lucide drawing on every call, so a list of thirty rows shipped the same twenty paths a hundred times. It now renders the 16px slot with a one-line <use href="#i-name"/> inside it, and the viewBox, fill, stroke and cap/join attributes move onto the <symbol>, which is where they belong once a drawing is defined once. iconSprite() (src/web/icons.ts) reads the page's own rendered markup for those references and emits exactly the icons it found, in a zero-sized <svg class="sprite"> at the end of <body> — that is the choice the issue asked me to name: no collector threaded through components, and a <use> earlier in the document resolves against it fine. layout.ts builds the body first, scans it (~75 µs on a 110 KB page) and appends the block before the script.

Weights, measured locally by booting a real forge: a 30-row issues list goes 82,472 → 76,392 b with its icon markup dropping 19,058 → 12,998 b; a repo page 50,381 → 48,399 b; a fresh account's studio / 64,248 → 63,036 b (only 28 icon uses on an empty forge, so the whole saving is there to see but small). On the census this issue measured — 98 of the 104 uses, across the same 20 distinct drawings — the icon markup goes 32,136 → 16,893 b, −15.2 KB; test/web.test.ts asserts that delta stays above 15 KB, so the deployed front door should land near 96 KB instead of 112.6 KB. Look first at iconSprite/inlineIcons in src/web/icons.ts and the shell split in page().

The one thing that needed care beyond the issue: markup that lands in a document it does not own cannot reference a sprite it did not ship. fragment() and threadFragment therefore expand their references back into the nested <svg> a <use> would have instantiated (same pixels, no ids to collide), and liveRegionsJs — which re-fetches a whole page and swaps one region's innerHTML — now carries the fresh page's sprite across first, so a region that swaps in an icon the first paint never used still draws. The CSP is untouched; the only stylesheet change is one .sprite rule taking the block out of flow. New tests: the slot's exact markup and both sizes, the spinner's ico-loader class, a dozen rows sending the issue glyph's path once, symbols-defined equalling icons-used exactly on three pages, and a fragment that contains no <use> at all. No snapshot held icon markup, so none were updated.

What I did not do: themeGlyph stays inline (one per page, nothing to fold), and I left the block out of <head>, which would have meant rendering the body twice or threading a collector. Note for the check: six tests in this suite fail in my sandbox because git-over-HTTP pushes are blocked here — the same six fail identically on main at this commit, and my six new tests pass.

🤖 Generated with Claude Code

Closes #134

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs