mcpField
T
tinacms

tinacms

github.com/jezweb开发1.1k304 次安装3 周前更新
代码仓库

关于 tinacms

面向内容型网站开发者的 Git 驱动无头 CMS 指南,介绍 TinaCMS 的可视化编辑与配置。内容涉及 Next.js 集成、内容模式、常见故障排查及部署选项。

主要功能

  1. 01Git 驱动的内容管理
  2. 02可视化编辑集成
  3. 03集合与字段模式配置
  4. 04常见构建及配置错误排查
  5. 05TinaCloud 与 Node.js 部署说明

适用场景

  1. 01为内容型网站配置内容管理
  2. 02在 Next.js 页面启用可视化编辑
  3. 03排查模式构建或路径配置问题
  4. 04选择托管或 Node.js 自托管部署

安装

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

$npx skills add https://github.com/jezweb/claude-skills --skill tinacms

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

包含的文件

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

README.md
.claude-plugin/
plugin.json
assets/
links-to-official-docs.md
references/
common-errors.md
scripts/
check-versions.sh
templates/astro/
.env.example
package.json
tina-config.ts
templates/cloudflare-worker-backend/src/
index.ts
templates/collections/
author.ts
blog-post.ts
doc-page.ts
landing-page.ts
templates/nextjs/
.env.example
package.json
tina-config-app-router.ts
tina-config-pages-router.ts
templates/vite-react/
.env.example
package.json
tina-config.ts
vite.config.ts

详细介绍

TinaCMS

基于 Git 的无头 CMS,为内容丰富的网站提供可视化编辑功能。

最后更新:2026-01-21 版本:[email protected],@tinacms/[email protected]


快速开始

包管理器建议:

  • 推荐:pnpm(TinaCMS >2.7.3 需要)
  • 替代方案:npm 或 yarn(较新版本中可能存在模块解析问题)
# Install pnpm (if needed)
npm install -g pnpm

# Initialize TinaCMS
npx @tinacms/cli@latest init

# Install dependencies with pnpm
pnpm install

# Update package.json scripts
{
  "dev": "tinacms dev -c \"next dev\"",
  "build": "tinacms build && next build"
}

# Set environment variables
NEXT_PUBLIC_TINA_CLIENT_ID=your_client_id
TINA_TOKEN=your_read_only_token

# Start dev server
pnpm run dev

# Access admin interface
http://localhost:3000/admin/index.html

锁定版本(推荐):

固定具体版本,以防 CLI/UI 自动更新导致重大变更:

{
  "dependencies": {
    "tinacms": "3.3.1",  // NOT "^3.3.1"
    "@tinacms/cli": "2.1.1"
  }
}

原因:TinaCMS UI 资源通过 CDN 提供,可能会在本地 CLI 更新前更新,从而导致不兼容。

来源:GitHub Issue #5838


Next.js 集成

useTina Hook(启用可视化编辑):

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

export default function BlogPost(props) {
  const { data } = useTina({
    query: props.query,
    variables: props.variables,
    data: props.data
  })

  return <article><h1>{data.post.title}</h1></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
    }
  }
}

App Router:管理路由位于 app/admin/[[...index]]/page.tsx Pages Router:管理路由位于 pages/admin/[[...index]].tsx


架构配置

tina/config.ts 结构:

import { defineConfig } from 'tinacms'

export default defineConfig({
  branch: process.env.GITHUB_BRANCH || 'main',
  clientId: process.env.NEXT_PUBLIC_TINA_CLIENT_ID,
  token: process.env.TINA_TOKEN,
  build: {
    outputFolder: 'admin',
    publicFolder: 'public',
  },
  schema: {
    collections: [/* ... */],
  },
})

集合示例(博客文章):

{
  name: 'post',           // Alphanumeric + underscores only
  label: 'Blog Posts',
  path: 'content/posts',  // No trailing slash
  format: 'mdx',
  fields: [
    {
      type: 'string',
      name: 'title',
      label: 'Title',
      isTitle: true,
      required: true
    },
    {
      type: 'rich-text',
      name: 'body',
      label: 'Body',
      isBody: true
    }
  ]
}

字段类型:string、rich-text、number、datetime、boolean、image、reference、object

引用字段说明:当引用字段指向多个具有相同字段名的集合类型时,请确保这些字段的类型一致。类型冲突(例如,bio: string 与 bio: rich-text)会导致 GraphQL 架构错误。

