Commit Graph

2 Commits

Author SHA1 Message Date
James Anderson 4fefbbce84 fix(cache): attach path tags to prerender-seeded entries so revalidatePath invalidates them (#1486) (#1688)
Build-time prerender seeding (`isrSetPrerenderedAppPage`) and TPR upload were
writing cache entries with `tags: []`. Tag-based invalidation could never
reach them, so `revalidatePath('/foo')` left the seeded HTML/RSC stale until
the natural `revalidateAt` expired.

Compute the path-derived implicit tags via `buildAppPageCacheTags(pathname, [])`
in both seed paths and forward them through to the cache handler.

Closes (in part) #1486 — plain path invalidation. Rewrite-aware
invalidation (canonical-vs-rewrite key mismatch) is left for a follow-up.
2026-06-03 22:55:16 +01:00
Nathan Nguyen e19ec196c8 fix(tpr): use correct KV cache key format matching runtime (#736)
* fix(tpr): use correct KV cache key format matching runtime

TPR's uploadToKV wrote keys as `cache:<pathname>` but the runtime
KVCacheHandler reads `cache:app:<buildId>:<pathname>:html`. Every
TPR-seeded entry was a dead key — guaranteed cache miss on first
request.

Extract buildTprKVPairs() as a testable pure function that delegates
key construction to the shared isrCacheKey(), and read buildId from
the prerender manifest at upload time.

* fix(tpr): read buildId from BUILD_ID file instead of prerender manifest

TPR doesn't use the prerender pipeline, so vinext-prerender.json never
exists in TPR context. Write a standalone BUILD_ID file during every
build (matching Next.js convention) and read from that instead.

* address bonk review comments

- Add console.warn when BUILD_ID can't be read so operators can diagnose key mismatches
- Match runtime KVCacheHandler TTL strategy: use flat MAX_KV_TTL_SECONDS (30d) instead of 10x revalidate, preventing premature eviction of low-traffic TPR-seeded pages
- Export ENTRY_PREFIX from kv-cache-handler.ts and import it in tpr.ts instead of duplicating with a comment
- Restrict vinext:build-id writeBundle to rsc environment only (was firing for both rsc+ssr, writing duplicate files)
- Guard nextConfig resolution so buildId is generated exactly once per plugin instance across all Vite environments
- Update tpr-kv-keys tests to reflect new flat-TTL behaviour

* address second bonk review round

- Document intentional 24h fallback TTL divergence from runtime for non-revalidating entries
- Clarify index.ts guard comment: resolveNextConfig()->resolveBuildId() chain; note fileMatcher etc stay outside guard intentionally
- Make missing BUILD_ID a hard failure: skip KV upload entirely instead of proceeding with dead keys
- Update no-buildId test to document it exercises buildTprKVPairs() directly; runTPR() now fails fast before reaching that path

* fix(build-id): write BUILD_ID once per build via closeBundle, not per-environment

The previous writeBundle + envName === 'rsc' guard only wrote BUILD_ID for
App Router builds. Pages Router builds (ssr environment) and any future
router types were silently skipped.

BUILD_ID has nothing to do with which environment is active — it is a
per-build property. Replace with a closeBundle hook wrapped in an IIFE that
carries a write-once guard (buildIdWritten flag). The output path is always
root/dist/server/BUILD_ID, derived from the plugin-level root variable, so
it is router-agnostic and matches exactly where tpr.ts reads it from.

---------

Co-authored-by: James <james@eli.cx>
2026-04-01 22:54:17 +01:00