perf: stop prefetching every link in the viewport - #17
Merged
Merged
Conversation
faraapacalda.ro was 87% of the Vercel account's edge requests over the last
31 days (644k of 740k) and pushed the Hobby plan past its ISR-read and
fast-origin-transfer allowances, which pauses the project rather than billing
for it.
Measured cause: one homepage visit fired 35 `?_rsc=` prefetch requests and a
street page fired 24, several of them the same URL repeated under different
`_rsc` cache-buster tokens. Each distinct RSC payload comes back
`x-vercel-cache: PRERENDER`, i.e. a read out of the prerender store, and they
are not small - 70 KB for a street page, 30 KB for /metodologie. Roughly 1 MB
of origin traffic per page view to speculatively fetch pages nobody asked for.
Every route here is static and visitors arrive from search and usually read one
page, so prefetching the whole viewport buys very little. Route all links
through components/Link.tsx, which defaults prefetch={false}; in the App Router
that disables prefetch on viewport entry and on hover, while navigation still
fetches on click.
Measured after: homepage origin requests 49 -> 15, zero `?_rsc=` on load.
test/link-prefetch.test.ts fails if any component imports next/link directly,
so a new link cannot silently reintroduce the storm.
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Verified statically: every prior next/link import is now routed through components/Link.tsx (grep confirms no stray direct imports remain), the wrapper correctly defaults prefetch=false while still allowing per-call opt-in, and the new regression test's logic holds up (scans app/components/lib, matches wrapper behavior). Diff is a minimal, mechanical import swap + wrapper + guard test, matching the PR description exactly. No security-relevant surface touched (no auth/secrets/input-handling/dependency changes).
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.
Why
faraapacalda.ro is 87% of the Vercel account's edge requests (644k of 740k over 31 days) and has pushed the Hobby plan past two allowances:
On Hobby this does not generate a bill, it pauses the project. That would take the site down in the middle of the September hot-water season.
Measured cause
One homepage visit fired 35
?_rsc=prefetch requests; a street page fired 24. Several are the same URL repeated under different_rsccache-buster tokens:Each distinct RSC payload returns
x-vercel-cache: PRERENDER, i.e. a read out of the prerender store, and they are large: 70 KB for a street page, 30 KB for/metodologie. That is roughly 1 MB of origin traffic per page view, spent fetching pages nobody asked for.The change
Every route here is static, and visitors arrive from search and usually read one page, so prefetching the whole viewport buys very little. All links now route through
components/Link.tsx, which defaultsprefetch={false}. In the App Router that disables prefetch on viewport entry and on hover; navigation still fetches on click.Diff is one line per file (the import swap) plus the wrapper and a test.
Measured after
?_rsc=on load, on the homepage and on street pages_rscper click, for the URL actually clicked (the navigation fetch itself)Verification
npm test125 passed (3 new)npx tsc --noEmitcleannpx playwright test34/34 passed (with Playwright building its own server, soNEXT_PUBLIC_APP_POLL_DELAY_MSis inlined correctly)/,/strada/drm-taberei,/clasament: renders unchanged, 0 console messages, no failed first-party requestsRegression guard
test/link-prefetch.test.tsfails if any component importsnext/linkdirectly, so a newly added link cannot silently bring the storm back.Not addressed here
This only removes the real-user half of the traffic. Roughly 60% of the site's edge requests are non-JS clients (crawlers) hitting HTML directly, which needs a CDN in front. Tracked separately.