Fumadocs

我们很高兴地宣布首个资助项目:由 Fuma Nama 打造的 Fumadocs。
Fumadocs 是一个美观且灵活的 React 文档框架,由四个模块化层组成:Core、Content、UI 和 CLI。其架构与视觉设计都源自可组合性与简洁性这两大核心理念。每个库都是一组“构建块”,将自身的运作方式坦然呈现,让开发者能完全按照自己的想法修改和创建文档。视觉设计将优雅、高性能的组件与对细节的极致打磨融为一体,无论对人类还是 LLMs,都是一种极速流畅的阅读体验。
Fumadocs 已被 Vercel Turborepo、shadcn/ui、BetterAuth、Unkey 等众多项目采用。这些站点风格迥异,恰恰印证了 Fumadocs 的可组合性。当然,General Translation 自己的文档也是用 Fumadocs 搭建的!
Fumadocs 的创建者 Fuma Nama 对开发者体验有着深入的思考。框架的每一层、每一处细节都经过反复推敲:从组织内容以提升可读性,到减少抽象层,再到在可维护性与可定制性之间取得平衡。
我们与 Fuma Nama 进行了他有生以来的第一次访谈,聊到了开发 Fumadocs 的三年多历程,以及更长时间的开源开发经历。 (你知道吗?他去年才刚刚高中毕业。)
下文中,我们会谈到 Fuma Nama 如何通过阅读代码文件自学编程、他对“有主见的软件”的看法、他的库为何采取“少一些魔法”的思路、开源为何天然具有全球性,以及他关于文档阅读体验的理念——其间还藏着一些彩蛋,比如他这个名号的由来,以及 Fumadocs 标志如何从月亮获得灵感。
计算机的绚烂世界
Fuma Nama 在香港长大。他 6 岁那年,家里买了一台电脑。他在文章中写道,童年时他常在万维网上四处漫游,第一次见识到“计算机的绚烂世界”。他眼中的软件,始终带着一层魔力与玩心。上小学时,他用 Unity 拼凑出一款沙盒游戏,让玩家能在沙漠、月球、废墟之城、山脉与森林等不同场景中切换驾驶汽车和飞机。
至于“软件作为一种概念”,是很久以后才进入 Fuma 视野的。他学写代码,靠的是给电子游戏做模组和逆向工程。他说,自己学 C# 的方式就是看代码、改代码,然后观察游戏里发生了什么变化。
“说起来挺疯狂的。我是从文件里学会编程的。我会看到一大堆 JavaScript,然后就一路读下去,”他说,“我完全没看过任何文档,只看代码本身。”
正因为 (虽然纯属偶然) 直接接触了“第一手资料”,Fuma 对那些最本质的认知原理理解得很深。他掌握的是框架背后的思维模型,而不是贴在各种行为上的标签。被问到最喜欢软件架构的哪一点时,Fuma 至今仍会提起 Java 里那套老派的 OOP (面向对象编程) ——一个简单得近乎激进的选择。
“对象这个想法非常优雅。我是按类的继承来思考的,”他说,“这是一个通用模型,在 Java、JavaScript 以及你接触到的许多其他语言中都是一样的。”
Fuma Nama 在自己的网站上自称“开源法师 (open sourcerer) ”。在从零学会 C# 之后,也难怪他会形容 React.js、Vite 这类现代 Web 开发框架“闪闪发光、充满魔法”。在他的软件体验里,处处透着一种被创造可能性所迷住的感觉。
“如果一整天没碰过我的编辑器,我会觉得不开心,”Fuma 说,“哪怕在旅行,我醒来第一件事就是打开电脑、打开编辑器。有时候我其实也不知道自己要做什么,就是想打开编辑器。”
“别人在画画里感受到的东西,我在写代码里感受到了,”Fuma 说。
开源生态
在 Fuma 看来,开源库凝聚着无数开发者的愿景与心血。
"能亲手触碰到这些由众多人耗费大量精力设计出来的想法,本身就很有意思,"Fuma Nama 说,"就像感受自然、感受这个星球。你真的能感受到世界各地的人。"
"比如 [React] 的 Server Component,就汇聚了许多聪明的头脑。RFC 流程意味着除了 React 核心成员,还有大量开发者参与其中,"他说。他所指的是 Request For Comments 流程。
Fuma 刚开始着手打造后来的 Fumadocs 时,最初给它取名"Next-docs"。
"我当时觉得,做一个正式的 Next.js 文档框架应该挺好玩的,虽然这个野心有点疯狂,"他说,"但那只是个实验。当时正值 App Router 时代,Server Component 刚刚问世,这是一种我还没试过的有趣模式。对我来说,代码本身就像一个想拿来玩玩的玩具。"
后来他把框架改名为 Fumadocs,以免与官方文档混淆。 (Fuma Nama 这个名字源自对日语"ふわふわ" (fuwa fuwa) 的俏皮化用,这个词用来形容轻盈蓬松的事物。或许可以说,这正是理想的开发者体验。)
Fumadocs 的成长离不开开源社区的鼎力支持。而 Fuma 最喜欢的回应,是那些富有建设性的反馈。
"我喜欢带着问题的回应,或者任何能帮我改进框架的东西,"他说。Fuma 至今仍会翻看开发者 Anthony Shew 两年前提出的一个 issue。在那份功能请求中,Shew 敏锐地指出,Fumadocs 的设计意图明显偏向"少一些魔法,多一些可组合性"的理念。
"他是最早在重要项目中采用 [Fumadocs] 的人之一,"Fuma 说,"他给了我非常具体、非常有价值的反馈。他是真的理解并在意这个项目的目标,这让我很意外。"
如今 Fumadocs 在 GitHub 上已收获超过 13,000 颗星,Vercel、Unkey、Orama 以及我们自己等公司都在使用它。过去三年里,Fuma Nama 持续构建和维护着这个框架,在学业和其他事务之余投入了数百小时。
在 Fuma Nama 对手艺的追求之下,是一套关于 Web 开发框架与软件设计的更深层思考。
更少的抽象,更少的固执己见
在 Fumadocs 文档的 Philosophy 一节中,Fuma 阐明了其核心主张:Fumadocs 是一个可以被你拆开的文档框架。
他所说的“可拆解”,指的是开发者能够拆分并重塑框架中的任意一部分。Fumadocs 的精神,是服务于那些不满足于“一份能用的文档”、而是想打造“完美文档”的人:契合自己独特的需求、偏好与审美。
“我们需要一个真正、真正可组合的系统,”他说,“一个足够完整、同时又极具可组合性的框架。”Fumadocs 希望为开发者提供模块化且易于理解的乐高积木,让他们能以截然不同的方式搭建出截然不同的文档站点。
Fuma 的思路源自一个更宏观的判断:现代 Web 框架抽象得太多了。复杂性被隐藏起来,用起来自然“魔法般”轻松;但这同时也遮蔽了底层的逻辑、机制以及不可避免的取舍。比如,初学者可能完全不了解 meta 标签的工作原理,就用上了 Next.js 的 Metadata API;或者完全不清楚计算开销,就把逻辑写进了 Server Component。
过度抽象让开发者无法真正看清、理解并修改代码。因此,他给 Fumadocs 定下的目标是“少一点魔法”:框架把路由文件放在你的 repository 里,让你自己创建搜索 handler,让你从自己的代码中调用内容 loader,还可以通过 CLI 把 UI 组件直接复制到你的 codebase 中。
Fuma 明确地把这个框架定义为“不固执己见”的。“固执己见的软件 (opinionated software) ”指的是那种强制推行一套约定、引导用户走向某一种“正确”构建方式的框架或库。 (这个说法有时会被混同于“有主张”本身,或被当作一种普遍的褒义评价。) 固执己见的软件带着强势的默认设定和“正确”的构建路径,这与 Fuma 追求的可组合性、可拆解性和更少抽象相冲突。
因此,Fumadocs 是一个更少魔法、更少固执己见的框架。
不过 Fuma 也承认,开发者同样需要开箱即用的可用性和完整性。为此,他把 UI 库设计成框架中相对固执己见的一层,带有强势的默认视觉设计。这样一来,开发者可以立刻得到外观优雅的文档,同时保留修改每个模块化部件的能力。 (也就是说,只要愿意,他们完全可以换上自己的一整套 UI。)
“Fumadocs 最难的问题,是在两类极端用户之间取得平衡,”他说,“一边是完全不想做任何修改、只想快速轻松上手的开发者;另一边是想定制一切、改到几乎认不出原本模样的人。”
这种平衡对大多数框架和库的作者来说都是一项挑战,而这只是 Fuma Nama 深入思考过的众多取舍之一。
黑盒与编译器
以 package 形式交付代码是大多数库的默认做法,而对 Fuma 来说,这是一个深思熟虑后的选择。
“对大多数开发者来说,package 就是个黑盒,除非他们去翻源代码,”Fuma 说,“当然,你还是可以打补丁去改代码。但一旦把它塞进 package 里,你其实并不知道里面发生了什么。”
规模一大,这个问题就更严重。“你在 package 里写的逻辑越多,就相当于往黑盒里塞了越多代码,”他说。
另一条路——shadcn/ui 那种把 组件 直接复制进 codebase 的模式——绕开了黑盒问题,但也有它自己的代价。
“维护成本永远由你自己承担,”他说,“而且框架每改进一次、每加一个新功能,你就得做大量代码重构。到某个阶段,这就不划算了。”
在 Fumadocs 里,Fuma 用渐进式的“逃生舱”来平衡这笔账。package 仍是主要模式,而 CLI (灵感来自 shadcn/ui) 则服务于那些需要更细粒度定制的开发者。CLI 以 组件 为单位工作,甚至能更细——只取出布局中的某一个 slot (比如只要目录) 。组件 的 copy 归开发者所有,slots prop 再把它接回周围的结构中,这样后续 release 依然能从 Fumadocs package 持续更新,而不会把它覆盖掉。
在幕后,Fuma Nama 认为 CLI 是构建难度最高的部分之一。它本质上是一个编译器,要把原本的 package 组件 转换成与目标项目和框架兼容的 standalone files。
“你得把 package 里一个能跑起来的 组件 反过来拆成独立、隔离的文件,还要能 download 到 codebase 里,”他解释道,“我得把各种框架都学一遍,还做了大量测试,才能确保 AST 是对的。” (抽象语法树转换包括:把 组件 的源文件解析成一棵树,重写其导入路径以匹配目标项目,并调整语法。)
有了 CLI,这个框架的四个模块化层次就齐全了:Content、Core、UI 和 CLI。
Fuma 把 Fumadocs 描述为“一堆工具函数和 MDX plugin”。他最喜欢的 integration 是 Story,它专为组件库文档而生。Story 正是 Fumadocs 大放异彩之处,因为交互式 组件 没法只靠 Markdown 展示,而这对灵活性欠佳的文档框架来说是个硬伤。
“就算从头再来一遍,我想 Fumadocs 大概还是现在这个样子,”Fuma 说。这是一个真正可以被“拆开”的框架,而这正是精心设计的结果。
Fumadocs 的设计信条
Fuma 的文档设计理念偏向极简的用户体验,同时对每一处细节都极为讲究;他的视觉审美与他在代码上崇尚简洁的信念一脉相承。
“我着迷于设计艺术中对形状的抽象。我会试着把这一点融入自己的设计,用几何形状去描绘某种事物,”他说,“Fumadocs 的标志是一个圆,我愿称之为月亮,Luna。”
“我花了大量时间,就是在打磨细节。默认布局改过很多次,每个版本都有一些非常细微的迭代,”他说。
Fuma Nama 认为,“花哨吸睛的 UI”更适合落地页,而文档页面应当聚焦于内容和简洁的阅读体验。
目录 (TOC) 的设计就是一例:它并不喧宾夺主,却是 Fumadocs 中经过深思熟虑的视觉细节。

