feat(website): AllowPageCache section for CMS-only pages - #1649
Conversation
The runtime only emits a public Cache-Control when a middleware marks the request as cacheable via PAGE_CACHE_ALLOWED_KEY. Commerce apps (VTEX) set this from their middleware, but that middleware is a resolver middleware and only runs when a block from that app is resolved. CMS-only pages (e.g. a home built purely from website sections, no commerce loader) never opt in and stay uncached. This adds an editor-droppable section that opts the current page into caching by setting the bag key. It renders nothing and remains guarded by the runtime: a foreign Set-Cookie or a no-store from another block on the page still wins. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tagging OptionsShould a new tag be published when this PR is merged?
|
📝 WalkthroughWalkthroughAdds a non-visual ChangesPage cache opt-in
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
1 issue found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="website/sections/Cache/AllowPageCache.tsx">
<violation number="1" location="website/sections/Cache/AllowPageCache.tsx:18">
P2: The loader uses `ctx.bag?.set(...)`, which will silently do nothing if `bag` is undefined — but setting this key is the sole purpose of the section, so a silent no-op means the page stays uncached with no indication why. The VTEX middleware this PR mirrors uses non-optional `ctx.bag.set(...)`; consider matching that or adding a warning if bag is missing.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| * same page marks the response `no-store`, that decision wins. | ||
| */ | ||
| export const loader = (_props: unknown, _req: Request, ctx: AppContext) => { | ||
| ctx.bag?.set(PAGE_CACHE_ALLOWED_KEY, true); |
There was a problem hiding this comment.
P2: The loader uses ctx.bag?.set(...), which will silently do nothing if bag is undefined — but setting this key is the sole purpose of the section, so a silent no-op means the page stays uncached with no indication why. The VTEX middleware this PR mirrors uses non-optional ctx.bag.set(...); consider matching that or adding a warning if bag is missing.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At website/sections/Cache/AllowPageCache.tsx, line 18:
<comment>The loader uses `ctx.bag?.set(...)`, which will silently do nothing if `bag` is undefined — but setting this key is the sole purpose of the section, so a silent no-op means the page stays uncached with no indication why. The VTEX middleware this PR mirrors uses non-optional `ctx.bag.set(...)`; consider matching that or adding a warning if bag is missing.</comment>
<file context>
@@ -0,0 +1,25 @@
+ * same page marks the response `no-store`, that decision wins.
+ */
+export const loader = (_props: unknown, _req: Request, ctx: AppContext) => {
+ ctx.bag?.set(PAGE_CACHE_ALLOWED_KEY, true);
+ return {};
+};
</file context>
|
Superseded by the |
Problem
The FARM home (and any CMS-only page) isn't being CDN-cached because it doesn't go through any VTEX loader.
The runtime (
deco/runtime/middleware.ts→applyPageCacheDecision) uses an opt-in model: it only emits a publicCache-Controlwhen some middleware has setPAGE_CACHE_ALLOWED_KEYon the request bag.The only thing that sets that key is
apps/vtex/middleware.ts. But an appmiddlewareis composed as a resolver middleware (blocks/appsUtil.ts→compose(...middlewares, blockResolver)), so it only runs when a block from that app is resolved. A page built purely fromwebsite/CMS sections with no commerce loader never triggers it →isPageCacheAllowed = false→ no publicCache-Control→ the page is never cached.Fix
An editor-droppable
websitesection that opts the current page into the existing caching pipeline by settingPAGE_CACHE_ALLOWED_KEYfrom its loader. It renders nothing.Drop Allow Page Cache on a CMS-only page (e.g. the home) to make it cacheable.
Why it's safe
It's still fully guarded by the runtime
applyPageCacheDecision:Set-Cookie→no-storewins;shouldCacheFromVary === false→no-storewins;Cache-Control(e.g. a VTEX loader markingno-storefor a logged-in/segmented request) wins, since the runtime only sets the public directiveif (!headers.has("Cache-Control")).So it never forces caching of a personalized response — it only fills the opt-in gap for pages that have no app to vouch for them.
Notes
ctx.bag.set(PAGE_CACHE_ALLOWED_KEY, true)API as the VTEX middleware.website/manifest.gen.ts.deno check website/mod.tspasses;deno fmtapplied.🤖 Generated with Claude Code
Summary by cubic
Adds a new
AllowPageCachewebsite section that lets CMS‑only pages opt into CDN caching by settingPAGE_CACHE_ALLOWED_KEY. It renders nothing and respects existing runtime cache safety checks.New Features
PAGE_CACHE_ALLOWED_KEYin its loader to enable public Cache-Control on CMS-only pages (e.g., home).Set-Cookieis present or another block sets cache headers.Migration
AllowPageCacheto any CMS-only page you want cached; no props needed.Written for commit 4580918. Summary will update on new commits.