关于 tinacms
面向内容型网站开发者的 Git 驱动无头 CMS 指南,介绍 TinaCMS 的可视化编辑与配置。内容涉及 Next.js 集成、内容模式、常见故障排查及部署选项。
主要功能
- 01Git 驱动的内容管理
- 02可视化编辑集成
- 03集合与字段模式配置
- 04常见构建及配置错误排查
- 05TinaCloud 与 Node.js 部署说明
适用场景
- 01为内容型网站配置内容管理
- 02在 Next.js 页面启用可视化编辑
- 03排查模式构建或路径配置问题
- 04选择托管或 Node.js 自托管部署
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jezweb/ claude-skills --skill tinacms安装后在 Claude Code 中输入/tinacms确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.md.claude-plugin/plugin.jsonassets/links-to-official-docs.mdreferences/common-errors.mdscripts/check-versions.shtemplates/astro/.env.examplepackage.jsontina-config.tstemplates/cloudflare-worker-backend/src/index.tstemplates/collections/author.tsblog-post.tsdoc-page.tslanding-page.tstemplates/nextjs/.env.examplepackage.jsontina-config-app-router.tstina-config-pages-router.tstemplates/vite-react/.env.examplepackage.jsontina-config.tsvite.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 更新前更新,从而导致不兼容。
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: [/* ... */]
}
调试:
- 运行
npx @tinacms/cli@latest audit检查路径 - 确认文件存在于指定目录中
- 检查文件扩展名是否与
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:自定义字段组件(高级)
- 在自定义组件中实现分页
- 参阅 TinaCMS 文档:https://tina.io/docs/extending-tina/custom-field-components/
10. ❌ 媒体管理器上传超时(虚假上传)
错误消息:
Upload failed
Error uploading image
原因:
- 媒体管理器显示错误,但图片已在后台成功上传
- 界面超时并不反映实际上传状态
- 删除时也会出现类似问题(显示错误,但删除成功)
解决方案:
如果上传时显示错误:
- 等待 5-10 秒
- 关闭并重新打开媒体管理器
- 重试前检查图片是否已上传
- 避免重复尝试上传
状态:已知问题(优先级高) 来源:GitHub Issue #6325
部署选项
TinaCloud(托管)- 推荐
设置:
- 在 https://app.tina.io 注册
- 获取 Client ID 和只读令牌
- 设置环境变量:
NEXT_PUBLIC_TINA_CLIENT_ID、TINA_TOKEN - 部署到 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 仓库中的官方自托管示例已被团队承认为“相当过时”。请始终对照最新文档,而不要仅依赖示例仓库。
仅适用于 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 运行时(无法使用边缘计算)