mcpField
T
tinacms

tinacms

github.com/jackspace開発1640 回インストール12 週間前に更新
リポジトリ

tinacms について

コンテンツ中心の Web アプリに TinaCMS を組み込むための実践的なスキルです。複数のフレームワークでの設定、スキーマ設計、トラブルシューティングを扱い、Git 管理とビジュアル編集を使うサイトの開発者向けです。

主な機能

  1. 01フレームワーク別の設定ガイド
  2. 02スキーマとコレクションの設計
  3. 03ビジュアル編集の連携
  4. 04設定とエラーのトラブル対応

活用シーン

  1. 01Next.js サイトへの CMS 導入
  2. 02ブログやドキュメントのコンテンツ設計
  3. 03編集者向けライブプレビューの有効化

インストール

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

$npx skills add https://github.com/jackspace/claudeskillz --skill tinacms

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

同梱ファイルREADME.mdSKILL.json

詳細

TinaCMS スキル

モダンなウェブアプリケーションに TinaCMS を統合するための完全なスキルです。


TinaCMS とは?

TinaCMS は、開発者とコンテンツ制作者がコンテンツ中心のウェブサイトでスムーズに共同作業できる、オープンソースの Git ベースのヘッドレスコンテンツ管理システム(CMS)です。

主な機能
  1. Git ベースのストレージ

    • Git リポジトリ内に Markdown、MDX、または JSON ファイルとしてコンテンツを保存します
    • 完全なバージョン管理と変更履歴を利用できます
    • ベンダーロックインがなく、コンテンツはリポジトリ内に保存されます
  2. ビジュアル/コンテキスト編集

    • 横並びの編集エクスペリエンス
    • 入力中に変更をライブプレビューできます
    • Markdown コンテンツを WYSIWYG のように編集できます
  3. スキーマ駆動のコンテンツモデリング

    • コード内でコンテンツ構造を定義します(tina/config.ts)
    • スキーマから型安全な GraphQL API が自動生成されます
    • コンテンツを整理するためのコレクションとフィールドのシステム
  4. 柔軟なデプロイ

    • TinaCloud:マネージドサービス(最も簡単で、無料プランも利用できます)
    • セルフホスト:Cloudflare Workers、Vercel Functions、Netlify Functions、AWS Lambda
    • 複数の認証オプション(Auth.js、カスタム、ローカル開発)
  5. フレームワークのサポート

    • 最適:Next.js(App Router と Pages Router)
    • 良好:React、Astro(ビジュアル編集は実験的)、Gatsby、Hugo、Jekyll、Remix、11ty
    • フレームワーク非依存:あらゆるフレームワークで動作します(ビジュアル編集は React に限定)
現在のバージョン
  • tinacms:2.9.0(2025年9月)
  • @tinacms/cli:1.11.0(2025年10月)
  • React のサポート:19.x(>=18.3.1 <20.0.0)

このスキルを使う場面

✅ TinaCMS を使う場合:
  1. コンテンツ中心のサイトを構築する

    • ブログや個人ウェブサイト
    • ドキュメントサイト
    • マーケティングウェブサイト
    • ポートフォリオサイト
  2. 技術に詳しくない編集者にもアクセスが必要

    • コーディングの知識がないコンテンツチーム
    • ページを管理するマーケティングチーム
    • ブログ記事を執筆する著者
  3. Git ベースのワークフローを希望する

    • Git でコンテンツをバージョン管理したい
    • プルリクエストでコンテンツをレビューする必要がある
    • コードとともにリポジトリ内でコンテンツを管理したい
  4. ビジュアル編集が必要

    • 編集者が変更をライブで確認したい
    • WYSIWYG のエクスペリエンスが望ましい
    • 横並びの編集ワークフローを使いたい
❌ TinaCMS を使わない場合:
  1. リアルタイムの共同作業が必要

    • 複数のユーザーが同時に編集する場合(Google ドキュメントのような形式)
    • 代わりに Sanity、Contentful、または Firebase を使ってください
  2. 動的なデータが多い

    • 在庫が頻繁に変動する E コマースの商品カタログ
    • リアルタイムのダッシュボード
    • 代わりに従来型のデータベース(D1、PostgreSQL)を使ってください
  3. コンテンツ管理が不要

    • アプリケーションがコンテンツ駆動ではなく、データ駆動である
    • ハードコードされたコンテンツで十分である

フレームワーク別のセットアップパターン

使用するフレームワークに応じたセットアップパターンを使ってください。

1. Next.js のセットアップ(推奨)
App Router(Next.js 13 以降)

手順:

  1. TinaCMS を初期化します:

    npx @tinacms/cli@latest init
    
    • 公開アセットディレクトリを尋ねられたら、public と入力します
  2. package.json のスクリプトを更新します:

    {
      "scripts": {
        "dev": "tinacms dev -c \"next dev\"",
        "build": "tinacms build && next build",
        "start": "tinacms build && next start"
      }
    }
    
  3. 環境変数を設定します:

    # .env.local
    NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id
    TINA_TOKEN=your_read_only_token
    
  4. 開発サーバーを起動します:

    npm run dev
    
  5. 管理インターフェースにアクセスします:

    http://localhost:3000/admin/index.html
    

