mcpField
S
sanity-live-cache-components

sanity-live-cache-components

github.com/sanity-io開発957533 回インストール5 日前に更新
リポジトリ

sanity-live-cache-components について

コーディングエージェント向けに、Sanity LiveをNext.js 16以降のCache Componentsへ組み込むスキルです。Sanity固有のデータ取得、ドラフトモード、ライブ再検証を扱い、一般的なフレームワーク作業はNext.js公式スキルに委ねます。

主な機能

  1. 01Sanity LiveとCache Componentsの設定
  2. 02共有キャッシュ取得ヘルパー
  3. 03ドラフトモードとVisual Editingの接続
  4. 04コンテンツのライブ再検証
  5. 05移行と実行時検証のガイド

活用シーン

  1. 01Next.jsアプリへのSanity Live導入
  2. 02既存のSanityデータ取得方式の移行
  3. 03Presentation Toolでのドラフトプレビュー

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/sanity-io/next-sanity --skill sanity-live-cache-components

インストール後、Claude Code で/sanity-live-cache-componentsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

reference/
dynamic-segments.md
layouts.md
live-helpers.md
three-layer-pattern.md

詳細

Sanity Live + Cache Components

next-sanity を cacheComponents: true に設定した Next.js 16 以降のアプリに組み込みます。データは、単一の共有 'use cache' 境界(cachedSanity)を通じて sanityFetch で取得します。ルートレイアウトの <SanityLive> は、Sanity Content Lake への EventSource 接続を介してキャッシュ済みコンテンツを再検証します。ドラフトモードを有効にすると、Visual Editing と Presentation Tool が完全にサポートされます。

コードを書く前に、関連するガイドを node_modules/next/dist/docs/ で確認してください(利用可能な場合)。ガイドとこのスキルが矛盾する場合は、このスキルに従ってください。

このスキルでは、Cache Components ガイド(node_modules/next/dist/docs/ にオフライン版が含まれています)で説明されている Cache Components の基本事項('use cache'、cacheLife、cacheTag、cookies/headers/params のルール)を理解していることを前提とします。Sanity に関する例外は、await draftMode() を 'use cache' の内部で使用できることだけです(ドラフトモードが有効な場合、Next.js はキャッシュを回避します。詳細は use cache のリファレンスを参照してください)。

このスキルの位置づけ

Next.js には、フレームワーク共通のワークフローを扱う公式スキルが用意されています(AI コーディングエージェント向けにプロジェクトを設定するを参照)。このスキルが扱うのは Sanity の範囲のみで、それ以外は公式スキルに委ねます。Next.js リポジトリからインストールしてください。

npx skills add vercel/next.js --skill next-dev-loop
npx skills add vercel/next.js --skill next-cache-components-adoption
npx skills add vercel/next.js --skill next-cache-components-optimizer
npx skills add vercel/next.js --skill next-partial-prefetching-adoption

公式スキルのルールが適用される場合(ブロッキングルートのトリアージ、<Suspense> の配置、ローディング UI の再利用、instant() の回帰テスト、リンクのプリフェッチ監査など)は、その指針に従ってください。ここから指針を導き直す必要はありません。

アプリを移行する際の推奨手順:

  1. next-cache-components-adoption — cacheComponents: true を有効にし、ルートごとにアプリのビルドが成功する状態にします。Sanity の範囲はこのスキルに任せるよう指示してください。

    next-cache-components-adoption Skill を使用して、このプロジェクトに Cache Components を導入してください。ドラフトモードの処理と、すべての sanityFetch / <SanityLive> 呼び出し箇所は sanity-live-cache-components スキルに委ねてください。Sanity のデータ取得をリファクタリングするのではなく、それらのルートではオプトアウト(export const instant = false)したままにしてください。

  2. このスキル — defineLive と live.ts ヘルパーを設定し、sanityFetch の呼び出し箇所をリファクタリングして perspective / stega を正しく取得し、<SanityLive> / <VisualEditing> とドラフトモードを接続してから、保留していた Sanity ルートに残るオプトアウトを削除します。削除には、導入スキルのルートごとのループと成功基準(開発オーバーレイに問題がなく、ブラウザーで検証済みで、next build が成功すること)を使用してください。このスキルが提供するのは Sanity 固有の修正で、ループの進め方は導入スキルが提供します。

  3. 以下のいずれか、または両方を任意で追加できます:

    • next-cache-components-optimizer — ルートの静的シェルを拡張し、@next/playwright の instant() テストで保護します。プロンプト:「next-cache-components-optimizer Skill を使用して、/<route> へのナビゲーションを瞬時にしてください。」
    • next-partial-prefetching-adoption — partialPrefetching を有効にし、<Link prefetch={true}> の使用状況を監査します。プロンプト:「next-partial-prefetching-adoption Skill を使用して、このプロジェクトに Partial Prefetching を導入してください。」

    このスキルがどちらかを妨げることはありません。3 層パターンにより、公開ブランチのルートは完全に事前レンダリング可能な状態に保たれます。これは、これらのスキルが拡張し、プリフェッチする対象となるシェルそのものです。cachedSanity を介してキャッシュされた Sanity コンテンツも、ランタイムプリフェッチの要件である「URL に依存するキャッシュ済みコンテンツ」を満たします。

この一連の作業では、next-dev-loop を使って、実行時に変更を検証してください。コンパイルに成功しても、静的シェルとストリーミングのどちらに何が含まれるかは確認できません。

前提条件

  • プロジェクトに Next.js 16.3+ がインストールされていること(package.json を確認するか、pnpm list next / npm ls next を実行してください。pnpm view next version は使用しないでください。インストール済みのバージョンではなく、レジストリの最新バージョンが表示されます)。next-sanity v13 は Next.js 16 をサポートしますが、このスキルと組み合わせて使う公式スキルには 16.3+ が必要です。
  • AGENTS.md が存在すること。Next.js 16.3+ では、next dev が(バンドルされたドキュメントをエージェントに案内する)ファイルを自動生成します。それより古いバージョンでは、ガイドに従ってください。
  • 次の環境変数が設定されていること:
    • NEXT_PUBLIC_SANITY_PROJECT_ID
    • NEXT_PUBLIC_SANITY_DATASET
    • SANITY_API_READ_TOKEN
  • 埋め込み Sanity Studio の設定(sanity.config.ts、sanity.cli.ts、sanity/ 以下のすべてのファイル)は変更不要です。このスキルが変更するのは Next.js アプリの範囲のみです。

参考ファイル

ファイル読むタイミング
reference/live-helpers.mdclient.ts / live.ts の全内容、cachedSanity、sanityFetch*、getDynamicFetchOptions の詳細
reference/three-layer-pattern.mdsearchParams のバリエーションを含む、page.tsx 向けの Page → Dynamic → Cached パターン
reference/layouts.mdlayout.tsx 内でのノンブロッキングなデータ取得
reference/dynamic-segments.md高パフォーマンスな [slug] ルート:loading.tsx と部分的な generateStaticParams、またはレイアウト内でのノンブロッキングな動的 params

1. next-sanity@^13 をインストールする

npm install next-sanity@^13 --save-exact
既存の Sanity Live 設定の移行

アプリですでに defineLive を使用している場合、このスキルで行うのは書き換えではなくリファクタリングです。以下の 5 ステップの手順は引き続き適用されますが、次の点に注意してください。

  • client.ts または live.ts が存在する場合、上書きしないでください。 不足しているオプションを追加します。既存の token と stega.* の設定は維持してください。詳しくは reference/live-helpers.md を参照してください。
  • コードベース内で、sanityFetch の呼び出し箇所にあるハードコードされた perspective: 'published' と stega: false を検索し、 3 層パターンと getDynamicFetchOptions を使って perspective / stega を取得するようにリファクタリングしてください。
  • generateStaticParams 内の sanityFetch 呼び出しを検索し、 cachedSanityStaticParams に置き換えてください。
  • generateMetadata / sitemap.ts / opengraph-image.tsx などにある sanityFetch 呼び出しを検索し、 cachedSanityMetadata に置き換えてください。
  • 'use server' 関数内に直接記述された sanityFetch 呼び出しを検索し、 cachedSanity に置き換えてください。
  • ツリー内に <SanityLive> と <VisualEditing> がそれぞれ 1 つだけあることを確認してください。 複数回のレンダリングは未定義動作になります。

このファイルの末尾にある「grep で検索するアンチパターン」セクションに、検索パターンが記載されています。


2. next.config.ts を設定する

cacheComponents を有効にし、cacheLife.default を sanity に設定して、デフォルトの再検証期間を 1 年(15 分ではなく)にします。sanityFetch はオンデマンド再検証向けに最適化されているため、時間ベースの再検証は必要ありません。

// next.config.ts
import type {NextConfig} from 'next'
import {sanity} from 'next-sanity/live/cache-life'

const nextConfig: NextConfig = {
  cacheComponents: true,
  cacheLife: {default: sanity},
}

export default nextConfig

3. defineLive を設定し、ヘルパーをエクスポートする

src/sanity/lib/client.ts と src/sanity/lib/live.ts を作成します。live.ts の中核となる部分は次のとおりです。

// src/sanity/lib/live.ts (excerpt)
export const {SanityLive, sanityFetch} = defineLive({
  client,
  serverToken: token,
  browserToken: token,
  strict: true,
})

// The app's one shared 'use cache' boundary. `sanityFetch` calls
// `cacheTag`/`cacheLife` internally but doesn't create the boundary —
// this wrapper provides it once, so callers don't add their own.
export const cachedSanity: StrictDefinedFetchType = async (options) => {
  'use cache'
  return sanityFetch(options)
}

client.ts、getDynamicFetchOptions、cachedSanityMetadata、cachedSanityStaticParams を含むファイル全体の内容と、各ヘルパーのガイダンスについては、reference/live-helpers.md を参照してください。

live.ts からエクスポートされるヘルパーは次のとおりです。

ヘルパー使用箇所
cachedSanityサーバー側でコンテンツを取得する場合のデフォルト:ページ、レイアウト、コンポーネント、サーバーアクション
sanityFetch独自の 'use cache' を持つコンポーネント内のみ(レンダリングされた JSX もキャッシュします)
cachedSanityMetadatagenerateMetadata、generateViewport、sitemap.ts、robots.ts、opengraph-image.tsx など
cachedSanityStaticParamsgenerateStaticParams のみ
getDynamicFetchOptions'use cache' の境界の外で perspective/stega を解決する場合
SanityLiveルートレイアウトで一度だけレンダリング

4. ルートレイアウトで <SanityLive> をレンダリングする

<SanityLive> と <VisualEditing> はどちらも layout.tsx に配置し、page.tsx には配置しないでください。ツリー全体で、それぞれ最大1回だけレンダリングする必要があります。複数回レンダリングした場合の動作は未定義です。

  • defineLive を strict: true(推奨される設定)で構成する場合、includeDrafts は必須です。指定がない場合、TypeScript がエラーを通知します。ライブ再検証にドラフトが含まれるのはドラフトモードの場合のみとなるよう、includeDrafts={isDraftMode} を渡してください。
  • 移行時には、<SanityLive> に既存のオプションのコールバックプロパティがあれば維持してください。対象は onError、onWelcome、onReconnect です。これらは一般にトースト/通知ヘルパーに接続されているため、何も通知せずに削除すると UX が低下します。
// src/app/layout.tsx
import {SanityLive} from '@/sanity/lib/live'
import {VisualEditing} from 'next-sanity/visual-editing'
import {draftMode} from 'next/headers'

export default async function RootLayout({children}: LayoutProps<'/'>) {
  const {isEnabled: isDraftMode} = await draftMode()
  return (
    <html lang="en">
      <body>
        {children}
        <SanityLive includeDrafts={isDraftMode} />
        {isDraftMode && <VisualEditing />}
      </body>
    </html>
  )
}
Sanity Studio を埋め込む場合

ルートで next-sanity/studio の NextStudio をマウントする場合(例:app/studio/[[...index]]/page.tsx)、<SanityLive> は埋め込み Studio と共有されないレイアウトに配置する必要があります。ルートグループを使用し、<SanityLive> を src/app/(website)/layout.tsx に配置して、アプリの残りの部分も src/app/(website) の配下に置いてください。


