Skip to content

fix(website): index prerendered HTML from Next's adapter route cache - #697

Merged
stipsan merged 1 commit into
currentfrom
cody/website-pagefind-next-16-4-1cb7
Oct 12, 2026
Merged

stipsan merged 1 commit into
currentfrom
cody/website-pagefind-next-16-4-1cb7

Conversation

@stipsan

@stipsan stipsan commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

Description

The Vercel – react-rx deployment of the docs site fails on current since #694: next build succeeds, then pagefind --site .next/server/app reports Found 0 files matching **/*.{html} and exits 1 with "Pagefind was not able to build an index".

Root cause. #694 resolved next ^16.3.6 → 16.4.0 (the lockfile-only hold from #684 could not survive the next lockfile refresh). next@16.4.0 is the first stable release with vercel/next.js#99482 "Scope response cache keys to their source route": when a deployment adapter is configured, the export worker writes each prerendered page to .next/server/route-cache/APP_PAGE/<sha256(source route)>/$/<pathname>.html (useScopedBuildArtifacts in next/dist/export/worker.js) instead of .next/server/app/<pathname>.html. Vercel's @vercel/next builder sets NEXT_ADAPTER_PATH (adapter builds for next >= 16.2.0-canary.28), so on Vercel .next/server/app contains only the compiled route modules and no HTML. Local and CI builds have no adapter and still prerender to .next/server/app, which is why next build kept passing everywhere except the Vercel deployment. The layout is unchanged on Next canary, so this is the new permanent output for adapter builds, not a regression that will be reverted.

Fix. postbuild now runs website/scripts/pagefind.mts, which uses Pagefind's Node API to index .next/server/app plus every .next/server/route-cache/APP_PAGE/*/$ root that exists, then writes public/_pagefind as before. Pagefind derives URLs relative to each root, so the index content is identical to what the CLI produced before 16.4 (/, /guide.html, /examples/activity.html, … — Nextra strips .html). The script still fails the build when no HTML is found anywhere, and prints which roots it indexed so a future layout change is visible in the build log.

Why not pin next. Reverting to 16.3.6 only defers this to the next bump (the #684 hold lasted hours), holds back security patches, and the route-cache layout is where the Vercel adapter now reads prerendered output from. Pointing Pagefind at where the HTML actually lives is the durable fix; a single --site directory cannot express it because the root is hashed and differs between adapter and non-adapter builds, hence the small script.

The tsconfig.json change only adds **/*.mts to include so Oxlint's type-aware lint sees @types/node for the script. .mts is used so Node loads it as ESM without MODULE_TYPELESS_PACKAGE_JSON warnings, since website/package.json has no "type": "module".

What to review

  • website/scripts/pagefind.mts — the root discovery (.next/server/app and route-cache/APP_PAGE/<hash>/$), error handling (createIndex/addDirectory/writeFiles errors, and the explicit "no prerendered HTML" failure), and the summary line. 41 lines, one no-console disable for the summary.
  • website/package.json — postbuild runs the script with node (Node ≥ 22.18 strips types natively; the prebuild tsdown step already requires that on every build host).
  • website/tsconfig.json — **/*.mts added to include.

Suggested merge: rebase (single commit).

Testing

No automated test for a build script; verified by running pnpm run build in website/ with next@16.4.0 from the current lockfile, in both layouts:

  • Default (local/CI, no adapter): Pagefind indexed 24 from .next/server/app into public/_pagefind, exit 0, pagefind-entry.json reports page_count: 22.
  • Adapter mode, reproducing Vercel with NEXT_ADAPTER_PATH=<no-op adapter>: before this change, pagefind --site .next/server/app → Found 0 files matching **/*.{html} → Pagefind was not able to build an index → exit 1 (the exact Vercel failure). After: Pagefind indexed 1 from …/APP_PAGE/1ac71f…/$, 1 from …/APP_PAGE/41da0e…/$, 22 from …/APP_PAGE/fbc75e…/$ into public/_pagefind, exit 0.
  • Both layouts produce a byte-identical index (en_155874b525, 22 pages); the decoded fragments list /, /guide.html, /reference.html, /examples/*.html, /migrate/*.html with no route-cache prefix.
  • Negative path: running the script against an empty .next/server/app exits 1 with Pagefind found no prerendered HTML in .next/server/app and writes nothing.
  • pnpm lint, pnpm knip and oxfmt --check pass.
  • On Vercel itself: this PR's Vercel – react-rx check passes ("Deployment has completed"), the preview serves /_pagefind/pagefind-entry.json with page_count: 22, and a Pagefind query for useObservable against the preview's index returns 20 results whose URLs (/reference, /guide, /examples/simple, /migrate/v4-to-v7, …) all respond HTTP 200.
Open in Web Open in Cursor 

`next@16.4.0` (vercel/next.js#99482) writes prerendered app HTML to
`.next/server/route-cache/APP_PAGE/<sha256(source route)>/$/` whenever a
deployment adapter is configured. Vercel's `@vercel/next` builder sets
`NEXT_ADAPTER_PATH`, so on Vercel `.next/server/app` no longer contains any
HTML and `pagefind --site .next/server/app` fails with "Found 0 files" /
"Pagefind was not able to build an index", exiting 1. Local and CI builds
have no adapter and still prerender to `.next/server/app`, which is why
the failure only showed up in the Vercel deployment.

Replace the CLI call with a small script on Pagefind's Node API that
indexes `.next/server/app` plus every `route-cache/APP_PAGE/*/$` root that
exists. URLs are relative to each root, so search results are unchanged
(`/`, `/guide.html`, `/examples/activity.html`, ...), and the script still
fails the build when no HTML is found.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
@vercel

vercel Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
react-rx Building Building Preview Oct 12, 2026 8:10pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
async-react Skipped Skipped Oct 12, 2026 8:10pm UTC

Request Review

@stipsan stipsan added the ✨ ai label Oct 12, 2026 — with Cursor
@stipsan
stipsan marked this pull request as ready for review October 12, 2026 21:24
Copilot AI balanced review requested due to automatic review settings October 12, 2026 21:24
@stipsan
stipsan merged commit 897feeb into current Oct 12, 2026
14 checks passed
@stipsan
stipsan deleted the cody/website-pagefind-next-16-4-1cb7 branch October 12, 2026 21:25

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.

🟢 Approval recommended

The implementation correctly handles both Next.js output layouts with appropriate failure reporting.

0 open findings

What changed in this PR

Updates website search indexing to support Next.js 16.4 adapter route-cache output while preserving local builds.

Changes:

  • Adds Pagefind discovery and indexing across standard and adapter output roots.
  • Runs the new script after website builds.
  • Includes .mts scripts in TypeScript analysis.
File Description
website/​scripts/​pagefind.mts Discovers prerendered HTML roots and builds the Pagefind index.
website/​package.json Uses the new postbuild script.
website/​tsconfig.json Includes .mts files in type checking.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

This branch was successfully deployed

1 active and 1 inactive deployments
Preview – react-rx — 94ffab52 Deployed Oct 12, 2026 by vercel[bot]
Preview – async-react — 94ffab52 Deployed Oct 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants