mcpField
C
cache-components

cache-components

github.com/laguagu开发70214 次安装2 天前更新
代码仓库

关于 cache-components

Cache Components 是应用 Next.js 缓存模式的技能,强调保留项目现有配置。它帮助开发者核实版本相关行为、缓存边界、数据新鲜度与失效规则,并提供生产行为测试指引。

主要功能

  1. 01按 Next.js 版本提供缓存指引
  2. 02设计缓存边界与键
  3. 03设置新鲜度和失效模式
  4. 04安排 Suspense 与请求数据
  5. 05迁移与故障排查指引
  6. 06生产行为测试清单

适用场景

  1. 01在应用中采用 Cache Components
  2. 02设置缓存时长和失效规则
  3. 03诊断路由过期或阻塞
  4. 04在生产模式验证导航与数据变更

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/laguagu/claude-code-nextjs-skills --skill cache-components

安装后在 Claude Code 中输入/cache-components确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

PATTERNS.md
REFERENCE.md
TROUBLESHOOTING.md

详细介绍

缓存组件

除非用户要求迁移,否则保留项目当前的缓存模式。应用这些模式前,请确认已安装的 Next.js 版本以及 cacheComponents/partialPrefetching 配置。

请先阅读 node_modules/next/dist/docs/ 中的相关指南(自 16.2 起随包提供;在 monorepo 中,请使用应用自身的 next 包)。Web 路径会映射到带编号的文件夹,因此请按名称查找:.../functions/cacheLife 对应 01-app/03-api-reference/04-functions/cacheLife.md。在 01-app/ 下,请先阅读 02-guides/migrating-to-cache-components.md、01-getting-started/08-caching.md 和 02-guides/instant-navigation.md。/docs/messages 下的错误页面不会随包提供;next dev/next build 会直接输出可用的修复选项。如果本地没有文档,请参阅官方缓存文档。准确的导出项和签名也可在 node_modules/next/cache.d.ts 中找到。对于 16.4 及更高版本中有关静态输出和分阶段延迟的问题,请按名称查找已安装版本中的 ensureStatic 路由段参考,以及 navigation/prefetch 函数参考。

目标是生成实用的预渲染外壳,同时确保在发生变更、部署和客户端导航后,数据新鲜度与授权规则依然正确。

旧示例常见的错误说法

  • Next.js 16 通过顶层的 cacheComponents: true 启用此模式。它取代了 experimental.dynamicIO、experimental.useCache 和 experimental.ppr; cacheLife/cacheTag 从 next/cache 导入,无需加 unstable_。 在 16.4 中,需显式设置 partialPrefetching:不设置会发出警告; 推荐的 create-next-app 默认会启用这两个标志。
  • 启用此模式后,分段导出 dynamic、revalidate、fetchCache 和 dynamicParams 都会报错,且不支持 Edge 运行时。revalidate = N 在 use cache 内改为 cacheLife(使用最接近的配置文件或自定义配置文件); force-dynamic 和 fetchCache 不再需要;fetch next: { revalidate, tags } 改为在 use cache 函数中使用 cacheLife/cacheTag;请求数据应放在 Suspense 下;未知参数的 dynamicParams = false 改为调用 notFound()。
  • 现有的 fetch 和 unstable_cache 缓存仍可作为独立层继续工作, 因此不要机械地重写每次读取。缓存能否跨部署和实例持久化,取决于是否保留或共享存储;默认情况下,可自托管的实例不会共享缓存。use cache 默认使用内存缓存;即使有持久化处理程序,构建或部署 ID 变化后也无法复用缓存条目。
  • generateStaticParams 必须至少返回一个参数:返回 [] 会导致构建失败, 移除此导出则会使路由在每次请求时都渲染。
  • revalidate: 0 或低于 5 分钟的 expire 会生成请求时填充,而不是预渲染输出;预设中只有 seconds 会这样。16.3 新增了 stale 阈值(低于 30 秒:不预渲染;低于 5 分钟:不放入 App Shell)。
  • 预渲染期间同步调用 new Date()、Math.random() 或 crypto.randomUUID() 会报错:可在 use cache 中捕获其值,或在 Suspense 下使用 await io()(next/cache,16.3+)或 await connection()(next/server)延后执行。
  • use cache: private 在 16.2 及更早版本中为实验性功能。它在请求时运行, 不会进入静态外壳,也不接受自定义处理程序。
  • export const instant(16.3;16.2 中为 unstable_instant)会将分段纳入 即时导航验证。从 16.3 开始,只有在 next dev 中(通过开发覆盖层),每个 Page/Default 分段才会在默认级别隐式接受验证;构建时验证需要将 experimental.instantInsights.validationLevel 设为 experimental-error 或 experimental-manual-error(16.2 中的 unstable_instant 也会在构建时验证)。使用 @next/playwright 的 instant() 测试导航。instant = false 允许阻塞式路由; 但不会清除同步 IO 错误。