作成される主なファイル:

  • tina/config.ts - スキーマ設定
  • app/admin/[[...index]]/page.tsx - 管理 UI のルート(App Router を使う場合)

テンプレート:templates/nextjs/tina-config-app-router.ts を参照してください


Pages Router(Next.js 12 以前)

セットアップは同じですが、管理ルートは次のようになります:

  • app ディレクトリの代わりに pages/admin/[[...index]].tsx

データ取得パターン:

// pages/posts/[slug].tsx
import { client } from '../../tina/__generated__/client'
import { useTina } from 'tinacms/dist/react'

export default function BlogPost(props) {
  // Hydrate for visual editing
  const { data } = useTina({
    query: props.query,
    variables: props.variables,
    data: props.data
  })

  return (
    <article>
      <h1>{data.post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: data.post.body }} />
    </article>
  )
}

export async function getStaticProps({ params }) {
  const response = await client.queries.post({
    relativePath: `${params.slug}.md`
  })

  return {
    props: {
      data: response.data,
      query: response.query,
      variables: response.variables
    }
  }
}

export async function getStaticPaths() {
  const response = await client.queries.postConnection()
  const paths = response.data.postConnection.edges.map((edge) => ({
    params: { slug: edge.node._sys.filename }
  }))

  return { paths, fallback: 'blocking' }
}

テンプレート:templates/nextjs/tina-config-pages-router.ts を参照してください


2. Vite + React のセットアップ

手順:

  1. 依存関係をインストールします:

    npm install react@^19 react-dom@^19 tinacms
    
  2. TinaCMS を初期化します:

    npx @tinacms/cli@latest init
    
    • 公開アセットのディレクトリを public に設定します
  3. vite.config.ts を更新します:

    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'
    
    export default defineConfig({
      plugins: [react()],
      server: {
        port: 3000  // TinaCMS default
      }
    })
    
  4. package.json のスクリプトを更新します:

    {
      "scripts": {
        "dev": "tinacms dev -c \"vite\"",
        "build": "tinacms build && vite build",
        "preview": "vite preview"
      }
    }
    
  5. 管理インターフェースを作成します:

    オプション A:手動ルート(React Router)

    // src/pages/Admin.tsx
    import TinaCMS from 'tinacms'
    
    export default function Admin() {
      return <div id="tina-admin" />
    }
    

    オプション B:直接 HTML

    
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8" />
        <title>Tina CMS</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
      </head>
      <body>
        <div id="root"></div>
        <script type="module" src="/@fs/[path-to-tina-admin]"></script>
      </body>
    </html>
    
  6. ビジュアル編集には useTina フックを使用します:

    import { useTina } from 'tinacms/dist/react'
    import { client } from '../tina/__generated__/client'
    
    function BlogPost({ initialData }) {
      const { data } = useTina({
        query: initialData.query,
        variables: initialData.variables,
        data: initialData.data
      })
    
      return (
        <article>
          <h1>{data.post.title}</h1>
          <div>{/* render body */}</div>
        </article>
      )
    }
    
  7. 環境変数を設定します:

    # .env
    VITE_TINA_CLIENT_ID=your_client_id
    VITE_TINA_TOKEN=your_read_only_token
    

テンプレート:templates/vite-react/ を参照してください。


3. Astro のセットアップ

手順:

  1. 公式スターターを使用します(推奨):

    npx create-tina-app@latest --template tina-astro-starter
    

    または、手動で初期化します:

    npx @tinacms/cli@latest init
    
  2. package.json のスクリプトを更新します:

    {
      "scripts": {
        "dev": "tinacms dev -c \"astro dev\"",
        "build": "tinacms build && astro build",
        "preview": "astro preview"
      }
    }
    
  3. Astro を設定します:

    // astro.config.mjs
    import { defineConfig } from 'astro/config'
    import react from '@astro/react'
    
    export default defineConfig({
      integrations: [react()]  // Required for Tina admin
    })
    
  4. ビジュアル編集(実験的機能):

    • React コンポーネントが必要です
    • インタラクティブな編集には client:tinaDirective を使用します
    • 2025 年 10 月時点では、完全なビジュアル編集は実験的機能です
  5. 環境変数を設定します:

    # .env
    PUBLIC_TINA_CLIENT_ID=your_client_id
    TINA_TOKEN=your_read_only_token
    

最適な用途:コンテンツ中心の静的サイト、ドキュメント、ブログ

テンプレート:templates/astro/ を参照してください。


4. フレームワークに依存しないセットアップ

対象:Hugo、Jekyll、Eleventy、Gatsby、Remix、または任意のフレームワーク

手順:

  1. TinaCMS を初期化します:

    npx @tinacms/cli@latest init
    
  2. ビルドスクリプトを手動で設定します:

    {
      "scripts": {
        "dev": "tinacms dev -c \"<your-dev-command>\"",
        "build": "tinacms build && <your-build-command>"
      }
    }
    
  3. 管理インターフェース:

    • http://localhost:<port>/admin/index.html に自動的に作成されます
    • ポートは使用するフレームワークによって異なります
  4. データの取得:

    • ビジュアル編集は利用できません(サイドバーのみ)
    • Git と連携したインターフェースからコンテンツを編集します
    • 変更はファイルに直接保存されます
  5. 環境変数を設定します:

    TINA_CLIENT_ID=your_client_id
    TINA_TOKEN=your_read_only_token
    

制限事項:

  • ビジュアル編集は利用できません(React のみの機能)
  • 手動での統合が必要です
  • サイドバーでの編集のみ利用できます

スキーマモデリングのベストプラクティス

コンテンツ構造は tina/config.ts で定義します。

基本的な設定構造
import { defineConfig } from 'tinacms'

export default defineConfig({
  // Branch configuration
  branch: process.env.GITHUB_BRANCH ||
          process.env.VERCEL_GIT_COMMIT_REF ||
          'main',

  // TinaCloud credentials (if using managed service)
  clientId: process.env.NEXT_PUBLIC_TINA_CLIENT_ID,
  token: process.env.TINA_TOKEN,

  // Build configuration
  build: {
    outputFolder: 'admin',
    publicFolder: 'public',
  },

  // Media configuration
  media: {
    tina: {
      mediaRoot: '',
      publicFolder: 'public',
    },
  },

  // Content schema
  schema: {
    collections: [
      // Define collections here
    ],
  },
})

コレクション

コレクション = コンテンツタイプ+ディレクトリのマッピング

{
  name: 'post',           // Singular, internal name (used in API)
  label: 'Blog Posts',    // Plural, display name (shown in admin)
  path: 'content/posts',  // Directory where files are stored
  format: 'mdx',          // File format: md, mdx, markdown, json, yaml, toml
  fields: [/* ... */]     // Array of field definitions
}

主なプロパティ:

  • name:内部識別子(英数字とアンダースコアのみ)
  • label:管理インターフェースに表示する名前
  • path:プロジェクトルートからの相対ファイルパス
  • format:ファイル拡張子(既定値は 'md')
  • fields:コンテンツ構造の定義

フィールドタイプのリファレンス
タイプ用途例
string短いテキスト(1 行)タイトル、スラッグ、著者名
rich-text書式付きの長いコンテンツブログ本文、ページコンテンツ
number数値価格、数量、評価
datetime日付/時刻公開日、イベント時刻
boolean真偽値の切り替え下書きステータス、注目フラグ
image画像のアップロードヒーロー画像、サムネイル、アバター
reference別のドキュメントへのリンク著者、カテゴリ、関連投稿
object入れ子になったフィールドのグループSEO メタデータ、ソーシャルリンク

完全なリファレンス:references/field-types-reference.md を参照してください。


コレクションのテンプレート
ブログ投稿コレクション
{
  name: 'post',
  label: 'Blog Posts',
  path: 'content/posts',
  format: 'mdx',
  fields: [
    {
      type: 'string',
      name: 'title',
      label: 'Title',
      isTitle: true,  // Shows in content list
      required: true
    },
    {
      type: 'string',
      name: 'excerpt',
      label: 'Excerpt',
      ui: {
        component: 'textarea'  // Multi-line input
      }
    },
    {
      type: 'image',
      name: 'coverImage',
      label: 'Cover Image'
    },
    {
      type: 'datetime',
      name: 'date',
      label: 'Published Date',
      required: true
    },
    {
      type: 'reference',
      name: 'author',
      label: 'Author',
      collections: ['author']  // References author collection
    },
    {
      type: 'boolean',
      name: 'draft',
      label: 'Draft',
      description: 'If checked, post will not be published',
      required: true
    },
    {
      type: 'rich-text',
      name: 'body',
      label: 'Body',
      isBody: true  // Main content area
    }
  ],
  ui: {
    router: ({ document }) => `/blog/${document._sys.filename}`
  }
}

テンプレート:templates/collections/blog-post.ts を参照してください。


ドキュメントページコレクション
{
  name: 'doc',
  label: 'Documentation',
  path: 'content/docs',
  format: 'mdx',
  fields: [
    {
      type: 'string',
      name: 'title',
      label: 'Title',
      isTitle: true,
      required: true
    },
    {
      type: 'string',
      name: 'description',
      label: 'Description',
      ui: {
        component: 'textarea'
      }
    },
    {
      type: 'number',
      name: 'order',
      label: 'Order',
      description: 'Sort order in sidebar'
    },
    {
      type: 'rich-text',
      name: 'body',
      label: 'Body',
      isBody: true,
      templates: [
        // MDX components can be defined here
      ]
    }
  ],
  ui: {
    router: ({ document }) => {
      const breadcrumbs = document._sys.breadcrumbs.join('/')
      return `/docs/${breadcrumbs}`
    }
  }
}

テンプレート:templates/collections/doc-page.ts を参照してください。


