Skip to content

perf(sponsor): render wall statically with on-demand revalidation - #54

Merged
mkdir700 merged 1 commit into
mainfrom
perf/sponsor-page-static
Jun 24, 2026
Merged

perf(sponsor): render wall statically with on-demand revalidation#54
mkdir700 merged 1 commit into
mainfrom
perf/sponsor-page-static

Conversation

@mkdir700

@mkdir700 mkdir700 commented Jun 24, 2026

Copy link
Copy Markdown
Member

问题

/sponsor 页面之前是 force-dynamic,每次访问都做完整 SSR:

  • 两次 DB 查询(SponsorHeroSponsorWall 各调一次 getPublicSponsors
  • 每次重新渲染整棵 React 树

赞助名单只在后台 admin 操作时才变,绝大多数访问都在做无意义的 DB 查询 + 渲染——正是 #53 想砍掉的那类 Vercel Active CPU 消耗。

方案

套用仓库里已有的「静态渲染 + cache tag 按需失效」模式(与 articles / use-cases 一致):

  • sponsors-store:用 unstable_cache 包裹 getPublicSponsors,打上新增的 SPONSORS_PUBLIC_CACHE_TAG。附带把 hero + wall 同一次渲染里的两次读取去重成一次 DB 查询。
  • sponsor/page:删除 force-dynamic,改为 revalidate = 1800。layout 的 generateStaticParams + setRequestLocale 已让子树静态化(无 cookies/headers 依赖),页面现在从缓存直出;30 分钟 ISR 仅作兜底。
  • admin sponsor 路由(create / update / delete / reorder):调用 revalidateTag(SPONSORS_PUBLIC_CACHE_TAG),赞助墙按需重建。

self-service 邀请链接 claim 路由无需失效:它创建的是 pending 行,要等 admin 审核 publish(走上面的 PATCH 路由)后才上墙。

效果

赞助页从「每次访问 SSR + 2 次 DB 查询」变为「CDN 缓存直出,仅 admin 改动时重建」。部署后可在构建路由表确认 /sponsorƒ (Dynamic) 变为 ● (ISR)

验证

  • bun run typecheck
  • eslint(改动文件)✅

Summary by CodeRabbit

  • New Features

    • Sponsor content is now cached for faster loading, with updates still appearing after admin changes.
  • Bug Fixes

    • Public sponsor updates now refresh immediately after adding, editing, deleting, or reordering sponsors.
    • Sponsor page rendering now falls back to a 30-minute refresh window instead of loading fresh on every visit.

The /sponsor page was force-dynamic, so every visit paid a full SSR: two
DB reads (SponsorHero + SponsorWall each call getPublicSponsors) plus a
fresh render of the whole tree. The sponsor list only changes on admin
edits, so the per-request DB query + render was wasted Vercel Active CPU
— the same class of cost #53 cut for the rest of the [locale] subtree.

Switch to the repo's established static + tag-based revalidation pattern
(mirrors articles / use-cases):

- sponsors-store: wrap getPublicSponsors in unstable_cache under a new
  SPONSORS_PUBLIC_CACHE_TAG. Also dedupes the hero + wall reads in a
  single render into one DB query.
- sponsor/page: drop force-dynamic for `revalidate = 1800`. The layout's
  generateStaticParams + setRequestLocale already make the subtree static
  (no cookies/headers), so the page now serves from cache. The 30-min ISR
  window is just a safety net.
- admin sponsor routes (create / update / delete / reorder): call
  revalidateTag(SPONSORS_PUBLIC_CACHE_TAG) so the wall rebuilds on demand.

Self-service claim links need no revalidation: they create `pending` rows
that only reach the wall after an admin publish (the PATCH route above).
@vercel

vercel Bot commented Jun 24, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
uc-website Error Error Jun 24, 2026 9:59am

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

The public sponsors list is now served from a Next.js unstable_cache layer keyed by SPONSORS_PUBLIC_CACHE_TAG. The sponsor page switches from force-dynamic to a 30-minute ISR fallback. All four admin mutation routes (create, update, delete, reorder) call revalidateTag(SPONSORS_PUBLIC_CACHE_TAG) after each successful write.

Sponsor Wall ISR Caching

Layer / File(s) Summary
Cache foundation: sponsors-store and sponsor page
src/lib/sponsors-store.ts, src/app/[locale]/sponsor/page.tsx
Exports SPONSORS_PUBLIC_CACHE_TAG, introduces getPublicSponsorsRaw for the uncached DB query, wraps it with unstable_cache as the new getPublicSponsors, and replaces force-dynamic on the sponsor page with revalidate = 1800.
Admin route cache invalidation
src/app/api/admin/sponsors/route.ts, src/app/api/admin/sponsors/[id]/route.ts, src/app/api/admin/sponsors/reorder/route.ts
Imports revalidateTag and SPONSORS_PUBLIC_CACHE_TAG in all three admin route files; calls revalidateTag(SPONSORS_PUBLIC_CACHE_TAG) after successful POST (create), PATCH (update), DELETE, and reorder operations.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 Hop hop, no more fetching each time,
The sponsors are cached — oh how sublime!
A tag named just right, the wall stays fresh,
When admins mutate, the cache gets a refresh.
Thirty minutes of rest, then revalidate anew,
This little rabbit cached something for you! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: static sponsor wall rendering with on-demand revalidation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/sponsor-page-static

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mkdir700
mkdir700 merged commit 6a271b2 into main Jun 24, 2026
3 of 5 checks passed
@mkdir700
mkdir700 deleted the perf/sponsor-page-static branch June 24, 2026 10:01
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