基于 Next.js 与 Fumadocs 构建现代文档站点:next-forge Geistdocs 文档模板全解析
【免费下载链接】next-forgeProduction-grade Turborepo template for Next.js apps.项目地址: https://gitcode.com/GitHub_Trending/ne/next-forge
Geistdocs是 next-forge 仓库中内置的一套现代文档站点模板:它以 Next.js 16 + Fumadocs 为底座,开箱即用地集成了 MDX 内容引擎、AI 问答助手、全文模糊搜索、GitHub 反馈集成、RSS、暗色模式与 LLM 友好输出能力,被用作本仓库docs应用的完整实现。阅读本文后,你将理解该模板的整体架构与关键源码路径,掌握从内容配置(frontmatter schema、MDX 集合)、站点配置(geistdocs.tsx)到 AI 聊天、搜索、RSS/llms.txt 等核心模块的工作原理,并能够据此快速搭建或定制自己的文档站点。
模板定位:为 Vercel 风格文档站点而生的开箱即用方案
docs/README.md对 Geistdocs 的定位描述得很直接:A modern documentation template built with Next.js and Fumadocs,目标是"快速且一致地搭建文档站点",并内置 AI 聊天、GitHub Discussions 集成和一套漂亮的 UI。其特性清单可归纳为九大能力:
| 能力 | 说明 |
|---|---|
| MDX 驱动的文档 | 用 MDX 写作,支持完整组件能力 |
| AI 聊天 | 内置理解本站文档的 AI 助手 |
| GitHub Discussions 集成 | 用户可直接向 GitHub 提交反馈 |
| 现代 UI | 基于 Radix UI 的漂亮、可访问组件 |
| 高级搜索 | 覆盖全部文档的快速模糊搜索 |
| 暗色模式 | 内置主题切换 |
| 响应式 | 移动优先设计 |
| 高性能 | 基于 Next.js App Router |
| RSS | 内置文档 RSS 订阅源 |
在 next-forge 中,这个模板被实例化为仓库根目录下的docs/应用:既承载了 next-forge 自己的全部文档内容(docs/content/docs下约 90 个 MDX 文件,涵盖 setup、packages、migrations、deployment 等分类),又为希望自建文档站的开发者提供了完整的参考实现。注意docs/package.json中的"name": "template"与描述"Template for Geistdocs projects.",从源码结构看,该目录正是以"可复制的模板"形态存在的。
技术栈与目录结构
从docs/package.json可以清晰还原模板的技术选型:
- 框架层:
next16.0.10、react19.2.3、react-dom19.2.3; - 文档引擎:
fumadocs-core16.2.2、fumadocs-mdx14.0.4、fumadocs-ui16.2.2; - AI 能力:
ai5.x、@ai-sdk/react2.x; - 搜索:
@orama/tokenizers(提供日文/中文分词)、fumadocs-core/search; - 内容增强:
shiki(代码高亮)、mermaid(图表)、@streamdown/code、@streamdown/cjk、streamdown; - UI 与交互:
radix-ui、sonner、cmdk、vaul、motion、lucide-react、next-themes、tailwindcss4; - 数据与校验:
dexie/dexie-react-hooks(本地持久化,用于聊天记录)、zod4(schema 校验)、jotai(轻量状态); - 其他:
feed(RSS 生成)、@vercel/analytics、@vercel/speed-insights。
目录结构围绕"内容"与"代码"分离设计:
docs/ ├── app/ # Next.js App Router 路由 │ ├── [lang]/ # 国际化路由(默认 en) │ │ ├── (home)/ # 首页(hero、apps 展示、features) │ │ ├── docs/[[...slug]]/ # 文档渲染页(动态 slug) │ │ ├── llms.txt/ # LLM 友好的全文输出 │ │ ├── rss.xml/ # RSS 订阅源 │ │ ├── sitemap.md/ # 语义化站点地图 │ │ └── og/[...slug]/ # 动态 OG 图片 │ ├── api/ │ │ ├── chat/ # AI 聊天流式接口 │ │ └── search/ # 全文搜索接口 │ └── actions/feedback/ # 反馈提交 Server Action ├── components/ │ ├── geistdocs/ # 模板核心组件(navbar、sidebar、chat、search…) │ ├── ai-elements/ # AI 对话 UI 元素 │ └── ui/ # Radix 封装的基础组件 ├── content/docs/ # 全部 MDX 文档内容(含 meta.json 目录配置) ├── hooks/geistdocs/ # use-chat、use-sidebar 等 ├── lib/geistdocs/ # source、i18n、db、md-tracking 等核心库 ├── geistdocs.tsx # ★ 站点级配置中心 ├── source.config.ts # ★ MDX 集合与 frontmatter schema └── next.config.ts # MDX 插件接入内容引擎:MDX 集合与 frontmatter Schema 配置
Geistdocs 的核心是 Fumadocs 的 **MDX 集合(collection)**机制,所有配置集中在docs/source.config.ts。它通过defineDocs声明文档目录为content/docs,并扩展了一套自定义 frontmatter 规范:
export const docs = defineDocs({ dir: "content/docs", docs: { schema: frontmatterSchema.extend({ product: z.string().optional(), url: z.string().regex(/^\/.*/, { message: "url must start with a slash" }).optional(), type: z.enum([ "conceptual", // 解释"是什么、为什么存在":架构、心智模型、设计决策 "guide", // 引导完成目标:教程、快速上手、工作流 "reference", // 查询导向的详尽资料:API 文档、配置项、函数签名 "troubleshooting", // 诊断问题与解决方案:FAQ、错误、已知问题、调试指南 "integration", // 多系统连接:第三方接入、插件、Webhooks、迁移 "overview", // 高层介绍:落地页、变更日志、发布说明 ]).optional(), prerequisites: z.array(z.string().regex(/^\/.*/, { message: "prerequisites must start with a slash" })).optional(), related: z.array(z.string().regex(/^\/.*/, { message: "related must start with a slash" })).optional(), summary: z.string().optional(), }), postprocess: { includeProcessedMarkdown: true }, }, meta: { schema: metaSchema }, });几个值得注意的设计点:
- 类型化 frontmatter:
product、type(六种文档类型枚举)、prerequisites、related、summary均通过 Zod 校验;其中url、prerequisites、related强制以/开头(正则校验并在错误信息中明确提示),从机制上杜绝了文档间链接的相对路径混乱,保证所有内部引用都是站点根路径。 includeProcessedMarkdown:开启后,构建期会保存经过处理的 Markdown 文本,供getLLMText等场景直接读取,这是 llms.txt / AI 聊天的基础。- 插件化:
remarkPlugins注册了remarkMdxMermaid(MDX 中的 Mermaid 图表),lastModified()插件为每个页面注入lastModified元数据,RSS 与 OG 图都会用到它。
meta.json则通过metaSchema定义每个目录的导航分组元信息,与 MDX 文件共同构成完整的文档树。构建时postinstall: "fumadocs-mdx"(见docs/package.json)会预生成.source/数据供类型安全地引用,例如lib/geistdocs/source.ts中的import { docs } from "@/.source/server"。
站点配置中心:geistdocs.tsx
模板把站点级"全局变量"集中在docs/geistdocs.tsx,改一处即可全站生效:
export const Logo = () => ( <p className="font-semibold text-xl tracking-tight">next-forge</p> ); export const github = { owner: "vercel", repo: "next-forge" }; export const nav = [ { label: "Docs", href: "/docs" }, { label: "Source", href: `https://github.com/${github.owner}/${github.repo}/` }, ]; export const suggestions = [ "What is next-forge?", "What can I build with next-forge?", "How do packages and apps work?", "What is a monorepo?", ]; export const title = "next-forge Documentation"; export const prompt = "You are a helpful assistant specializing in answering questions about next-forge, a production-grade Turborepo template for Next.js apps"; export const translations = { en: { displayName: "English" } }; export const basePath: string | undefined = undefined; export const siteId: string | undefined = "next-forge";各配置项的作用与消费方:
| 配置项 | 作用 | 消费位置 |
|---|---|---|
Logo | 站点 Logo(React 组件) | navbar / sidebar |
github.owner/repo | 生成 GitHub 编辑链接 | components/geistdocs/edit-source.tsx(拼接edit/main/docs/content/docs/${path}) |
nav | 顶部导航项 | navbar |
suggestions | AI 聊天默认推荐问题 | chat 对话框 |
title | 站点标题 | RSS 源、页面元数据 |
prompt | AI 助手的系统角色设定 | api/chat/utils.ts的createSystemPrompt |
translations | 已启用语言列表 | lib/geistdocs/i18n.ts(defineI18n的languages: Object.keys(translations)) |
basePath | 站点部署子路径前缀 | 搜索、聊天等所有fetch路径拼接 |
siteId | 站点唯一标识,用于 Markdown 请求追踪埋点 | lib/geistdocs/md-tracking.ts |
注意prompt仅定义了角色的第一句话,实际系统提示词在api/chat/utils.ts中被大幅扩展(见下文 AI 章节)。而translations目前仅含en,说明模板默认单语言;若要启用多语言,只需扩展该对象并在content/docs下按语言组织内容。
国际化侧,docs/lib/geistdocs/i18n.ts使用defineI18n({ defaultLanguage: "en", hideLocale: "default-locale" })——默认语言en的路由不显示语言前缀,其他语言则以/de、/fr等形式出现;同时通过defineI18nUI向 Fumadocs UI 注入语言切换能力(对应components/geistdocs/language-selector.tsx)。
文档渲染管线:从 source loader 到页面
类型安全的文档源加载
docs/lib/geistdocs/source.ts是文档树的"唯一事实来源":
export const source = loader({ i18n, baseUrl: "/docs", source: docs.toFumadocsSource(), plugins: [lucideIconsPlugin()], });loader把构建产物转成带 i18n、slug 解析、导航树能力的类型安全数据源;lucideIconsPlugin允许在 frontmatter 或 MDX 中直接用 Lucide 图标名。同文件还导出了两个关键工具函数:
getPageImage(page):按[...slugs, "image.png"]拼出/og/<路径>/image.png,配合动态 OG 路由为每篇文档生成专属社交分享图;getLLMText(page):读取page.data.getText("processed")(即includeProcessedMarkdown产出的纯净 Markdown),并序列化出包含title、description、product、type、summary、prerequisites、related的 frontmatter 块,最后统一追加/sitemap.md与/llms.txt两个导航链接——这段文本同时供给llms.txt 路由、RSS 之外、AI 上下文与"复制为 Markdown"使用。
文档页面与元数据
docs/app/[lang]/docs/[[...slug]]/page.tsx是文档渲染的入口,整体是服务端组件(async):
source.getPage(slug, lang)解析当前路由,未命中则notFound();DocsPage配置了tableOfContent风格为"clerk",并在目录底部注入一组工具栏:EditSource(GitHub 编辑)、ScrollTop(回到顶部)、Feedback(反馈)、CopyPage(复制 Markdown)、AskAI(针对当前页提问)、OpenInChat(打开聊天);- MDX 正文通过
getMDXComponents(...)注入模板组件:Tabs/Steps(来自 fumadocs-ui)、VercelButton,以及把Warning、Tip、Info、Note统一映射为不同色调Callout的便捷写法——这意味着在 MDX 里写:::tip或<Tip>都能得到一致的提示块样式; generateStaticParams全量静态生成(SSG),generateMetadata输出openGraph.images(动态 OG 图)与alternates.types["text/markdown"](Markdown 原文替代格式)。
首页(docs/app/[lang]/(home)/page.tsx)由Hero、Apps、Features、CallToAction组合而成,并定义了面向搜索引擎的metadata.title/description。
AI 聊天助手:理解并回答"你自己的文档"
AI 聊天是 Geistdocs 最具特色的能力。其实现横跨客户端、API 路由与工具层三部分。
服务端:流式响应 + 文档工具
docs/app/api/chat/route.ts使用 AI SDK v5 的streamText/createUIMessageStreamResponse实现流式输出,maxDuration = 800。请求体除messages外还携带currentRoute(用户当前所在文档页)与可选的pageContext(当前页标题/URL/内容)。核心处理逻辑:
- 过滤掉仅用于 UI 展示的
isPageContext消息; - 若携带
pageContext,则将当前页内容拼接到最后一条用户消息之前,使模型"带着当前页面上下文"作答; - 通过
createTools(writer)注册文档工具(见docs/app/api/chat/tools.ts),典型工具包括:search_docs(按查询搜索文档内容,返回标题、描述、URL 等);get_doc_page(按 slug 获取完整文档页内容);- 列出全部可用文档页面(
get_all_docs类工具);
- 用
createSystemPrompt生成的系统提示词约束模型行为。
docs/app/api/chat/utils.ts中的系统提示词值得全文研读,它规定了:只依据检索到的文档回答、不依赖外部知识;优先引导用户走"happy path";currentRoute与当前页匹配时优先get_doc_page,否则每轮最多调用一次search_docs;禁止连续多次调用工具;一律用 Markdown 输出、代码块必须带语言与文件名标注;不使用 emoji;文档与指令冲突时以文档为准。这套提示词工程使 AI 助手能稳定地"只在文档内作答",避免幻觉。
客户端:带持久化的聊天体验
docs/components/geistdocs/chat.tsx通过@ai-sdk/react的useChat连接/api/chat(自动适配basePath)。模板还实现了useChatPersistence——利用Dexie(IndexedDB)把对话记录保存在本地,刷新页面后会话不丢失;docs/hooks/geistdocs/use-chat.ts提供全局聊天状态(开关、提示词),AskAI与OpenInChat组件即通过它把"针对当前页提问"注入聊天。UI 元素(对话气泡、输入框、来源引用、思考中的 shimmer 动画)集中在components/ai-elements/。
全文搜索:模糊匹配与多语言分词
搜索是"高级搜索"特性的实现核心。服务端docs/app/api/search/route.ts基于fumadocs-core/search/server的createFromSource,把source的全部页面建立索引;针对非拉丁语言,模板用@orama/tokenizers做了语言适配:
- 若
translations中包含cn(中文),自动挂载createTokenizerMandarin()并把搜索threshold与tolerance都设为0(要求更严格匹配,避免中文分词噪声); - 若包含
jp(日文),挂载createTokenizerJapanese(); - 每个 locale 还会映射
displayName作为搜索引擎的语言标识。
客户端docs/components/geistdocs/search.tsx使用useDocsSearch+ Fumadocs 的SearchDialog系列组件(cmdk驱动命令面板式弹窗),支持键盘快捷键唤起、结果列表展示与跳转,实现"输入即搜、模糊命中"的体验。当前仓库translations仅含en,因此中文分词器处于待启用状态——若你的站点需要中文搜索,只需在geistdocs.tsx的translations中加入cn配置即可自动生效。
LLM 友好输出:llms.txt、sitemap.md 与 RSS
这是 Geistdocs 面向 AI 时代的设计亮点:让整站文档对 LLM 和 Agent 可读、可检索。
/llms.txt(docs/app/[lang]/llms.txt/route.ts):遍历source.getPages(lang),对每页调用getLLMText得到"frontmatter + 处理过的 Markdown"文本,全部拼接后以text/markdown; charset=utf-8返回。revalidate = false表示静态生成。/sitemap.md(docs/app/[lang]/sitemap.md/route.ts):输出按语义组织的文档索引,供 LLM 快速理解站点内容范围。/rss.xml(docs/app/[lang]/rss.xml/route.ts):用feed库生成 RSS 2.0,条目来自每个页面的title、description、lastModified(正是前面lastModified()插件注入的字段),站点基础 URL 取自NODE_ENV与NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL环境变量。/og/[...slug](docs/app/[lang]/og/[...slug]/route.tsx):动态 OG 图片生成路由,为每篇文档渲染带标题的分享图(字体文件与背景图位于该目录下)。
反馈与 GitHub 集成
模板把"用户反馈回流到 GitHub"做成了完整链路:
- 页面内反馈:
docs/components/geistdocs/feedback.tsx提供表情评分(app/actions/feedback/emotions.ts)+ 可选文本,通过 Server ActionsendFeedback(docs/app/actions/feedback/index.ts)提交;并用localStorage记录docs-feedback-${url},防止同一用户对同一页面重复评分。 - 编辑入口:
docs/components/geistdocs/edit-source.tsx依据github.owner/repo生成指向源 MDX 文件的 GitHub 编辑链接,引导贡献者直接改文档。 - "Open in Chat" / "Copy Page":分别把当前页作为上下文发起 AI 追问,或把
getLLMText产出的 Markdown 复制到剪贴板,形成"阅读 → 提问 → 复制引用"的闭环。
主题、暗色模式与 UI 基础
模板的 UI 建立在 Radix UI 之上(components/ui/目录封装了 dialog、dropdown-menu、popover、select、sheet、tooltip 等几十个组件,并基于 shadcn 风格用class-variance-authority+tailwind-merge管理样式变体)。暗色模式由next-themes提供(components/geistdocs/theme-toggle.tsx),配合 Tailwind CSS 4(@tailwindcss/postcss)与tw-animate-css动画。内容侧的渲染增强还包括:
- Mermaid 图表:通过
remarkMdxMermaid插件 +components/geistdocs/mermaid.tsx,文档里可直接书写 `sh
安装依赖(仓库根目录使用 Bun)
bun install
构建期先运行 postinstall 钩子生成 MDX 集合数据
bun run postinstall # 即 fumadocs-mdx
开发 / 构建 / 生产启动
bun run dev bun run build bun run start
定制一个属于你自己的文档站点,核心只需四步: 1. **换内容**:把 `docs/content/docs/` 替换为你自己的 MDX 文档与 `meta.json`; 2. **改配置**:编辑 `docs/geistdocs.tsx`,更新 `Logo`、`title`、`prompt`、`suggestions`、`siteId`,并按需扩展 `translations` 启用多语言或中文分词搜索; 3. **扩展 schema**:在 `docs/source.config.ts` 的 Zod schema 上追加自定义 frontmatter 字段(如 `product`、`summary`),并在 `getLLMText` 中同步序列化; 4. **调 UI**:在 `docs/app/[lang]/docs/[[...slug]]/page.tsx` 的 `getMDXComponents` 中注册你自己的 MDX 组件。 若需部署在子路径下,设置 `geistdocs.tsx` 的 `basePath` 即可——搜索、聊天、OG 图片等所有路径都会自动带上前缀。模板还提供了 `bun run translate`(`npx @vercel/geistdocs translate`)辅助多语言翻译流程。 ## 小结 Geistdocs 在 next-forge 中不仅是一套"能跑的文档站",更是一份高完成度的参考实现:Fumadocs 提供了类型安全的内容管线(`source.config.ts` → `loader` → 静态页面),模板在其上补齐了 AI 问答(流式 API + 文档工具 + 对话持久化)、多语言全文搜索、llms.txt/RSS/OG 等分发渠道,以及基于 Radix 的完整 UI。对于任何需要"文档即产品"的 Next.js 项目,直接以 `docs/` 目录为蓝本二次开发,都是成本最低的路径。【免费下载链接】next-forgeProduction-grade Turborepo template for Next.js apps.项目地址: https://gitcode.com/GitHub_Trending/ne/next-forge
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考