著者コレクション(参照先)
{
  name: 'author',
  label: 'Authors',
  path: 'content/authors',
  format: 'json',  // Use JSON for structured data
  fields: [
    {
      type: 'string',
      name: 'name',
      label: 'Name',
      isTitle: true,
      required: true
    },
    {
      type: 'string',
      name: 'email',
      label: 'Email',
      ui: {
        validate: (value) => {
          if (!value?.includes('@')) {
            return 'Invalid email address'
          }
        }
      }
    },
    {
      type: 'image',
      name: 'avatar',
      label: 'Avatar'
    },
    {
      type: 'string',
      name: 'bio',
      label: 'Bio',
      ui: {
        component: 'textarea'
      }
    },
    {
      type: 'object',
      name: 'social',
      label: 'Social Links',
      fields: [
        {
          type: 'string',
          name: 'twitter',
          label: 'Twitter'
        },
        {
          type: 'string',
          name: 'github',
          label: 'GitHub'
        }
      ]
    }
  ]
}

テンプレート:templates/collections/author.ts を参照してください。


ランディングページコレクション(複数のテンプレート)
{
  name: 'page',
  label: 'Pages',
  path: 'content/pages',
  format: 'mdx',
  templates: [  // Multiple templates for different page types
    {
      name: 'basic',
      label: 'Basic Page',
      fields: [
        {
          type: 'string',
          name: 'title',
          label: 'Title',
          isTitle: true,
          required: true
        },
        {
          type: 'rich-text',
          name: 'body',
          label: 'Body',
          isBody: true
        }
      ]
    },
    {
      name: 'landing',
      label: 'Landing Page',
      fields: [
        {
          type: 'string',
          name: 'title',
          label: 'Title',
          isTitle: true,
          required: true
        },
        {
          type: 'object',
          name: 'hero',
          label: 'Hero Section',
          fields: [
            {
              type: 'string',
              name: 'headline',
              label: 'Headline'
            },
            {
              type: 'string',
              name: 'subheadline',
              label: 'Subheadline',
              ui: { component: 'textarea' }
            },
            {
              type: 'image',
              name: 'image',
              label: 'Hero Image'
            }
          ]
        },
        {
          type: 'object',
          name: 'cta',
          label: 'Call to Action',
          fields: [
            {
              type: 'string',
              name: 'text',
              label: 'Button Text'
            },
            {
              type: 'string',
              name: 'url',
              label: 'Button URL'
            }
          ]
        }
      ]
    }
  ]
}

テンプレートを使用する場合:ドキュメントの frontmatter に _template フィールドを含める必要があります:

---
_template: landing
title: My Landing Page
---

テンプレート:templates/collections/landing-page.ts を参照してください。


よくあるエラーと解決策

1. ❌ ESbuild のコンパイルエラー

エラーメッセージ:

ERROR: Schema Not Successfully Built
ERROR: Config Not Successfully Executed

原因:

  • カスタムローダー(webpack、babel プラグイン、esbuild ローダー)を使用するコードのインポート
  • フロントエンド専用コード(window、DOM API、React フックを使用)のインポート
  • 特定のモジュールではなく、コンポーネントライブラリ全体をインポート

解決方法:

必要なものだけをインポートしてください:

// ❌ Bad - Imports entire component directory
import { HeroComponent } from '../components/'

// ✅ Good - Import specific file
import { HeroComponent } from '../components/blocks/hero'

予防のヒント:

  • tina/config.ts のインポートは最小限にしてください
  • 型定義とシンプルなユーティリティのみをインポートしてください
  • UI コンポーネントを直接インポートしないでください
  • 必要に応じて、個別の .schema.ts ファイルを作成してください

参考:references/common-errors.md#esbuild を参照してください


2. ❌ モジュール解決:「Could not resolve 'tinacms'」

エラーメッセージ:

Error: Could not resolve "tinacms"

原因:

  • インストールが破損している、または不完全
  • 依存関係間のバージョン不一致
  • ピア依存関係が不足している

解決方法:

# Clear cache and reinstall
rm -rf node_modules package-lock.json
npm install

# Or with pnpm
rm -rf node_modules pnpm-lock.yaml
pnpm install

# Or with yarn
rm -rf node_modules yarn.lock
yarn install

予防策:

  • ロックファイル(package-lock.json、pnpm-lock.yaml、yarn.lock)を使用してください
  • --no-optional や --omit=optional フラグを使用しないでください
  • React 以外のフレームワークでも、react と react-dom がインストールされていることを確認してください

3. ❌ フィールド名の制約

エラーメッセージ:

Field name contains invalid characters

原因:

  • TinaCMS のフィールド名に使用できるのは、英字、数字、アンダースコアのみです
  • ハイフン、スペース、特殊文字は使用できません

解決方法:

// ❌ Bad - Uses hyphens
{
  name: 'hero-image',
  label: 'Hero Image',
  type: 'image'
}

// ❌ Bad - Uses spaces
{
  name: 'hero image',
  label: 'Hero Image',
  type: 'image'
}

// ✅ Good - Uses underscores
{
  name: 'hero_image',
  label: 'Hero Image',
  type: 'image'
}

// ✅ Good - CamelCase also works
{
  name: 'heroImage',
  label: 'Hero Image',
  type: 'image'
}

注:これは Forestry.io からの移行における破壊的変更です


4. ❌ Docker のバインドに関する問題

エラー:

  • Docker コンテナの外部から TinaCMS 管理画面にアクセスできない

原因:

  • TinaCMS はデフォルトで 127.0.0.1(localhost のみ)にバインドされます
  • Docker コンテナが外部接続を受け入れるには、0.0.0.0 へのバインドが必要です

解決方法:

# Ensure framework dev server listens on all interfaces
tinacms dev -c "next dev --hostname 0.0.0.0"
tinacms dev -c "vite --host 0.0.0.0"
tinacms dev -c "astro dev --host 0.0.0.0"

Docker Compose の例:

services:
  app:
    build: .
    ports:
      - "3000:3000"
    command: npm run dev  # Which runs: tinacms dev -c "next dev --hostname 0.0.0.0"

5. ❌ _template キーがないエラー

エラーメッセージ:

GetCollection failed: Unable to fetch
template name was not provided

原因:

  • コレクションが templates 配列(複数のスキーマ)を使用している
  • ドキュメントのフロントマターに _template フィールドがない
  • templates から fields への移行時に、ドキュメントが更新されていない

解決方法:

オプション 1:代わりに fields を使用する(単一テンプレートの場合に推奨)

{
  name: 'post',
  path: 'content/posts',
  fields: [/* ... */]  // No _template needed
}

オプション 2:フロントマターに _template があることを確認する

---
_template: article  # ← Required when using templates array
title: My Post
---

移行スクリプト(templates から fields に変換する場合):

# Remove _template from all files in content/posts/
find content/posts -name "*.md" -exec sed -i '/_template:/d' {} +

6. ❌ パスの不一致に関する問題

エラー:

  • Tina 管理画面にファイルが表示されない
  • 保存時に「File not found」エラーが発生する
  • GraphQL クエリの結果が空になる

原因:

  • コレクション設定の path が実際のファイルディレクトリと一致していない
  • 相対パスと絶対パスの混同
  • 末尾のスラッシュに関する問題

解決方法:

// Files located at: content/posts/hello.md

// ✅ Correct
{
  name: 'post',
  path: 'content/posts',  // Matches file location
  fields: [/* ... */]
}

// ❌ Wrong - Missing 'content/'
{
  name: 'post',
  path: 'posts',  // Files won't be found
  fields: [/* ... */]
}

// ❌ Wrong - Trailing slash
{
  name: 'post',
  path: 'content/posts/',  // May cause issues
  fields: [/* ... */]
}

デバッグ:

  1. npx @tinacms/cli@latest audit を実行してパスを確認します
  2. 指定されたディレクトリにファイルがあることを確認します
  3. ファイル拡張子が format フィールドと一致していることを確認します

7. ❌ ビルドスクリプトの実行順序に関する問題

エラーメッセージ:

ERROR: Cannot find module '../tina/__generated__/client'
ERROR: Property 'queries' does not exist on type '{}'

原因:

  • tinacms build より先にフレームワークのビルドが実行されている
  • TypeScript のコンパイル前に Tina の型が生成されていない
  • CI/CD パイプラインの順序が正しくない

解決方法:

{
  "scripts": {
    "build": "tinacms build && next build"  // ✅ Tina FIRST
    // NOT: "build": "next build && tinacms build"  // ❌ Wrong order
  }
}

CI/CD の例(GitHub Actions):

- name: Build
  run: |
    npx @tinacms/cli@latest build  # Generate types first
    npm run build                   # Then build framework

重要な理由:

  • tinacms build は tina/__generated__/ に TypeScript の型を生成します
  • フレームワークのビルドを正常に行うには、これらの型が必要です
  • 順序を誤ると型エラーが発生します

8. ❌ TinaCMS アセットの読み込み失敗

エラーメッセージ:

Failed to load resource: net::ERR_CONNECTION_REFUSED
http://localhost:4001/...

原因:

  • 開発用の admin/index.html を本番環境にプッシュした(localhost からアセットを読み込む)
  • サイトがサブディレクトリで配信されているのに、basePath が設定されていない

解決方法:

本番環境へのデプロイの場合:

{
  "scripts": {
    "build": "tinacms build && next build"  // ✅ Always build
    // NOT: "build": "tinacms dev"          // ❌ Never dev in production
  }
}

サブディレクトリへのデプロイの場合:

// tina/config.ts
export default defineConfig({
  build: {
    outputFolder: 'admin',
    publicFolder: 'public',
    basePath: 'your-subdirectory'  // ← Set if site not at domain root
  }
})

CI/CD の修正:

# GitHub Actions / Vercel / Netlify
- run: npx @tinacms/cli@latest build  # Always use build, not dev

9. ❌ Reference Field 503 Service Unavailable

エラー:

  • Reference Field のドロップダウンがタイムアウトし、503 エラーが発生します
  • Reference Field の読み込み中に管理インターフェースが応答しなくなります

原因:

  • 参照先のコレクションに項目が多すぎます(数百〜数千件)
  • 現在、Reference Field はページネーションに対応していません

解決策:

オプション 1:コレクションを分割する

// Instead of one huge "authors" collection
// Split by active status or alphabetically

{
  name: 'active_author',
  label: 'Active Authors',
  path: 'content/authors/active',
  fields: [/* ... */]
}

{
  name: 'archived_author',
  label: 'Archived Authors',
  path: 'content/authors/archived',
  fields: [/* ... */]
}

オプション 2:バリデーション付きの文字列フィールドを使用する

