十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

TinaCMS × Astro 集成完全指南:@tinacms/astro 视觉编辑、富文本渲染与静态站点编辑实战

TinaCMS × Astro 集成完全指南:@tinacms/astro 视觉编辑、富文本渲染与静态站点编辑实战 TinaCMS × Astro 集成完全指南tinacms/astro 视觉编辑、富文本渲染与静态站点编辑实战【免费下载链接】tinacmsTinaCMS is the leading open-source headless CMS that supports Markdown and Visual Editing. Your content is stored in your own GitHub repo ❤️项目地址: https://gitcode.com/GitHub_Trending/ti/tinacmstinacms/astro是 TinaCMS 为 Astro 提供的一站式集成包它把 TinaCMS 的视觉编辑能力点击聚焦、表单面板、iframe 内联预览带进纯 Astro 应用同时提供一个与 ReactTinaMarkdownAPI 完全对齐的富文本渲染器——页面树中不引入任何 React。读完本文你将掌握如何安装并接线该集成、如何用requestWithMetadata加载数据、如何注册可编辑区域island、如何自定义 MDX 组件与默认标签渲染以及如何在output: static下依然实现视觉编辑。新项目建议先跟随逐步指南 packages/tinacms/astro/GETTING_STARTED.md 完成安装、集成接线、数据加载器、island 注册与排障本文其余部分是完整的 API 参考。参考实现位于 examples/astro/visual-editing与 React kitchen-sink 使用相同的内容 schema但全部以纯 Astro 渲染。一、包能做什么纯 Astro 富文本渲染器镜像 ReactTinaMarkdown的 API——同样的contentprop、同样的componentsmap 结构但输出的是纯 HTML页面树中没有 React。桥接层直接复用框架无关的tinacms/bridge以tinacms/astro/bridge子路径重导出只需安装一个包见 package.json 中的dependencies仅依赖tinacms/bridge。二、安装与环境要求pnpm add tinacms/astro tinacms pnpm add -D tinacms/cli同时需要安装 Astro SSR adapter——island 刷新端点/tina-island/[name]是按需on-demand渲染的pnpm add astrojs/node # 或 astrojs/vercel / netlify / cloudflare要求 Astro 5 / 6 / 7见package.json的peerDependencies: astro: ^5.0.0 || ^6.0.0 || ^7.0.0、Node 18、TinaCMS 3。output: server是最简单的选择output: static也可以前提是可编辑区域包在TinaIsland中且 adapter 能提供那一条 on-demand 路由详见下文“静态站点编辑”。集合使用 MDX body 时额外安装astrojs/mdx自托管不使用 TinaCloud时额外安装tinacms/datalayer。三、一次性接线集成在astro.config.mjs中添加一次集成它会自动接入请求级中间件并把打包好的桥接层以静态资源形式输出到/admin/bridge.js——其余一切只在编辑模式请求下自动注入// astro.config.mjs import { defineConfig } from astro/config; import tina from tinacms/astro/integration; import node from astrojs/node; import mdx from astrojs/mdx; export default defineConfig({ output: server, adapter: node({ mode: standalone }), integrations: [mdx(), tina()], });从 integration.ts 的源码可以看到tina()集成的内部行为astro:config:setup阶段调用addMiddleware注册tinacms/astro/middleware默认order: pre可通过选项middlewareOrder: pre | post调整同时注入三个 dev-only Vite 插件bridgeDevPlugin()dev 下直接从已安装的 bridge 包内存响应/admin/bridge.js不在源码树写文件、devContentInvalidationPlugin()Astro 6 下监听 Tina 集合内容目录的文件增删发出astro:content-changed信号使getStaticPaths重新执行解决 dev 中新建文档 404 的问题、cloudflareImportMetaUrlPlugin()Cloudflare Workers 下为服务端 bundle 注入import.meta.url占位符astro:build:done阶段把 bridge 复制到构建输出树的admin/bridge.jsemitBridgeAsset与 admin SPA 并列随每次部署发布不触碰源码目录。集成选项cloudflareWorkers?: boolean可强制开关 workerd 的import.meta.url兼容处理省略时仅在检测到astrojs/cloudflareadapter 时自动启用。四、数据加载requestWithMetadata包装所有查询与任何 TinaCMS 项目一样调用生成的 client再用requestWithMetadata()包装结果--- import TinaMarkdown from tinacms/astro/TinaMarkdown.astro; import { requestWithMetadata, tinaField } from tinacms/astro; import client from ../tina/__generated__/client; const post await requestWithMetadata( client.queries.post({ relativePath: hello.md }), ); --- article h1>// src/lib/data.ts import { requestWithMetadata } from tinacms/astro; import client from ../../tina/__generated__/client; export const getPage (slug: string) requestWithMetadata(client.queries.page({ relativePath: ${slug}.md })); export const getPost (slug: string) requestWithMetadata(client.queries.post({ relativePath: ${slug}.md })); // ...每个集合一个编辑模式的注入机制中间件middleware.ts在onRequest中预渲染路由直接短路context.isPrerendered→tinaEdit false否则调用isEditMode(request)判定编辑模式并写入Astro.locals.tinaEdit用requestStore/formsStore的 AsyncLocalStorage 作用域包裹next()收集页面渲染期间requestWithMetadata注册的表单编辑模式下缓冲整个 HTML 响应在/head之前拼接表单 payload div 与script typemodule动态import/admin/bridge.js并调用init()监听astro:page-load触发refreshForms同时写入__tina_edit1cookieSameSiteStrict; Max-Age3600。生产访问者得到的是与不含 Tina 的 Astro 应用逐字节相同的 HTML——没有data-tina-formdiv、没有 script 标签、没有 bundle 预载。例外使用了TinaIsland的页面会携带一行内联 bootstrap使静态构建的页面也能编辑。跨域 admin 部署Codespaces、独立域名自托管时在环境变量中设置PUBLIC_TINA_ADMIN_ORIGIN逗号分隔允许多个中间件会把它内联嵌入让 bridge 校验入站postMessage事件。五、子路径导出总览子路径提供内容tinacms/astrorequestWithMetadata、tinaField、QueryResult及类型tinacms/astro/TinaMarkdown.astroTinaMarkdown content components /— 富文本渲染器。必须从此子路径导入这样 Astro 的检查器才能看到真正的.astro组件裸包默认导出通过 types 条件解析为占位符tinacms/astro/integrationtina()集成——自动接线中间件并输出静态/admin/bridge.js使requestWithMetadata()无需手动传递Astro.request或编写 wiring 组件tinacms/astro/TinaIsland.astroTinaIsland name wrapper params [primary] /— 可编辑区域的标记包装在页面主区域上传递primary编辑器会直接打开该表单而不是“Referenced Files”列表tinacms/astro/typesTinaRichTextContent、CustomComponentsMap、TinaRichTextNode、MdxElement、TextElementtinacms/astro/sanitize针对 CMS 提供 URL 的sanitizeHref/sanitizeImageSrctinacms/astro/bridgeinit、refreshForms及tinacms/bridge的其余内容tinacms/astro/tina-fieldtinaField()辅助函数tinacms/astro/is-edit-modeisEditMode(request)— 服务端 admin iframe 检测tinacms/astro/middleware集成自动接线的中间件——这里导出便于需要时手动组合tinacms/astro/vitetinaAdminDevRedirect()— dev 专用 Vite 插件把/admin和/admin/重定向到/admin/index.html使astro dev下 admin SPA 可从裸 URL 访问tinacms/astro/experimentalexperimental_createIslandRoute()— 基于 Astro 不稳定的experimental_AstroContainer构建的 opt-in 辅助函数全部导出映射见 package.json 的 exports 字段。六、富文本渲染器自定义 MDX 组件按 Tina 在编辑器中使用的名称注册 Astro 组件--- import TinaMarkdown from tinacms/astro/TinaMarkdown.astro; import type { CustomComponentsMap } from tinacms/astro/types; import BlockQuote from ../components/BlockQuote.astro; import NewsletterSignup from ../components/NewsletterSignup.astro; const components: CustomComponentsMap { BlockQuote, NewsletterSignup, }; --- TinaMarkdown content{post.data.post._body} components{components} /渲染器按node.name分发mdxJsxFlowElement和mdxJsxTextElement节点对应 types.ts 中的MdxElement类型。未知名称会渲染一个可见的占位符方便你在开发期发现漏注册。从 TinaMarkdown.astro 的实现可见渲染器把content归一化为节点数组根节点取children逐个交给Node.astro递归渲染嵌套富文本通过同一组件自递归完成。CustomComponentsMap还支持通过泛型参数精确约束自定义模板的 props// 模板 cta 含 title: string 字段 const components: CustomComponentsMap{ cta: { title: string } } { cta: Cta, // ← Cta 的 Props 必须可赋值自 { title: string } };默认标签覆盖Default-tag overrides同一个componentsmap 可以覆盖节点默认渲染的 HTML 标签便于在不 fork 渲染器的前提下做样式定制const components: CustomComponentsMap { p: Paragraph, // Tailwind 样式的 p h1: Heading1, blockquote: BlockquoteTag, code_block: CodeBlock, // 例如 shiki 高亮 a: Anchor, img: Img, };支持的覆盖键p、h1–h6、ul、ol、li、blockquote、lic、a、img、code_block、hr、break。命名 prop 型覆盖有精确的类型a收到{ url }、img收到{ url, alt?, caption? }、code_block收到{ value, lang? }、html/html_inline收到{ value }、table收到{ node }详见 types.ts。七、视觉编辑标记data-tina-field渲染器本身不输出data-tina-field属性——在调用处包装按任何你觉得合适的粒度添加--- import TinaMarkdown from tinacms/astro/TinaMarkdown.astro; import { tinaField } from tinacms/astro/tina-field; --- div>// src/lib/islands.ts import type { IslandRegistry } from tinacms/astro/experimental; import PostBody from ../components/PostBody.astro; import { getPost } from ./data; const ARTICLE_WRAPPER { tag: article, className: max-w-3xl mx-auto }; export const islands: IslandRegistry { post: { fetch: (_request, params) getPost(params.get(slug) ?? ), component: PostBody, wrapper: ARTICLE_WRAPPER, propsFromData: (data) ({ data: (data as { data?: { post?: unknown } }).data?.post, }), }, };6. 动态 island 端点——一个文件完全通用// src/pages/tina-island/[name].ts import type { APIRoute } from astro; import { experimental_createIslandRoute } from tinacms/astro/experimental; import { islands } from ../../lib/islands; export const prerender false; export const ALL: APIRoute experimental_createIslandRoute(islands);这是 bridge 唯一需要的文件。此后新增一个可编辑区域就是在注册表里加一个条目。注意experimental_createIslandRoute构建在 Astro 的experimental_AstroContainer之上Astro 自身标记为 unstable该辅助函数继承同样的警告见 experimental.tsAPI 可能在 minor/patch 版本中变化。7. 在页面中使用可编辑区域--- // src/pages/posts/[...urlSegments].astro import TinaIsland from tinacms/astro/TinaIsland.astro; import PostBody from ../../components/PostBody.astro; import { getPost } from ../../lib/data; import { islands } from ../../lib/islands; const slug (Astro.params.urlSegments ?? ).toString(); const post await getPost(slug); if (!post.data?.post) { return new Response(Not Found, { status: 404 }); } const data post.data.post; --- TinaIsland namepost wrapper{islands.post.wrapper} params{{ slug }} primary PostBody data{data} / /TinaIslandprimaryprop 把该区域标记为页面主可编辑区域编辑器加载时直接打开这个表单而不是在页面同时注册了例如global-config 表单时落到“Referenced Files”列表。在output: server页面上它是可选的页面自身的第一次requestWithMetadata()调用会被自动当作 primary在output: static页面上它告诉 bridge 哪个 island 是“页面本体”因此必须设置。每页最多标记一个。从 TinaIsland.astro 的实现可见它把params编码为查询串拼出 marker 路径/tina-island/${name}?…渲染为data-tina-island/data-tina-island-primary属性的包装标签wrapper.tag/wrapper.className并通过define:vars内联 admin origin 供 bootstrap 使用。在PostBody.astro内部用data-tina-field{tinaField(data, fieldName)}标记任何你想要点击聚焦的元素富文本 body 用TinaMarkdown渲染--- import TinaMarkdown from tinacms/astro/TinaMarkdown.astro; import { tinaField } from tinacms/astro/tina-field; import type { PostQuery } from ../../tina/__generated__/types; interface Props { data: NonNullablePostQuery[post]; } const { data } Astro.props; --- h1>// package.json { scripts: { dev: tinacms dev -c \astro dev\, build: tinacms build astro build, build:local: tinacms build --local --skip-cloud-checks -c \astro build\ } }build:local适合 CI / 离线开发——它在本地索引内容不联系 TinaCloud。运行后pnpm dev # 站点: http://localhost:4321/ # Admin: http://localhost:4321/admin/十三、TypeScript 小贴士用生成的查询类型PostQuery[post]、PageQuery[page]等标注路由数据去掉类型断言用if (!result.data?.X) return new Response(Not Found, { status: 404 });做守卫——守卫后的data非空且完整类型化tina/collections/、tina/schemas/、tina/fields/中的 admin schema 使用字面量类型的 Field 联合严格的astro check会难以处理。在tsconfig.json中排除这些目录让astro check聚焦 UI 代码——Tina 的 CLI 会单独校验 schema{ exclude: [ node_modules, dist, tina/__generated__, tina/collections, tina/schemas, tina/fields, tina/config.tsx, tina/database.ts ] }十四、常见问题排查症状原因修复iframe 显示页面但 admin 侧边栏为空iframe 内链接点击丢失了Sec-Fetch-Dest: iframe__tina_editcookie 会自动处理。仍异常时检查 DevTools → Application → Cookies确认 iframe 源上有__tina_edit1“Tina Dev server is already in use. Datalayer server is busy on port 9000”另一个pnpm dev在运行结束它或设置不同的 datalayer 端口admin URL 更新了但新页面的表单不出现bridge 没有在新页面上加载在 DevTools 检查新页面的head——应包含div>pnpm test在给tinacms/mdx新增节点类型后拉取新 fixture 集pnpm sync-fixtures相关测试与 fixture 位于 packages/tinacms/astro/src/tests含.astro、.snap与 JSON 断言文件sync-fixtures脚本见 packages/tinacms/astro/scripts/sync-fixtures.mjs。十六、LicenseApache 2.0。完整参考子路径导出、自定义 MDX 模式与默认标签覆盖见 packages/tinacms/astro/README.md底层 vanilla-JS bridge可用于 Hugo、纯 HTML 等任何非 React 场景见 packages/tinacms/bridge完整示例含列表页、layout/header/footer islands 与 5 个自定义 MDX 组件见 examples/astro/visual-editing。【免费下载链接】tinacmsTinaCMS is the leading open-source headless CMS that supports Markdown and Visual Editing. Your content is stored in your own GitHub repo ❤️项目地址: https://gitcode.com/GitHub_Trending/ti/tinacms创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表