Skip to content

test: reproduce x-void-page-data header failure with large props - #20

Closed
hyfdev wants to merge 3 commits into
mainfrom
fix/x-void-page-data-large-props
Closed

hyfdev wants to merge 3 commits into
mainfrom
fix/x-void-page-data-large-props

Conversation

@hyfdev

@hyfdev hyfdev commented Mar 13, 2026

Copy link
Copy Markdown
Contributor

Closes #19

Summary

  • Adds a large-props playground page that generates ~300KB of props simulating CMS data (record map + pre-rendered HTML with Unicode content)
  • Adds a failing integration test that builds the vue-pages playground in SSG mode and verifies prerendering succeeds

Test output

prerender /large-props failed: fetch failed
1 page(s) failed to prerender

Context

The x-void-page-data response header (protocol.ts:221) serializes the entire page object into an HTTP header. For pages with large props (common in CMS-powered sites), this exceeds Miniflare/workerd header size limits, causing fetch failed during SSG prerendering.

See #19 for full details and suggested fixes.

Test plan

  • Run pnpm test:pages:react-vue -- -t "SSG prerender should not fail" --hookTimeout=60000 — currently fails as expected
  • Existing tests pass (no modifications to existing files)

🤖 Generated with Claude Code

The `x-void-page-data` response header serializes the entire page object
(JSON.stringify(pageObj)) into an HTTP header on every non-deferred SSR
response. For pages with large props (e.g. CMS record maps + pre-rendered
HTML totaling 100KB+), this exceeds HTTP header size limits in
Miniflare/workerd, causing "fetch failed" during SSG prerendering.

Real-world case: a Notion-powered blog where each page returns a full
ExtendedRecordMap (~30-70KB) + pre-rendered HTML (~50-200KB) as props.
All blog post pages fail with "fetch failed" during `vite build` with
`output: "static"`.

This commit adds:
- A playground page (large-props) that generates ~300KB of props
  simulating CMS data with Unicode content
- A failing integration test that builds the vue-pages playground in
  SSG mode and verifies prerendering succeeds

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Vue Pages playground route and an integration test to reproduce the x-void-page-data header size/encoding failure when prerendering pages with very large props (common in CMS-backed apps), as described in #19.

Changes:

  • Added a /large-props playground page + companion server loader that generates ~300KB of CMS-like props (record-map-ish object + pre-rendered HTML with Unicode).
  • Added an integration test that builds playground/vue-pages in output: "static" mode and asserts prerendering succeeds for the large-props page.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
playground/vue-pages/pages/large-props.vue New page rendering generated “large props” + pre-rendered HTML.
playground/vue-pages/pages/large-props.server.ts New loader generating large CMS-like payload and declaring prerender paths.
packages/vue/test/integration/vue-pages-large-props.test.ts New integration test that enables SSG and runs a build to catch the header-size prerender failure.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +13 to +23
beforeAll(() => {
// Check if void.json already exists (shouldn't, but be safe)
voidJsonExisted = existsSync(VOID_JSON);
});

afterAll(() => {
// Clean up: remove void.json if we created it
if (!voidJsonExisted && existsSync(VOID_JSON)) {
unlinkSync(VOID_JSON);
}
});
Comment on lines +34 to +43
writeFileSync(VOID_JSON, JSON.stringify({ output: "static" }, null, 2));

let buildOutput: string;
try {
buildOutput = execSync("pnpm --dir playground/vue-pages exec vite build", {
cwd: ROOT,
stdio: "pipe",
encoding: "utf-8",
timeout: 60_000,
});
Comment on lines +25 to +52
it("SSG prerender should not fail for pages with large props (~300KB)", () => {
// Enable SSG mode so the build prerenders pages via Miniflare.
// The x-void-page-data header serializes the full page object (~300KB+)
// into an HTTP response header, which exceeds Miniflare's header size
// limits and causes "fetch failed" during prerendering.
//
// Real-world case: Notion-powered blog (musubi) where each page returns
// a full ExtendedRecordMap (~30-70KB) + pre-rendered HTML (~50-200KB).
// All 16 blog post pages fail with "fetch failed" during `vite build`.
writeFileSync(VOID_JSON, JSON.stringify({ output: "static" }, null, 2));

let buildOutput: string;
try {
buildOutput = execSync("pnpm --dir playground/vue-pages exec vite build", {
cwd: ROOT,
stdio: "pipe",
encoding: "utf-8",
timeout: 60_000,
});
} catch (e: any) {
// Build may "succeed" with warnings for failed prerenders, or may throw
buildOutput = (e.stdout ?? "") + (e.stderr ?? "");
}

// The large-props page should prerender successfully without "fetch failed"
expect(buildOutput).not.toContain("large-props failed");
expect(buildOutput).toContain("large-props.html");
}, 60_000);
Comment on lines +49 to +52
// The large-props page should prerender successfully without "fetch failed"
expect(buildOutput).not.toContain("large-props failed");
expect(buildOutput).toContain("large-props.html");
}, 60_000);
Comment on lines +38 to +43
buildOutput = execSync("pnpm --dir playground/vue-pages exec vite build", {
cwd: ROOT,
stdio: "pipe",
encoding: "utf-8",
timeout: 60_000,
});
@cpojer

cpojer commented Mar 25, 2026

Copy link
Copy Markdown
Member

What's the status of this PR?

@TheAlexLichter

Copy link
Copy Markdown
Member

So far we have a (failing) test but need to align on a better solution for page props/content.

@hyfdev

hyfdev commented Apr 14, 2026

Copy link
Copy Markdown
Contributor Author

Tests passed so I guess the issue is solved.

@hyfdev

hyfdev commented Apr 14, 2026

Copy link
Copy Markdown
Contributor Author

The underlying issue (#19) was fixed in 00bae0f — page data moved from the x-void-page-data HTTP header to an inline <script type="application/json"> tag in the HTML body, eliminating header size limits entirely.

The large-props test added here now passes in CI, confirming the fix. Closing since the fix landed separately on main. The regression test coverage is valuable — if we want to keep it, it can be cherry-picked or re-submitted as a standalone PR.

@hyfdev hyfdev closed this Apr 14, 2026
@cpojer
cpojer deleted the fix/x-void-page-data-large-props branch May 7, 2026 07:54
cpojer pushed a commit that referenced this pull request Sep 11, 2026
The framework's router.post() serializes data with JSON.stringify(),
which produces "{}" for FormData instances (no own enumerable properties).
This caused all 4 project mutations (add/remove domain, add/remove secret)
to silently fail — the server action received an empty object, no intent
matched, and no API call was made.

Switch client to pass plain objects and server to use c.req.json() instead
of c.req.parseBody(), matching the framework's JSON protocol.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

x-void-page-data header causes fetch failed for pages with large props

4 participants