// Instead of reference
{
  type: 'string',
  name: 'authorId',
  label: 'Author ID',
  ui: {
    component: 'select',
    options: ['author-1', 'author-2', 'author-3']  // Curated list
  }
}

オプション 3:カスタムフィールドコンポーネント(上級者向け)


デプロイパターン

ニーズに合ったデプロイ方法を選択してください。

オプション 1:TinaCloud(マネージド)- 最も簡単 ⭐

おすすめの用途:すばやくセットアップしたい場合、無料枠を利用したい場合、インフラ管理を任せたい場合

手順:

  1. https://app.tina.io でアカウントを登録します
  2. プロジェクトを作成し、Client ID と Read Only Token を取得します
  3. 環境変数を設定します:
    NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id
    TINA_TOKEN=your_read_only_token
    
  4. バックエンドを初期化します:
    npx @tinacms/cli@latest init backend
    
  5. ホスティングプロバイダー(Vercel、Netlify、Cloudflare Pages)にデプロイします
  6. Tina ダッシュボードでGitHub 連携を設定します

メリット:

  • ✅ バックエンドの設定が不要です
  • ✅ GraphQL API が自動で提供されます
  • ✅ 認証機能が組み込まれています
  • ✅ Git 連携が自動で処理されます
  • ✅ 無料枠が充実しています(月間 10k リクエスト)

デメリット:

  • ❌ 無料枠を超えると有料サービスになります
  • ❌ ベンダーに依存します(ただし、コンテンツは引き続き Git に保存されます)

参考:references/deployment-guide.md#tinacloud を参照してください


オプション 2:Cloudflare Workers でセルフホスト 🔥

おすすめの用途:バックエンドを完全に制御したい場合、Cloudflare エコシステムを利用している場合、エッジにデプロイしたい場合

手順:

  1. 依存関係をインストールします:

    npm install @tinacms/datalayer tinacms-authjs
    
  2. バックエンドを初期化します:

    npx @tinacms/cli@latest init backend
    
  3. Workers エンドポイントを作成します:

    // workers/src/index.ts
    import { TinaNodeBackend, LocalBackendAuthProvider } from '@tinacms/datalayer'
    import { AuthJsBackendAuthProvider, TinaAuthJSOptions } from 'tinacms-authjs'
    import databaseClient from '../../tina/__generated__/databaseClient'
    
    const isLocal = process.env.TINA_PUBLIC_IS_LOCAL === 'true'
    
    export default {
      async fetch(request: Request, env: Env) {
        const handler = TinaNodeBackend({
          authProvider: isLocal
            ? LocalBackendAuthProvider()
            : AuthJsBackendAuthProvider({
                authOptions: TinaAuthJSOptions({
                  databaseClient,
                  secret: env.NEXTAUTH_SECRET,
                }),
              }),
          databaseClient,
        })
    
        return handler(request)
      }
    }
    
  4. tina/config.ts を更新します:

    export default defineConfig({
      contentApiUrlOverride: '/api/tina/gql',  // Your Workers endpoint
      // ... rest of config
    })
    
  5. wrangler.jsonc を設定します:

    {
      "name": "tina-backend",
      "main": "workers/src/index.ts",
      "compatibility_date": "2025-10-24",
      "vars": {
        "TINA_PUBLIC_IS_LOCAL": "false"
      },
      "env": {
        "production": {
          "vars": {
            "NEXTAUTH_SECRET": "your-secret-here"
          }
        }
      }
    }
    
  6. デプロイします:

    npx wrangler deploy
    

メリット:

  • ✅ バックエンドを完全に制御できます
  • ✅ 無料枠が充実しています(1 日あたり 100k リクエスト)
  • ✅ グローバルなエッジネットワークを利用できます(世界中で高速)
  • ✅ ベンダーロックインがありません

デメリット:

  • ❌ セットアップが複雑になります
  • ❌ 認証設定が必要です
  • ❌ Cloudflare Workers の知識が必要です

詳細ガイド:references/self-hosting-cloudflare.md を参照してください

テンプレート:templates/cloudflare-worker-backend/ を参照してください


オプション 3:Vercel Functions でセルフホスト

おすすめの用途:Next.js プロジェクト、Vercel エコシステム

手順:

  1. 依存関係をインストールします:

    npm install @tinacms/datalayer tinacms-authjs
    
  2. API ルートを作成します:

    // api/tina/backend.ts
    import { TinaNodeBackend, LocalBackendAuthProvider } from '@tinacms/datalayer'
    import { AuthJsBackendAuthProvider, TinaAuthJSOptions } from 'tinacms-authjs'
    import databaseClient from '../../../tina/__generated__/databaseClient'
    
    const isLocal = process.env.TINA_PUBLIC_IS_LOCAL === 'true'
    
    const handler = TinaNodeBackend({
      authProvider: isLocal
        ? LocalBackendAuthProvider()
        : AuthJsBackendAuthProvider({
            authOptions: TinaAuthJSOptions({
              databaseClient,
              secret: process.env.NEXTAUTH_SECRET,
            }),
          }),
      databaseClient,
    })
    
    export default handler
    
  3. vercel.json のリライトを作成します:

    {
      "rewrites": [
        {
          "source": "/api/tina/:path*",
          "destination": "/api/tina/backend"
        }
      ]
    }
    
  4. 開発スクリプトを更新します:

    {
      "scripts": {
        "dev": "TINA_PUBLIC_IS_LOCAL=true tinacms dev -c \"next dev --port $PORT\""
      }
    }
    
  5. Vercel ダッシュボードで環境変数を設定します:

    NEXTAUTH_SECRET=your-secret
    TINA_PUBLIC_IS_LOCAL=false
    
  6. デプロイします:

    vercel deploy
    