// Example: Reference field referencing multiple collections
{
  type: 'reference',
  name: 'contributor',
  collections: ['author', 'editor']  // Ensure shared fields have same type
}

来源:社区提供


常见错误与解决方案

1. ❌ ESbuild 编译错误

错误消息:

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

原因:

  • 导入使用自定义加载器的代码(webpack、babel 插件、esbuild 加载器)
  • 导入仅供前端使用的代码(使用 window、DOM API、React Hook)
  • 导入整个组件库,而非特定模块

解决方案:

仅导入所需内容:

// ❌ 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"

原因:

  • 安装损坏或不完整
  • 依赖项版本不匹配
  • 缺少 peer 依赖

解决方案:

# 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-dom(即使使用非 React 框架也一样)

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(仅限本地主机)
  • 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 数组(多个架构)
  • 文档的 frontmatter 中缺少 _template 字段
  • 从 templates 迁移到 fields,但文档未更新

解决方案:

选项 1:改用 fields(单个模板时推荐)

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

选项 2:确保 frontmatter 中存在 _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
  }
}

子目录部署:

⚠️ 子路径部署限制:TinaCMS 部署在子路径时(例如,example.com/cms/admin 而非 example.com/admin),存在已知的资源加载问题。即使配置了 basePath,仍有此限制。

解决方法:将 TinaCMS 管理后台部署在根路径(/admin),或使用反向代理重写规则。

来源:社区提供

// tina/config.ts
export default defineConfig({
  build: {
    outputFolder: 'admin',
    publicFolder: 'public',
    basePath: 'your-subdirectory'  // ← May have asset loading issues on sub-paths
  }
})

CI/CD 修复:

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

9. ❌ 引用字段返回 503 服务不可用

错误:

  • 引用字段下拉菜单超时并返回 503 错误
  • 加载引用字段时,管理界面无响应

原因:

  • 被引用的集合中项目过多(数百或数千个)
  • 目前引用字段不支持分页

解决方案:

选项 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:自定义字段组件(高级)


10. ❌ 媒体管理器上传超时(虚假上传)

错误消息:

Upload failed
Error uploading image

原因:

  • 媒体管理器显示错误,但图片已在后台成功上传
  • 界面超时并不反映实际上传状态
  • 删除时也会出现类似问题(显示错误,但删除成功)

解决方案:

如果上传时显示错误:

  1. 等待 5-10 秒
  2. 关闭并重新打开媒体管理器
  3. 重试前检查图片是否已上传
  4. 避免重复尝试上传

状态:已知问题(优先级高) 来源:GitHub Issue #6325


部署选项

TinaCloud(托管)- 推荐

设置:

  1. 在 https://app.tina.io 注册
  2. 获取 Client ID 和只读令牌
  3. 设置环境变量:NEXT_PUBLIC_TINA_CLIENT_ID、TINA_TOKEN
  4. 部署到 Vercel/Netlify/Cloudflare Pages

优点:无需配置,提供免费套餐(每月 10k 次请求)


在 Node.js 上自托管

⚠️ Edge Runtime 限制:由于 @tinacms/datalayer 和 @tinacms/graphql 中依赖 Node.js,自托管 TinaCMS 无法在 Edge Runtime 环境(Cloudflare Workers、Vercel Edge Functions)中运行。对于边缘部署,请使用 TinaCloud(托管服务)。

来源:GitHub Issue #4363(标记为“wontfix”)

⚠️ 自托管示例可能已过时:TinaCMS 仓库中的官方自托管示例已被团队承认为“相当过时”。请始终对照最新文档,而不要仅依赖示例仓库。

来源:GitHub Issue #6365

仅适用于 Node.js 环境(不适用于 Edge Runtime):

pnpm install @tinacms/datalayer tinacms-authjs
npx @tinacms/cli@latest init backend

示例(Node.js 服务,不适用于 Workers):

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'

// This ONLY works in Node.js runtime, NOT edge runtime
const handler = TinaNodeBackend({
  authProvider: isLocal
    ? LocalBackendAuthProvider()
    : AuthJsBackendAuthProvider({
        authOptions: TinaAuthJSOptions({
          databaseClient,
          secret: process.env.NEXTAUTH_SECRET,
        }),
      }),
  databaseClient,
})

优点:完全掌控,可自托管 缺点:需要 Node.js 运行时(无法使用边缘计算)

评论

支持 Markdown