👆本指南假设您正在使用 Next.js app router.
在您网站的目录中运行:
npx @tinacms/cli@latest init
这将询问您一些设置问题。当提示输入公共资产目录时,输入:public。
tina init
应该已经更新了您的 package.json
脚本。
"scripts": {"dev": "tinacms dev -c \"next dev\"","build": "tinacms build && next build","start": "tinacms build && next start"}
如果这些没有被CLI设置,您需要手动应用。
您可以通过以下命令启动TinaCMS:
pnpm dev
我们推荐使用pnpm。
在TinaCMS运行后,导航到 http://localhost:3000/admin/index.html
。
❓ 提示:如果运行此命令时出现错误,请查看常见错误页面。
此时,您应该能够看到Tina管理界面,选择一个帖子,保存更改,并看到更改持久化到您的本地markdown文件中。
运行 tina init
命令后,创建了一些文件以帮助您快速入门。其中之一是 tina/config.ts
文件。这是一个必需的配置文件,定义了所有的tina模式。
它看起来如下:
import { defineConfig } from 'tinacms';// 您的托管提供商可能将此作为环境变量公开const branch =process.env.GITHUB_BRANCH ||process.env.VERCEL_GIT_COMMIT_REF ||process.env.HEAD ||'main';export default defineConfig({branch,// 从 tina.io 获取clientId: process.env.NEXT_PUBLIC_TINA_CLIENT_ID,// 从 tina.io 获取token: process.env.TINA_TOKEN,build: {outputFolder: 'admin',publicFolder: 'public',},media: {tina: {mediaRoot: '',publicFolder: 'public',},},schema: {collections: [{name: 'post',label: 'Posts',path: 'content/posts',fields: [{type: 'string',name: 'title',label: 'Title',isTitle: true,required: true,},{type: 'rich-text',name: 'body',label: 'Body',isBody: true,},],},],},});
有关配置的更详细概述,请参阅TinaCMS内容建模
💡 如果您按照本指南使用tina init
命令,您可能已经注意到创建了一个content
和一个pages
文件夹:
Adding file at content/posts/hello-world.md... ✅Adding file at pages/demo/blog/[filename].tsx... ✅
这些可以用作快速参考,但可以安全删除。
💡 如tina/config.ts
文件中定义的,我们有一个名为post
的集合,它将被TinaCMS拾取并映射到您在TinaCMS管理页面中看到的内容。
/admin/index.html
现在,让我们回去检查创建了什么。您将看到一个 /content
文件夹,其中保存了您的新帖子作为 .md
文件。此路径在 tina/config.ts
文件的post集合中定义!
content└── posts└── hello-world.md
让我们从创建一个 /posts
文件夹开始。这里的页面将列出我们所有的帖子。
文件: app/posts/page.tsx
import PostList from './client-page';import { client } from '../../tina/__generated__/client';export default async function Page() {const { data } = await client.queries.postConnection();return (<><h1>Posts</h1><div>{data.postConnection.edges.map((post) => (<div key={post.node.id}><Link href={`/posts/${post.node._sys.filename}`}>{post.node._sys.filename}</Link></div>))}</div></>);}
您可能已经注意到这是一个服务器渲染的页面。根据此页面的生成方式,Next将会:
这取决于您希望如何渲染此页面。
为了使其与TinaCMS可视化编辑器一起工作,我们将其分为两个组件。一个将在构建时构建页面。另一个将是一个可以与TinaCMS交互并工作的客户端渲染页面。
文件: app/posts/[...filename].tsx
import Post from './client-page';import client from '../../../tina/__generated__/client';export async function generateStaticParams() {const pages = await client.queries.postConnection();const paths = pages.data?.postConnection?.edges?.map((edge) => ({filename: edge?.node?._sys.breadcrumbs,}));return paths || [];}export default async function PostPage({params,}: {params: { filename: string[] };}) {const data = await client.queries.post({relativePath: `${params.filename}.md`,});return <Post {...data}></Post>;}
在这里,我们使用 generateStaticParams 将这些页面构建为SSG。您可以根据需要随意更改。
现在,为了使可视化编辑器工作,我们将创建一个新的“客户端页面”:
文件: app/posts/[...filename]/client-page.tsx
'use client';import { useTina } from 'tinacms/dist/react';import { PostQuery } from '../../../tina/__generated__/types';interface ClientPageProps {query: string;variables: {relativePath: string;};data: PostQuery;}export default function Post(props: ClientPageProps) {// 数据在生产模式下传递,并在编辑模式下更新为侧边栏数据const { data } = useTina({query: props.query,variables: props.variables,data: props.data,});return (<code><prestyle={{backgroundColor: 'lightgray',}}>{JSON.stringify(data.post, null, 2)}</pre></code>);}
在使用App Router的Next.js项目中使用TinaCMS时,您可能会遇到Vercel过于积极地缓存内容,导致某些更新未正确反映的情况。
根本原因是 Vercel数据缓存 正在缓存来自TinaCloud内容API的响应。这可以通过查询GraphQL API并查找更新的内容,或检查Vercel中的缓存使用情况来确认。
有两种方法可以修改您的网站以最佳方式使用Vercel数据缓存:
const response = await client.queries.page({ relativePath: 'pages/home.mdx'}, { fetchOptions: { next: { revalidate: 60 } })})
fetch
请求。有关Next.js如何扩展 fetch
的更多信息,请参见:https://nextjs.org/docs/app/api-reference/functions/fetch在使用App Router的Next.js项目中使用TinaCMS时,您可能会遇到新创建的内容项未立即出现在相应页面上的情况。这种行为通常是由于Next.js和浏览器采用的积极缓存机制造成的。
为了确保在本地开发期间看到最新的内容,您可以在浏览器的开发者工具中禁用浏览器缓存:
有关Next.js中缓存的更详细信息,请参阅Next.js官方文档:
Next.js缓存文档