メリット:

  • ✅ Next.js とネイティブに統合できます
  • ✅ Vercel へのデプロイが簡単です
  • ✅ サーバーレスです(自動的にスケールします)

デメリット:

  • ❌ Vercel 専用です
  • ❌ 関数に制限があります(タイムアウト 10 秒、サイズ 50MB)

参考:references/deployment-guide.md#vercel を参照してください


オプション 4:Netlify Functions でセルフホスト

手順:

  1. 依存関係をインストールします:

    npm install express serverless-http @tinacms/datalayer tinacms-authjs
    
  2. 関数を作成します:

    // netlify/functions/tina.ts
    import express from 'express'
    import ServerlessHttp from 'serverless-http'
    import { TinaNodeBackend, LocalBackendAuthProvider } from '@tinacms/datalayer'
    import { AuthJsBackendAuthProvider, TinaAuthJSOptions } from 'tinacms-authjs'
    import databaseClient from '../../tina/__generated__/databaseClient'
    
    const app = express()
    app.use(express.json())
    
    const tinaBackend = TinaNodeBackend({
      authProvider: AuthJsBackendAuthProvider({
        authOptions: TinaAuthJSOptions({
          databaseClient,
          secret: process.env.NEXTAUTH_SECRET,
        }),
      }),
      databaseClient,
    })
    
    app.post('/api/tina/*', tinaBackend)
    app.get('/api/tina/*', tinaBackend)
    
    export const handler = ServerlessHttp(app)
    
  3. netlify.toml を作成します:

    [functions]
      node_bundler = "esbuild"
    
    [[redirects]]
      from = "/api/tina/*"
      to = "/.netlify/functions/tina"
      status = 200
      force = true
    
  4. デプロイします:

    netlify deploy --prod
    

参考:references/deployment-guide.md#netlify を参照してください


認証の設定

オプション 1:ローカル開発(デフォルト)

用途:ローカル開発、本番環境へのデプロイを行わない場合

// tina/__generated__/databaseClient or backend config
const isLocal = process.env.TINA_PUBLIC_IS_LOCAL === 'true'

authProvider: isLocal ? LocalBackendAuthProvider() : /* ... */

環境変数:

TINA_PUBLIC_IS_LOCAL=true

セキュリティ:認証はありません。ローカルでのみ使用してください!


オプション 2:Auth.js(セルフホストにおすすめ)

用途:OAuth プロバイダー(GitHub、Discord、Google など)を使ってセルフホストする場合

インストール:

npm install next-auth tinacms-authjs

設定:

import { AuthJsBackendAuthProvider, TinaAuthJSOptions } from 'tinacms-authjs'
import DiscordProvider from 'next-auth/providers/discord'

export const AuthOptions = TinaAuthJSOptions({
  databaseClient,
  secret: process.env.NEXTAUTH_SECRET,
  providers: [
    DiscordProvider({
      clientId: process.env.DISCORD_CLIENT_ID,
      clientSecret: process.env.DISCORD_CLIENT_SECRET,
    }),
    // Add GitHub, Google, etc.
  ],
})

const handler = TinaNodeBackend({
  authProvider: AuthJsBackendAuthProvider({
    authOptions: AuthOptions,
  }),
  databaseClient,
})

対応プロバイダー:GitHub、Discord、Google、Twitter、Facebook、Email など

参考:https://next-auth.js.org/providers/


オプション 3:TinaCloud Auth(マネージド)

用途:TinaCloud のホスティングサービスを利用する場合

import { TinaCloudBackendAuthProvider } from '@tinacms/auth'

authProvider: TinaCloudBackendAuthProvider()

設定:

  1. https://app.tina.io でアカウントを登録します
  2. プロジェクトを作成します
  3. ダッシュボードでユーザーを管理します
  4. 認証は自動的に処理されます

オプション 4:カスタム認証プロバイダー

用途:既存の認証システム、独自の要件がある場合

const CustomBackendAuth = () => {
  return {
    isAuthorized: async (req, res) => {
      const token = req.headers.authorization

      // Your validation logic
      const user = await validateToken(token)

      if (user && user.canEdit) {
        return { isAuthorized: true }
      }

      return {
        isAuthorized: false,
        errorMessage: 'Unauthorized',
        errorCode: 401
      }
    },
  }
}

authProvider: CustomBackendAuth()

GraphQL API の使用

TinaCMS は、型安全な GraphQL クライアントを自動的に生成します。

データのクエリ

TinaCloud:

import client from '../tina/__generated__/client'

// Single document
const post = await client.queries.post({
  relativePath: 'hello-world.md'
})

// Multiple documents
const posts = await client.queries.postConnection()

