Repository navigation
perf(prerender): reuse each page's HTML render for its navigation data - #501
Merged
Brooooooklyn merged 3 commits intoOct 20, 2026
Merged
Conversation
Static prerendering fetched every page twice: once for the HTML and again with X-VoidPages for `_void/pages/*.json`. The HTML already embeds the same page object in `__VOID_PAGE_DATA__`, so read the JSON from it instead. Pages with deferred props embed them unresolved, so they keep the second request, which resolves them inline. Output is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
yangshun
commented
Oct 20, 2026
The tests now fail if prerendering sends the X-VoidPages request again for a page whose HTML embeds its data: they record every page-data request and expect none, except for a deferred page, which still needs it after its HTML is written. One page uses characters the embedded script escapes, and its JSON file must match JSON.stringify of the page object. The comment says why the embedded text is parsed and stringified again. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Member
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. Delightful! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Brooooooklyn
approved these changes
Oct 20, 2026
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.
Problem
Static prerendering made two requests per page: one for the HTML, and a second with
X-VoidPagesto write_void/pages/*.json. The loader and middleware ran twice for every page.Fix
Fixes #500
The HTML already embeds the page object in
__VOID_PAGE_DATA__, so the prerenderer now writes the JSON from that script and skips the second request.extractPageDataFromHtmlfrom@void/isr/core, which ISR already uses to build JSON from page HTML.__VOID_PAGE_DATA__script, so they still get no JSON file.<,>and&.Results
I ran two benchmarks, once with a 1000-page Void app (no actual network requests), another with a remote PayloadCMS database.
1000-page Void app
Measured with my own 1000-page Void app benchmark, static output. Old and new code ran alternately in one process on the same build:
On Node, the second request was an in-process call, so a full build barely changes: 4.99 s before vs 4.64 s after, median of 3, within noise. The gain is larger on Cloudflare, where each request goes through the local Workers runtime.
The built output (1,001 HTML and 1,001 JSON files) is byte-identical to before on both Node and Cloudflare.
100-page blog backed by remote Payload CMS
Tested in a more realistic scenario of a 100-post blog backed by a remote Payload CMS database, where each pre-rendered page fetches from Payload CMS:
Tests
static-pagesandnode-staticintegration tests pass.Alternative considered
Another approach handles deferred props in the same single request. During prerendering, the page handler copies each deferred value into the page object as it streams, then appends the completed object to the end of the HTML as a build-only script.
The prerenderer removes that script and writes it as the JSON file. This avoids the second request even for deferred pages, but it changes
handlePageGet, which runs on every page request in every app, and the appended script has to pass through the app's HTML middleware unchanged.I prefer to keep the change in build-time code instead. Deferred props are uncommon in fully static pages, so those pages keeping the second request costs little.