SSR the download panel - #17
Merged
Merged
Conversation
DownloadButton fetched /api/releases from the browser on every visit, so each visitor cost a GitHub round trip, the panel flashed a loading state, and crawlers saw no version numbers at all. Resolve the data during render instead. lib/releases.ts holds the fetch and grouping logic lifted from the route handler; DownloadButton becomes an async server component that awaits it and hands the result to DownloadButtonClient for the interactive parts. /download drops "use client" so it can prerender, and gains its own metadata. Two details the client-side version did not have to worry about: - OS detection has no user agent to read on the server, so it moves to useSyncExternalStore and selectedOS becomes derived rather than stored. The server render and the hydration render are then identical by construction. (An effect would also trip react-hooks/set-state-in-effect.) - Dates are formatted through a fixed en-US/UTC Intl.DateTimeFormat. toLocaleDateString() resolves against the viewer's timezone, which would mismatch the prerendered HTML on hydration. getReleases() never throws: a GitHub outage must not fail the build, and on an already prerendered page a failed revalidation leaves the last good render in place. Deletes app/api/releases/route.ts, which existed only to serve this component and now has no callers.
The server render needs something to invalidate it, and issue #3 asks for a once-daily refresh at midnight so a new release gets a grace period before the website advertises it. vercel.json crons /api/revalidate-releases at 00:00 UTC. The handler purges the "releases" cache tag and the prerendered /download page, so the first visitor after midnight triggers exactly one upstream fetch. That puts the site at roughly one GitHub request per day rather than one per visitor, well inside the 60/hour unauthenticated limit. The endpoint requires CRON_SECRET, which Vercel sends as a bearer token on cron invocations. It 500s when the variable is missing rather than running unauthenticated, so a misconfigured deploy fails loudly.
The up-to-a-day delay before a new release appears on the site is deliberate, but nothing in the repo said so, and a maintainer hitting it would reasonably read it as a bug. Records the grace period, the manual override for publishing immediately, and the fact that CRON_SECRET must exist in the Vercel dashboard before this deploys. Also notes that the page's revalidate literal duplicates RELEASES_REVALIDATE_SECONDS because Next cannot accept an import there, so the two have to move together.
Tiles now read macOS, Windows, Linux. OS_ORDER was doing two jobs: laying out the tiles and picking the OS the panel falls back to when detection fails. Since the server has no user agent to sniff, that fallback is what the prerendered HTML shows and what crawlers index, so reordering the constant in place would have quietly moved the indexed default from Windows to macOS. Splits it into OS_DISPLAY_ORDER and OS_FALLBACK_ORDER. Only the former changes here; the prerendered default is still Windows.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
Closes #3.
DownloadButtonfetched/api/releasesfrom the browser on every visit — a GitHub round trip per visitor, a loading flash before anything useful appeared, and no version numbers for crawlers.It now renders on the server.
lib/releases.tsholds the fetch and grouping logic lifted from the route handler;DownloadButtonis an async server component that awaits it and passes the result toDownloadButtonClientfor the interactive parts./downloaddrops"use client"so it prerenders (○ Static,Revalidate: 1d) with real data and metadata in the HTML.app/api/releases/route.tsis deleted — no callers left.A cron in
vercel.jsonhits/api/revalidate-releasesat 00:00 UTC to purge the cache tag and the prerendered page, so the first visitor after midnight triggers one fetch. Roughly one GitHub request per day instead of one per visitor. A new release therefore takes up to a day to appear — the grace period #3 asks for.Tiles now read macOS, Windows, Linux.
Reviewer notes
Hydration. SSR introduced two ways server and client could disagree: OS detection (no user agent server-side) now uses
useSyncExternalStorewithselectedOSderived rather than stored, so both renders are identical by construction; dates go through a fixeden-US/UTCIntl.DateTimeFormat, sincetoLocaleDateString()would resolve against the viewer's timezone.OS_ORDERwas doing two jobs — tile layout and the fallback OS. That fallback is what gets prerendered and indexed, so reordering in place would have quietly moved the indexed default from Windows to macOS. Split intoOS_DISPLAY_ORDERandOS_FALLBACK_ORDER; only the former changed.Before merging
Set
CRON_SECRETin the Vercel dashboard, Production-scoped. Vercel sends it as a bearer token on cron invocations; the endpoint 500s when it's missing rather than running unauthenticated.Verification
lint,typecheck,format:check,next buildpass. Against live GitHub: prerendered HTML containsv0.5.0,VoxKit-setup.exeand the pre-release banner with no loading state; per-OS resolution correct (Windows v0.5.0, macOS v0.4.1, Linux greyed out); revalidate endpoint 401s unauthenticated and on a wrong secret, 200s with the right one, after which the page re-rendered with an advanced timestamp.Hydration is safe by construction but was not confirmed in a browser console — worth a look at the preview deploy.
Not in scope
The
DownloadButton→DownloadPanelrename is #2; doing it here would collide with that PR.