dev #22
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "dev"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Measured against the deployed asset set: Material Symbols (full variable font) 1,126,168 B Material Symbols (68 icons in use) 20,668 B -98% job icons, 21x 256px PNG 599,890 B job icons, 21x 64px WebP 42,054 B -93% guide screenshots 3,154,956 B guide screenshots as WebP 645,088 B -80% og-image.jpg 373,769 B og-image.jpg recompressed 40,000 B -89% The icon font alone was roughly ten times the size of the entire brotli'd JS and CSS of the app. Requesting it via icon_names= cuts it to the 68 icons actually rendered. That subset is a footgun: an icon used in src/ but missing from the list renders as its literal name ("settings") rather than a glyph, silently. scripts/check-icon-subset.js fails with the missing names; it is wired into npm run check separately. Job icons were hot-linked to raw.githubusercontent.com, costing a DNS lookup and TLS handshake to a third-party origin for images above the fold on every roster, and shipping 256px sources for something rendered at 20-32 CSS px. Now served from our own origin at 64px. og-image.jpg keeps its 1024x1024 dimensions; only the encoding changed, since its aspect ratio is a design decision rather than a size problem. Also adds a preconnect to xivapi.com, which serves gear and materia icons on nearly every roster view. Two guide assets have no references anywhere in src and were carried over as-is: static/guides/recording-gear-from-book/ duplicates recording-gear-from-a-book/, and 04-resolution sits beside the referenced 04-resolutions. Both look like leftovers from a rename.The Share button rendered the word "share" at icon size instead of the glyph. Its name never reached the icon_names= list because the extractor only recognised icon names written literally in markup: <span class="material-symbols-outlined text-sm">{shareCopied ? 'check' : 'share'}</span> Names also arrive through expressions like that one, and through helper functions such as statusIcon() in src/lib/utils/gear.ts. Both forms were skipped silently, so the guard reported a clean run while six icons were broken: share, expand_less, event_busy, shopping_bag, swords and radio_button_unchecked. Only Share had been noticed. check-icon-subset.js now harvests quoted string literals out of icon expressions, reads helper-supplied names from scripts/icons.extra.json, and reports every expression it cannot resolve statically so a new helper surfaces instead of shipping a broken glyph. `--list` prints the canonical list to paste into app.html, replacing the grep in the comment there that had the same blind spot as the original extractor. Subset is now 74 icons, 23,072 B against 1,126,168 B for the full font.Pairs with the API change that moves gear options out of StaticDTO. getStatic and getSingletonPlayerInfo now request includeGearOptions=false, and options come from the new cacheable GET api/Gear/Options/{tier}/{job}. The roster page fetches one set per distinct job on the roster rather than receiving a copy inside every player; players sharing a job share one options object. An API predating the split ignores the flag and still inlines the options, so both pages prefer an inline copy when present and only fetch when it is absent. That keeps the frontend deployable before or after the API. The slot-renaming and mapping logic the two pages had duplicated is now normalizeGearOptions in $lib/utils/gear, shared by the inline and fetched paths. The member page keeps seeding every slot with an empty array, since callers index by slot and expect an array rather than undefined. Measured on an 8-job party with a realistic tier catalog, the static payload drops from 151,498 B raw / 6,613 B brotli to 25,722 B / 811 B. That applies to every realtime refetch, which on a raid night is one per recorded drop.DropRecordModal (~890 lines) and PlayerDetailModal (~1330 lines) were static imports, so Rollup compiled both into the roster route's chunk and every roster load downloaded and parsed them — despite neither rendering until an explicit user action. PlayerDetailModal was inlined into the member-detail route's chunk as well, so it shipped twice. Eager weight of the roster route, transitively over static imports: before 32 modules 121,504 B brotli after 33 modules 104,150 B brotli The two modals become their own chunks (10,114 B and 6,762 B brotli), fetched on demand. They are gated on having loaded, not on being open. Both already wrap their entire markup in {#if open}, so mounting them early renders nothing, and keeping them mounted preserves script state across open/close — a half-finished set of drop assignments still survives closing the modal, which gating on `open` would have silently discarded. Both are also warmed on requestIdleCallback after mount, so the first click does not wait on a fetch; the effects covering dropModalOpen/editingPlayer handle a user who gets there first. A failed import clears its guard so a later attempt retries rather than leaving the button dead.