5. ページとレイアウトに3層パターンを適用する

静的に事前レンダリングするすべてのルートで、同じ構成を使用します。

Page/Layout (Layer 1: draftMode branch)
  ├── NOT draft mode → <CachedX perspective="published" stega={false} />  (no Suspense)
  └── draft mode → <Suspense fallback={...}>
                      <DynamicX params={params} />  (Layer 2: awaits dynamic APIs)
                        └── <CachedX perspective={p} stega={s} />  (Layer 3: fetches via cachedSanity)

重要なルール:

  • キャッシュ境界は live.ts(cachedSanity)にあるため、通常、ルートファイルに 'use cache' ディレクティブを付ける必要はありません。特に、最上位の Page / Layout に 'use cache' を付けてはいけません。これらは params、searchParams、または(getDynamicFetchOptions 経由で)cookies() を待機し、これらの動的 API は 'use cache' 内では使用できないためです。最上位の関数に 'use cache' を追加するのが最もよくある失敗パターンです。TypeScript とランタイムの両方でエラーが発生します。
  • Layer 3 で cachedSanity を待機するだけで、ルート全体を静的シェルに事前レンダリングできます。公開ブランチでは <Suspense> は不要です。perspective と stega は自動的にラッパーのキャッシュキーに含まれるため、公開コンテンツとドラフトコンテンツでキャッシュエントリーが共有されることはありません。
  • 動的 API に触れるのは、Layer 2(<Suspense> 内でレンダリングされ、ドラフトモードでのみ動作)だけです。

編集するファイルに合ったリファレンスを選んでください。


Sanity の動作確認

リファクタリングのたびに next-dev-loop を使用してください。ループの仕組みと成功基準は、公式スキルに記載されています。Sanity 固有で確認すべき点は次のとおりです。

  • 公開ブランチ:ルートが完全に事前レンダリングされ(ビルドのルートテーブルで ◐ または ○)、<Suspense> のフォールバックが一瞬表示されることなくコンテンツがレンダリングされること。
  • ドラフトモード:有効にするとドラフトコンテンツがストリーミングされ、<VisualEditing> オーバーレイが表示され、Presentation Tool でパースペクティブを切り替えるとレンダリングされるコンテンツが変わること。
  • ライブ更新:Studio で公開済みコンテンツを編集すると、再ビルドせずにルートが再検証されること(<SanityLive> 経由)。

避けるべきパターンを検索する

アプリを監査するときは、以下を検索してリファクタリングしてください。

  • 共有コンポーネント内の sanityFetch / cachedSanity 呼び出しで、perspective: 'published' と stega: false が一緒にハードコードされている → 3層パターンを使用し、getDynamicFetchOptions 経由で perspective / stega を取得します。(Layer 1 のドラフト以外の分岐で、リテラルの perspective="published" stega={false} props を渡すのは適切なパターンであり、違反ではありません。)
  • 本文が 'use server' で始まる関数内の sanityFetch( → cachedSanity に置き換えます(先に getDynamicFetchOptions で perspective / stega を解決します)。
  • generateStaticParams 内の sanityFetch( → cachedSanityStaticParams に置き換えます。
  • generateMetadata / generateViewport / sitemap.ts / robots.ts / opengraph-image.tsx などにある sanityFetch( → cachedSanityMetadata に置き換え、getDynamicFetchOptions で perspective を解決します。
  • 独自の 'use cache' ディレクティブがないコンポーネント内の sanityFetch( → cachedSanity に置き換えます(レンダリングされた JSX をキャッシュする意図がある場合は、ディレクティブを追加します)。
  • loading.tsx を兄弟ファイルとして持たない page.tsx または layout.tsx の先頭で、await draftMode() の直後に await getDynamicFetchOptions() がある → これらの動的 API 呼び出しを <Suspense> でラップした子コンポーネントに移動し、静的シェルを事前レンダリングできるようにします。
  • ツリー内で <SanityLive> または <VisualEditing> が複数回レンダリングされている → 適切なレイアウト内でのレンダリングに統合します。

コメント