“我受到了 Clerk 文档滑块的启发,但我想做得不一样,做得更漂亮些,”他说。由于涉及服务器端渲染,这个滑块的实现机制颇为棘手:服务器端能画出轮廓,却无法测量浏览器,因此交互部分需要在客户端重新构建。具体做法是把轮廓描摹成一条 SVG 路径,将其作为 CSS 遮罩应用,再让一个发光块在其后滑动,于是“当前章节”的高亮便会沿着这条线移动。
“我猜大家可能不会注意到吧,”Fuma 说。但这些小细节终究值得去做,而他对视觉设计中微妙之处的用心,显然源自他对开发者与读者体验的整体关照。
“很多时候你不只是在做出一个解决方案,你是在设计它,”他说,“你得不断尝试不同的方法,直到它达成一种平衡。”
完美的软件
Fumadocs Plus 的下一次迭代将提供更简单的处理方式,从而更好地服务初学者以及 AI。"复杂度越低,对 AI 越有利,"Fuma 解释道,"因为我们都知道,AI 真的会产生幻觉。"
他注意到,自己收到的 issue 比以前少了,很可能是因为智能体——它们不会提 issue,而是绕开问题继续干活。这让反馈闭环越来越难建立。"如果智能体不报告 bug,我就没法修复,"他说,"但我仍然在积极维护所有项目,并尽可能把 issue 数量压到最低。"
他欢迎来自 开源 社区的贡献。"如果你想给我的 repo 贡献一个功能或别的什么,直接开个 issue,说明你想参与就行,"他说,"我会很乐意审校。"
"我希望 Fumadocs 能成为 Web 的文档框架,"他说,"我也想让它一直是 UI 的标准。"
Fuma 还在打造其他 开源 软件,包括正在积极开发的 tegami——一个管理更新日志和 versioning 的工具,以及 fumadb——一个面向 library 的数据库 API。
"我认为,随着越来越多公司开始认可 开源 社区并加以回馈,开源 会发展得越来越壮大,"他说。他指出,AI 正在重塑整个生态,既降低了项目的维护成本,也给维护者留出了更多空间。
Fuma 将 Daishi Kato 视为自己在 开源 上的灵感来源,尤其是他的 RSC 框架 Waku 和状态管理库 Jotai。
"Waku 真的被低估了。它的核心思路是极简且 composable,这正是我把 Fumadocs 和许多其他项目构建在它之上的原因,"他说。两者在理念上的契合显而易见:Waku 官网就将该框架描述为"轻量"、带来"有趣的开发者体验"。
Fuma 在自己的 开源 项目上倾注了大量时间,其中的辛苦往往不为人所见。他把所有项目都视作珍宝,也视作永远在打磨中的作品。
"我想做出完美的软件,"他说,"让我的 repository 零 issue,这大概就是我的目标。"如果世上真有完美的软件,Fuma Nama 或许正是那个能造出它的人。