セルフホスト:

import client from '../tina/__generated__/databaseClient'

// Same API as TinaCloud client
const post = await client.queries.post({
  relativePath: 'hello-world.md'
})
useTina Hook によるビジュアル編集

Next.js の例:

import { useTina } from 'tinacms/dist/react'
import { client } from '../../tina/__generated__/client'

export default function BlogPost(props) {
  // Hydrate data for visual editing
  const { data } = useTina({
    query: props.query,
    variables: props.variables,
    data: props.data
  })

  return (
    <article>
      <h1>{data.post.title}</h1>
      <p>{data.post.excerpt}</p>
      <div dangerouslySetInnerHTML={{ __html: data.post.body }} />
    </article>
  )
}

export async function getStaticProps({ params }) {
  const response = await client.queries.post({
    relativePath: `${params.slug}.md`
  })

  return {
    props: {
      data: response.data,
      query: response.query,
      variables: response.variables
    }
  }
}

仕組み:

  • 本番環境では、useTina は初期データを返します(オーバーヘッドはありません)
  • 編集モードでは、useTina は GraphQL に接続し、リアルタイムで更新します
  • 変更はプレビューにすぐに反映されます

その他のリソース

テンプレート
  • templates/nextjs/ - Next.js App Router と Pages Router の設定
  • templates/vite-react/ - Vite + React のセットアップ
  • templates/astro/ - Astro の統合
  • templates/collections/ - 事前構築済みのコレクションスキーマ
  • templates/cloudflare-worker-backend/ - Cloudflare Workers でのセルフホスト
リファレンス
  • references/schema-patterns.md - 高度なスキーマモデリングのパターン
  • references/field-types-reference.md - フィールド型の完全なドキュメント
  • references/deployment-guide.md - すべてのプラットフォーム向けデプロイガイド
  • references/self-hosting-cloudflare.md - Cloudflare Workers の完全ガイド
  • references/common-errors.md - エラーの詳細なトラブルシューティング
  • references/migration-guide.md - Forestry.io からの移行
スクリプト
  • scripts/init-nextjs.sh - Next.js の自動セットアップ
  • scripts/init-vite-react.sh - Vite + React の自動セットアップ
  • scripts/init-astro.sh - Astro の自動セットアップ
  • scripts/check-versions.sh - パッケージのバージョンを確認
公式ドキュメント

トークン効率

推定削減率:65~70%(10,900 トークン削減)

スキルなし(約16,000トークン):

  • 初期調査と探索:3,000トークン
  • フレームワークのセットアップにおける試行錯誤:2,500トークン
  • スキーマモデリングの試行:2,000トークン
  • エラーのトラブルシューティング:4,000トークン
  • デプロイ設定:2,500トークン
  • 認証のセットアップ:2,000トークン

スキルあり(約5,100トークン):

  • スキルの発見:100トークン
  • スキルの読み込み(SKILL.md):3,000トークン
  • テンプレートの選択:500トークン
  • プロジェクト固有の軽微な調整:1,500トークン

防止できるエラー

このスキルにより、9つのよくあるエラーを防止できます(防止率100%)。

  1. ✅ ESbuild のコンパイルエラー(インポートの問題)
  2. ✅ モジュール解決の問題
  3. ✅ フィールド名の制約違反
  4. ✅ Docker のバインドの問題
  5. ✅ _template キーの欠落エラー
  6. ✅ パスの不一致の問題
  7. ✅ ビルドスクリプトの実行順序に関する失敗
  8. ✅ 本番環境でのアセット読み込みエラー
  9. ✅ Reference フィールドの 503 タイムアウト

クイックスタートの例

例1:Next.js + TinaCloud を使ったブログ
# 1. Create Next.js app
npx create-next-app@latest my-blog --typescript --app

# 2. Initialize TinaCMS
cd my-blog
npx @tinacms/cli@latest init

# 3. Set environment variables
echo "NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id" >> .env.local
echo "TINA_TOKEN=your_token" >> .env.local

# 4. Start dev server
npm run dev

# 5. Access admin
open http://localhost:3000/admin/index.html

例2:Astro を使ったドキュメントサイト
# 1. Use official starter
npx create-tina-app@latest my-docs --template tina-astro-starter

# 2. Install dependencies
cd my-docs
npm install

# 3. Start dev server
npm run dev

# 4. Access admin
open http://localhost:4321/admin/index.html

例3:Cloudflare Workers でのセルフホスト
# 1. Initialize project
npm create cloudflare@latest my-app

# 2. Add TinaCMS
npx @tinacms/cli@latest init
npx @tinacms/cli@latest init backend

# 3. Install dependencies
npm install @tinacms/datalayer tinacms-authjs

# 4. Copy Cloudflare Workers backend template
cp -r [path-to-skill]/templates/cloudflare-worker-backend/* workers/

# 5. Configure and deploy
npx wrangler deploy

本番環境での使用例


サポート

問題がありますか? まず references/common-errors.md を確認してください

まだ解決しませんか?


最終更新日:2025-10-24 スキルのバージョン:1.0.0 TinaCMS のバージョン:2.9.0 CLI のバージョン:1.11.0

コメント