对于整个应用的迁移或即时导航工作,Next.js 在 vercel/next.js/skills 中发布了工作流 技能(next-cache-components-adoption、next-cache-components-optimizer);随附的迁移指南涵盖了相同的步骤。

单个路由的结构

app/posts/page.tsx,经 next 16.3.8 验证,且启用了 cacheComponents: true (tsc --noEmit、next build,以及在 next start 下运行操作)。@/lib/* 是 项目代码。

import { Suspense } from 'react'
import { cookies } from 'next/headers'
import { cacheLife, cacheTag, updateTag } from 'next/cache'
import { insertPost, listPosts } from '@/lib/posts' // project code
import { requireEditor } from '@/lib/auth' // throws unless the session may edit

async function getPosts() {
  'use cache' // shared entry: no cookies/headers/searchParams inside
  cacheLife('hours')
  cacheTag('posts')
  return listPosts()
}

async function Theme() {
  const theme = (await cookies()).get('theme')?.value // request-time, outside the cache
  return <p>Theme: {theme ?? 'system'}</p>
}

async function addPost(formData: FormData) {
  'use server'
  await requireEditor()
  const title = String(formData.get('title') ?? '').trim()
  if (!title) return
  await insertPost(title)
  updateTag('posts') // Server Actions only; the next read waits for fresh data
}

export default async function Page() {
  const posts = await getPosts() // cached, so it can be part of the static shell
  return (
    <>
      <ul>{posts.map((p) => <li key={p.id}>{p.title}</li>)}</ul>
      <Suspense fallback={<p>Theme: …</p>}><Theme /></Suspense>
      <form action={addPost}><input name="title" /><button>Add</button></form>
    </>
  )
}

确定边界

  • 当产品的新鲜度和数据策略允许时,缓存可复用的结果。 静态内容无需仅为了成为静态内容而添加指令。
  • 普通的 use cache 作用域无法读取 cookies、headers、searchParams,也无法调用 connection(), 包括通过辅助函数间接调用的情况。在作用域外读取这些值,并传入经过授权且可序列化的值。 如果输出取决于账户/租户 ID,这些 ID 必须参与缓存键。 对于动态渲染的路由,next-request-in-use-cache 错误可能在 next build 时不出现,只在 next start 下暴露。
  • 将未缓存的 IO 和仅限请求时显示的内容放在适当的 Suspense 边界下。Suspense 会提供备用 UI,但本身不会让同步工作变为动态。
  • 根据已安装版本的文档和部署处理程序评估私有/远程变体。私有缓存并不保证合规;远程缓存不是一致性协议。

定义新鲜度和失效策略

根据实际可接受的陈旧程度选择生命周期。项目可以覆盖命名配置;在假定时长之前,请先查看项目配置。

当失效操作必须跨路由作用于同一实体时使用标签;针对路由特定输出时使用路径失效;如果过期策略符合要求,则使用过期策略。在执行变更前进行身份验证、授权和验证。仅使受影响的缓存数据失效:

  • updateTag:立即过期,支持读后写一致性;仅适用于 Server Actions。
  • revalidateTag(tag, 'max'):在后续访问时采用陈旧后重新验证策略。
  • revalidateTag(tag, { expire: 0 }):当 webhook/Route Handler 需要立即过期时使用。单参数形式已弃用。

这些标签 API 也可用于带标签的 fetch 数据;它们可用本身并不意味着已启用 Cache Components。

根据问题查阅

  • API 边界:键、序列化、生命周期、处理程序和路由 API。
  • 组合方式:租户隔离、嵌套缓存、透传和动态参数。
  • 故障排查:诊断阻塞、陈旧或不一致的输出。

运行生产构建,然后在 next start 下测试冷启动/直接导航、客户端导航、相关变更及后续读取。 在适用时检查租户隔离和多实例失效行为。 构建成功无法验证这些行为。

评论

支持 Markdown