Skip to content

feat(cache): probe Pages Router cacheability - #3098

Open
james-elicx wants to merge 14 commits into
codex/cacheability-cache-certificationfrom
codex/cacheability-pages-router
Open

feat(cache): probe Pages Router cacheability#3098
james-elicx wants to merge 14 commits into
codex/cacheability-cache-certificationfrom
codex/cacheability-pages-router

Conversation

@james-elicx

@james-elicx james-elicx commented Aug 26, 2026

Copy link
Copy Markdown
Member

Capability stack 8/9. Exact head: b40e1a98c03334c1aaf5c7eaf9930acd47a8d66c. Base: #3094.

Full chain: #3108#3090#3091#3092#3103#3093#3094#3098#3113.

This is the Pages Router capability layer. Without it, App Router probing and two-stage warming work, while Pages routes retain safe route-owned caching but are not classified or warmed by the two-stage flow. #3113 completes the cumulative capability by adding statically eligible Route Handlers.

What this adds

  • classify Pages Router HTML and /_next/data/<buildId>/*.json request identities inside the staged Worker
  • treat automatic static optimization and getStaticProps/ISR HTML as cache candidates
  • discover and warm Pages data identities only for real getStaticProps/ISR routes; automatic-static pages do not invent data endpoints
  • treat getServerSideProps and custom page getInitialProps as dynamic without executing request-time data functions during probing
  • match Next.js custom _app.getInitialProps behavior: automatic-static pages become dynamic, while getStaticProps pages remain cache candidates
  • preserve base paths and the runtime build ID when constructing Pages data paths
  • include the locale in Pages data identities even for the default locale, matching Next.js client requests
  • apply hybrid App/Pages runtime ownership before generating Pages data targets
  • validate Pages data fills as JSON rather than applying RSC response rules
  • emit the cacheability-manifest module asset in Pages-only Cloudflare Worker builds
  • register the CDN adapter before deciding admission so Pages-only/manual deployments still honor completed-response admission when the embedded manifest is null
  • carry discovered Pages HTML/data paths through probing, manifest generation, readiness, warming, retry, and admission
  • transfer hybrid App/Pages admission ownership explicitly so the App layer cannot overwrite Pages policy
  • keep unlisted paths, query variants, middleware/config-header variants, preview-cookie cleanup, unknown data paths, and failed responses private
  • fail closed when Pages redirects or rewrites depend on headers, cookies, or hosts in every routing phase
  • preserve explicit public next.config cache policy for App Pages, including force-dynamic, while retaining middleware-over-config precedence

Warming and certification behavior

The default flow probes each eligible App or Pages identity once and requests it once again to fill the final Worker's CDN cache. It does not make a second fill/certification request.

If --warm-cdn-certify is explicitly supplied, the optional header-only pass from #3094 re-requests warmed identities before promotion. Certification is disabled by default.

Next.js parity

The classification follows the Pages data-contract split used by Next.js: automatic static optimization and getStaticProps HTML are reusable unless a custom _app.getInitialProps opts automatic-static pages out; getStaticProps pages remain static. getStaticProps/ISR data endpoints receive the same static/ISR cache policy; getServerSideProps and page getInitialProps remain request-time. Default-locale data URLs and hybrid route ownership match the upstream client/build behavior. The tests link to the upstream prerender, i18n data-route, preview, middleware matcher, and getServerSideProps suites.

Known safe parity gap

Discoverable exact identities match the staged probe. Runtime-generated fallback: true/blocking paths that were not discovered remain no-store at the CDN, while Next.js can cache them after successful runtime generation. This is fail-closed and prevents disclosure, but is a CDN-performance parity gap for a separately reviewable pattern-contract/runtime-admission follow-up.

External gateway boundary

A preview/draft cookie request can still consume an already-cached anonymous edge HIT before this single Worker entrypoint runs. This stack deliberately does not add Vary: Cookie or multi-entrypoint behavior; the separate uncached-gateway stack owns that edge-before-Worker boundary.

Rollout requirement

Deploying the fixed Worker cannot remove objects that a vulnerable Worker version already admitted to the shared CDN cache. The security rollout must purge/invalidate existing cache entries when customers upgrade and redeploy. After that purge, this stack prevents unsafe refills; the embedded classification manifest itself survives later content-cache purges.

Review guide

  1. packages/vinext/src/server/pages-router-entry.ts exposes authenticated Pages probe handling, registers adapters before admission, and enables capability-based no-manifest completion handling.
  2. packages/vinext/src/server/pages-page-handler.ts classifies Pages HTML and data contracts.
  3. packages/vinext/src/build/prerender-paths.ts reports concrete Pages data identities for real getStaticProps/ISR routes.
  4. packages/vinext/src/server/app-pages-bridge.ts transfers hybrid Pages admission ownership.
  5. packages/vinext/src/server/cacheability-request.ts and cacheability-manifest.ts enforce exact HTML/data identity and fail-closed admission.
  6. packages/cloudflare/src/cdn-warm.ts sends browser-equivalent HTML, RSC, and Pages data requests and validates each representation.
  7. The Pages cacheability and Route Handler Playwright specs exercise hybrid and Pages-only built Workers.

Review size

Layer-only diff against this PR's base: 49 files, +1,754/-165.

Validation

  • Pages/hybrid built-workerd regression — 5/5
  • current full-stack cumulative changed-file suites — 2,864/2,864
  • current full-stack PPR probe/admission/Pages built-workerd E2E — 8/8
  • current full-stack vp check and git diff --check
  • layer exact-head CI and deploy previews are green

@pkg-pr-new

pkg-pr-new Bot commented Aug 26, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@3098
npm i https://pkg.pr.new/create-vinext-app@3098
npm i https://pkg.pr.new/@vinext/types@3098
npm i https://pkg.pr.new/vinext@3098

commit: b40e1a9

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared b40e1a9 against base de0d12e using alternating same-runner rounds. Next.js was unchanged and skipped.

1 improved · 0 regressed · 5 within ±1.5%

Scenario Framework Baseline Current Change
Client bundle size (gzip) vinext 142.3 KB 142.3 KB ⚫ 0.0%
Client entry size (gzip) vinext 129.6 KB 129.6 KB ⚫ +0.0%
Dev server cold start vinext 3.38 s 3.29 s 🟢 -2.5%
Production build time vinext 3.78 s 3.75 s ⚫ -0.7%
RSC entry closure size (gzip) vinext 118.9 KB 119.0 KB ⚫ +0.0%
Server bundle size (gzip) vinext 202.3 KB 202.3 KB ⚫ +0.0%

View detailed results and traces

🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor
Example Preview Production Original
app-router-cloudflare preview production
pages-router-cloudflare preview production
app-router-playground preview production original
realworld-api-rest preview production
nextra-docs-template preview production
benchmarks preview production
hackernews preview production original
workers-cache preview production
static-export preview production
web preview production

@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

Hard time limit: 10 minutes. Review the exact current head only.

@ask-bonk

ask-bonk Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

error: Your local changes to the following files would be overwritten by checkout:
pnpm-lock.yaml
Please commit your changes or stash them before you switch branches.
Aborting

github run

@ask-bonk

ask-bonk Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

@james-elicx Bonk workflow was cancelled.

View workflow run · To retry, trigger Bonk again.

@james-elicx
james-elicx force-pushed the codex/cacheability-pages-router branch from 49db635 to 447d3c9 Compare August 26, 2026 23:00
@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

Please return all findings within a hard 10-minute limit.

@ask-bonk

ask-bonk Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

error: Your local changes to the following files would be overwritten by checkout:
pnpm-lock.yaml
Please commit your changes or stash them before you switch branches.
Aborting

github run

@james-elicx
james-elicx force-pushed the codex/cacheability-pages-router branch from dbe4141 to 18e9667 Compare August 26, 2026 23:59
@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues. Hard time limit: 20 minutes; return all findings or a partial review by then.

@james-elicx
james-elicx force-pushed the codex/cacheability-pages-router branch from 18e9667 to 1409c0f Compare August 27, 2026 00:43
@james-elicx
james-elicx force-pushed the codex/cacheability-pages-router branch from b1e5316 to c8de27d Compare August 27, 2026 00:58
@james-elicx
james-elicx force-pushed the codex/cacheability-pages-router branch from c8de27d to 60e9abe Compare August 27, 2026 01:15
@james-elicx
james-elicx force-pushed the codex/cacheability-pages-router branch 2 times, most recently from 299afed to 94bcd91 Compare August 27, 2026 01:41
@james-elicx
james-elicx force-pushed the codex/cacheability-pages-router branch from 94bcd91 to b40e1a9 Compare August 27, 2026 01:50
@james-elicx
james-elicx marked this pull request as ready for review August 27, 2026 08:09
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.

1 participant