Repository navigation
every logo is revalidated on every page view, and /capital has 158 of them - #2934
Merged
Merged
Conversation
… them Provider marks are plain files under `public/`, and Next serves those as `cache-control: public, max-age=0, must-revalidate` unless the config says otherwise. The config did not: the only Cache-Control rule in next.config.ts was for /api/citable. must-revalidate means a browser holding the whole set in its disk cache still has to ask the server about each file before it is allowed to paint it. On /capital that is 158 conditional requests per visit. Measured against prod from a machine sitting next to the cdg1 edge, each 304 costs about 95 ms and carries no bytes. The marks render as empty circles until they land, which is what a reader sees. Why it turned slow recently rather than gradually: the page's logo set has been growing, and most of the growth is new. Counting the files /capital actually references by the month each was added to the repo: 2026-05 28 files 476 KB running 28 / 476 KB 2026-06 16 89 KB 44 / 564 KB 2026-07 19 663 KB 63 / 1227 KB 2026-08 18 326 KB 81 / 1553 KB 2026-09 72 1785 KB 153 / 3338 KB September alone doubled the file count and added more weight than the four months before it put together. A missing cache header is harmless at eighty images and is not at a hundred and sixty. So /logos/* gets a day of silence and then a month of serving the cached copy while a fresh one is fetched behind it. Deliberately not `immutable`: these filenames are stable and their CONTENTS get replaced — Chainstack sent a new mark in #2910 — so a year-long immutable cache would pin an old logo on every returning reader. A day is short enough that a swapped mark turns up on its own. Verified rather than assumed, because a config header does not always win: the same block carries a comment about /api/citable, where this layer loses to the Cache-Control the route handler sets. Static files have no handler, so the rule applies. Checked on a dev server: $ curl -sI /logos/ronin.png Cache-Control: public, max-age=86400, stale-while-revalidate=2592000 and /favicon.ico still answers `no-cache, must-revalidate`, so the scope is the one intended. This does not touch the other half of the problem, which is a separate job: 3.5 MB of marks on one page, for circles rendered at 22 pixels. 32 files are over 30 KB and carry 69 % of the weight, ronin.png alone is 227 KB. Re-encoded at 64 px those 158 files would be roughly 630 KB, an 82 % cut on first load. That one rewrites binaries and wants its own PR.
Flotapponnier
added a commit
that referenced
this pull request
Oct 9, 2026
3.5 MB of logos on one page, for circles drawn at 22 pixels The cache header landed in #2934 and fixes the repeat visit: a reader who already holds the marks no longer asks the server about each one. It does nothing for the first visit, which still downloads the lot. On /capital that is 158 files and 3.5 MB, and the marks are rendered in 22 px circles. The files were simply never sized for their use. ronin.png is 2000x2000 and 227 KB. tradoor.png is 1667x1667. tron.png is 2000x2000 and 104 KB. They are whatever the provider's press kit shipped. The largest size any `<ProviderLogo>` renders at anywhere in the codebase is 56, so every raster over 30 KB is capped at 160 px on its longest side: about 3x retina for the biggest use and 7x for the common 22 px chip. Format is unchanged file by file — PNG stays PNG, WebP stays WebP — so `logo-manifest.ts` needs no edit and no path moves. 97 files 7,371 KB -> 1,333 KB (-81%) /capital 3,506 KB -> 1,302 KB (-63%) public/logos 13 MB -> 6.8 MB Two files were left exactly as they were because re-encoding them came out larger, which is the rule the script applies: a result that does not shrink is not written. Checked rather than assumed, because the failure mode here is silent and ugly. Alpha and colour space survive on every sampled file (ronin, zircuit, immutable, rhea-finance, sun, kinetiq, tron, wallet-v: `hasAlpha` and `space` identical before and after), aspect ratios are preserved rather than squared off (wallet-v 794x203 -> 160x41), and three of the resized files were opened and look like their logos. An earlier run of this nearly shipped something worse: `tar --exclude=script` while packaging the rpc-cost harness also matched `cmd/script/`, the entire Go source. Different job, same lesson about patterns that match more than the one path they were written for.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
every logo is revalidated on every page view, and /capital has 158 of them
Provider marks are plain files under
public/, and Next serves those ascache-control: public, max-age=0, must-revalidateunless the config saysotherwise. The config did not: the only Cache-Control rule in next.config.ts
was for /api/citable.
must-revalidate means a browser holding the whole set in its disk cache still
has to ask the server about each file before it is allowed to paint it. On
/capital that is 158 conditional requests per visit. Measured against prod
from a machine sitting next to the cdg1 edge, each 304 costs about 95 ms and
carries no bytes. The marks render as empty circles until they land, which is
what a reader sees.
Why it turned slow recently rather than gradually: the page's logo set has
been growing, and most of the growth is new. Counting the files /capital
actually references by the month each was added to the repo:
2026-05 28 files 476 KB running 28 / 476 KB
2026-06 16 89 KB 44 / 564 KB
2026-07 19 663 KB 63 / 1227 KB
2026-08 18 326 KB 81 / 1553 KB
2026-09 72 1785 KB 153 / 3338 KB
September alone doubled the file count and added more weight than the four
months before it put together. A missing cache header is harmless at eighty
images and is not at a hundred and sixty.
So /logos/* gets a day of silence and then a month of serving the cached copy
while a fresh one is fetched behind it. Deliberately not
immutable: thesefilenames are stable and their CONTENTS get replaced — Chainstack sent a new
mark in #2910 — so a year-long immutable cache would pin an old logo on every
returning reader. A day is short enough that a swapped mark turns up on its
own.
Verified rather than assumed, because a config header does not always win:
the same block carries a comment about /api/citable, where this layer loses
to the Cache-Control the route handler sets. Static files have no handler, so
the rule applies. Checked on a dev server:
$ curl -sI /logos/ronin.png
Cache-Control: public, max-age=86400, stale-while-revalidate=2592000
and /favicon.ico still answers
no-cache, must-revalidate, so the scope isthe one intended.
This does not touch the other half of the problem, which is a separate job:
3.5 MB of marks on one page, for circles rendered at 22 pixels. 32 files are
over 30 KB and carry 69 % of the weight, ronin.png alone is 227 KB. Re-encoded
at 64 px those 158 files would be roughly 630 KB, an 82 % cut on first load.
That one rewrites binaries and wants its own PR.