Skip to content

转变 Material for MkDocs

我们正在开发一套令人惊叹的功能,这需要一些幕后工作,现在我们准备在一系列帖子中分享这些内容。在这里,我们概述了我们的目标、正在开发的功能、让我们夜不能寐的事情,以及我们对开源的承诺。

我们知道自上次更新以来已经过了相当长的时间,这就是为什么我们迫不及待想与您分享 Material for MkDocs 及其周边的最新动态。在 2024 年的大部分时间里,我们专注于转变 Material for MkDocs 的核心,为新功能的互联互通打下基础,这些功能是用户最常请求的。

本文是一个系列的一部分,我们将探讨如何通过改善信息检索、提供更好的多语言网站和版本控制支持,以及改善整体创作体验来支持我们的用户。我们概述了项目发展的愿景,并描述了我们一直在努力的内容。在这篇以及接下来的博客文章中,我们将与您分享我们的进展,并期待听到您的想法。

请注意,本文包含一些技术细节,特别是关于挑战的脚注。如果您对具体内容不感兴趣,可以随意跳过。


这是四部分系列的第一篇文章:

  1. Transforming Material for MkDocs
  2. Zensical – A modern static site generator built by the creators of Material for MkDocs
  3. Material for MkDocs Insiders – Now free for everyone
  4. Goodbye, GitHub Discussions

成功故事

截至目前,2024 年,Material for MkDocs 已经稳固地确立了自己作为文档框架领域的领先工具,每月下载量超过 500 万次。最初作为 @squidfunk 的个人项目,它已经发展成为一个多功能资源,用于创建全面的文档网站、个人网站、博客,尤其是在组织内部和外部管理知识方面。

目前,有近 50,000 个公共 GitHub 项目依赖于 Material for MkDocs,这清楚地表明该框架产生了重大影响。成千上万的作者依赖我们为每月数百万用户提供文档。1 除了被 许多流行的开源项目 采用外,Material for MkDocs 还得到了 AWSMicrosoftSiemens 等大型公司的信任和财务支持,以及许多其他公司和个人的支持。我们非常感谢持续的支持,这使我们能够将时间投入到这个项目中,让编写文档变得愉快。

我们的用户特别欣赏 Material for MkDocs 的易用性和简单设置。它通过处理网络技术的复杂性来简化流程,使您可以在几分钟内构建一个生产就绪的静态网站,而无需投入数年时间来掌握前端开发或 JavaScript。这使得无论用户的技术背景如何,都能轻松使用。此外,Material for MkDocs 采用 MIT 许可证,免费使用,这也促进了它的广泛采用,使每个人都能以零成本构建复杂的文档网站。

我们的愿景是为您提供工具,使您能够 拥有您的文档,使您能够开发自己的文档制作流程,并避免即使是做简单事情也被锁定在昂贵的订阅服务中。我们认为,这些工具应该易于设置和配置以满足您的需求,但也应该让您有自由进一步调整它们(如果需要)。这就是为什么我们始终努力确保我们的架构是模块化和面向未来的。2

挑战

现在,让我们谈谈我们的旅程以及我们正在解决的特定挑战。这里的“我们”指的是 @squidfunk 周围建立的令人难以置信的团队,感谢他从 赞助商 那里获得的财务支持。这个杰出的团队包括 @alexvoss@katharinalisalin,他们在研究、开发和社区支持方面的宝贵贡献对项目的持续成功至关重要。

我们一起开始探索新技术,结合用户反馈,重新思考关键组件,从第一原则出发,为我们不断增长的社区提供最佳的文档创建框架。

本节重点介绍了我们一直关注的关键领域。

搜索和发现

从我们的角度来看,搜索是任何有效文档网站的基石,使用户能够快速找到所需的信息。从一开始,我们就依赖于 Lunr.js,这是一个流行的客户端搜索库,它简化了文档网站的部署,无需外部服务。多年来,Lunr.js 为我们提供了良好的服务,处理了数百万个在 Material for MkDocs 构建的网站上的查询。然而,随着用户需求的演变,我们遇到了难以克服的局限性。

我们了解到,Lunr.js 核心的 BM25 排名算法(与许多其他搜索实现一样)并不适合有效和稳定的前置搜索。添加新文档可能会影响现有排名,要求进行手动调整3,这既繁琐又难以扩展。此外,Lunr.js 还存在性能问题,源于其设计未能充分利用现代 JavaScript 引擎和优化,导致其速度较慢且内存占用较高。4

在过去几年中,我们在 改善搜索体验 上投入了大量资金。例如,扩展 Lunr.js 的功能以支持 丰富搜索预览分词器前瞻 需要大量的工程努力。Lunr.js 允许自定义诸如词干提取、停用词过滤和修剪等任务,使用 管道函数,但这使得添加诸如术语高亮或替代排名方法等扩展变得特别困难。再加上 Lunr.js 自 2020 年以来 未维护,我们意识到需要找到一个更强大的解决方案。我们查看了其他基于 JavaScript 的库以保持我们的客户端搜索,但没有一个满足我们的要求或达到我们的期望。

为了解决这些挑战,我们开始从第一原则出发开发一个新的搜索系统,该系统不仅匹配而且已经超越了 Lunr.js 的能力。这个系统从头开始构建,速度更快,更紧凑,最重要的是:模块化。它基于一个不断增长的核心,围绕我们认为至关重要的两个核心概念——引擎和插件——发展,允许灵活配置和组件组装,如文本索引、向量嵌入、过滤、排名、高亮等。它的每个部分都可以被替换或扩展,使用户能够根据特定需求定制搜索系统。

我们的新搜索系统将作为一个单独的 MIT 许可证开源项目发布,旨在处理各种场景——从小型博客到大型文档项目。当然,它支持离线使用,并与客户端和服务器环境无缝集成。先进的排名系统提供精细的控制,第三方服务的集成现在也更加简单。

目标 – 使用户能够快速找到所需信息,同时让作者免于管理外部服务,通过提供一个适应多种内容类型的搜索系统。

您可能会想,为什么它还没有可用。开发这个系统的过程以及揭示其潜力使我们重新评估了 Material for MkDocs 的核心概念。因此,我们决定推迟新搜索系统的发布,以将其整合到我们开始工作的更广泛更新中。如果您继续阅读,您将了解到我们决定采取这种方法的进一步原因。

我们期待在本系列的下一篇文章中分享有关此更新的更多细节。

翻译和版本控制

在 MkDocs 中支持多语言网站是我们讨论板上 最受欢迎的功能 和与用户对话中的请求,但这带来了重大挑战,因为 MkDocs 本身并不原生支持多语言。版本控制也是如此,这同样涉及多项目构建的同步。尽管 MkDocs 生态系统开发了 各种插件和工具 来解决这些问题,但仍然存在大量未开发的潜力。我们开始探索这些领域,但很快遇到了阻碍我们进展的问题。

如您所知,我们的初步努力涉及 项目插件,旨在扩展 MkDocs,以支持多项目环境,作为支持多语言网站和版本控制的坚实基础。不幸的是,由于 MkDocs 的内部架构和设计限制,我们遇到了重大挑战,我们正在积极努力解决这些问题。5

目标 – 通过提供无缝的方法来集成多个文档项目,使文档能够扩展到任何规模或团队结构,无论它们涉及不同的语言、版本,还是整体工作体的不同部分。

因此,我们正在开发一种新方法,以提供更全面和强大的解决方案,支持多语言和版本控制。这种新方法还与相邻功能交叉,例如搜索,因为许多用户对将来自多个文档网站的结果组合到统一搜索界面的 联合搜索 功能感兴趣。克服这一挑战是我们在发布新搜索系统之前需要解决的主要障碍之一。

编辑和协作

我们曾考虑开发一个实时编辑器,以应对 MkDocs 在大型项目中的 性能问题,这些问题在大多数情况下源于不使用缓存的计算密集型插件。基于 Pyodide(= 在浏览器中运行 Python)的 概念验证 在用户中引起了重大兴趣,并促使许多组织和个人分享他们的协作工作流程以获取反馈。遗憾的是,实现这个实时编辑器证明是非常具有挑战性的,因为这需要重建 MkDocs 的大量部分。6 在停止对此方法的工作后,我们在多项目支持方面的进展使我们重新相信,我们最终可以解决过去几年多次报告的缓慢编辑体验。7

这使我们谈到了协作,这最初并不是我们的优先事项之一。然而,在 2024 年,与各种组织和流行开源项目维护者的对话强调了对增强协作功能的频繁请求。许多用户表达了希望能够让非技术团队成员建议和更改文档的需求。我们非常感谢这些反馈,因为它们在关键时刻到来。我们认识到需要简化跟踪和讨论更改的过程,并促进随意贡献。

目标 – 每个人,无论其技术技能水平如何,都可以轻松地参与和改善文档,并为不断增长的知识库做出贡献。9

这种对协作的关注与企业中知识管理的方式相一致。在大型组织中,文档通常存在于 信息孤岛 中——去中心化但又至关重要的信息存储库。我们理解需要能够将这些不同来源统一成一个连贯的知识体系,同时保持去中心化的所有权。这也与我们之前概述的多项目支持工作相一致,以及新搜索系统以实现多个项目之间的 联合搜索

大语言模型(LLMs)

几乎一年前,我们在文档网站上推出了一个 实验性聊天机器人。它迅速成为最受期待的功能之一,用户请求能够在自己的站点上部署类似的功能,突显出对互动文档工具日益增长的需求。然而,我们发现,增加现有聊天解决方案的种类,仅仅在 ChatGPT 上构建另一个薄薄的包装是没有意义的。

目标 – 我们设想创建一个统一的界面,完美整合高级搜索、聊天和摘要功能,提供互动文档体验。

当我们深入这个雄心勃勃的项目时,我们从用户反馈中获得了宝贵的见解。用户开始用他们的母语与聊天机器人互动,这是我们没有预料到的,因为我们的文档是用英语写的。值得注意的是(或者对那些全年从事 LLM 工作的人来说显而易见),聊天机器人用同样的语言作出回应。LLM 的这一能力是这些机器学习模型中真正令人兴奋的特性之一,因为它有潜力改善文档的可访问性。然而,尽管我们采用了最先进的 RAG 方法,但结果却是喜忧参半,偶尔会出现幻觉。

这些经历使我们优先考虑在集成基于 LLM 的功能之前增强我们的搜索能力。从零开始构建搜索引擎已经是一个相当大的工作,而在没有坚实的搜索基础的情况下增加更多复杂性将是草率的。通过重新构建我们的搜索功能,我们旨在创建一个强大的平台,能够无缝支持高级信息检索,并提供一个连贯的互动文档体验。

团队、透明度和增长

在我们应对挑战并探索该项目的机会时,我们认为展示我们如何为其持续增长和成功奠定坚实基础是至关重要的。请将此视为概述,而非正式路线图——我们的详细计划正在制定中。我们所强调的目标代表了我们希望解决的最具影响力的领域。

感谢我们赞助商的慷慨支持,我们有幸组建了一支能够投入大量时间和专业知识的团队。这种新获得的能力使我们能够更深入地进行核心开发,同时更全面地与用户社区互动。特别提到的是 @kamilkrzyskow,我们宝贵的社区专家之一,他在支持用户和促进我们平台上的讨论方面发挥了重要作用。

在团队的支持下,@squidfunk 可以专注于开发的核心,而我们已经开始投资于用户研究。这项工作帮助我们了解组织和个人如何与我们的工具互动,根据与众多用户和公司的真实反馈指导项目的未来方向。

我们希望进一步扩展我们的团队,致力于改善透明度和沟通。由于时间限制,我们之前的工作往往发生在幕后,但我们现在专注于使我们的流程更加开放,并欢迎新贡献者。通过这种协作方式,我们旨在增强我们的工具,确保它们满足我们社区不断变化的需求。

我们的未来

展望未来,我们现在奠定的一些基础工作对即将到来的激动人心的发展至关重要。我们讨论的许多倡议代表了基础工作,将为更雄心勃勃和创新的功能奠定基础。一旦这些核心要素到位,我们将提供一系列令人兴奋的新功能,以符合我们的愿景和目标。

在接下来的几个月中,我们将分享有关我们计划的更多细节,以及它们将如何为我们的总体目标做出贡献。虽然增长和创新是我们计划的核心,但我们想向您保证,我们的核心价值观保持不变。我们致力于维护指导我们至今的原则,确保我们的增长既健康又一致:

  • 针对最近行业趋势中公司远离开源核心理念的情况,我们正在加倍致力于开源,因为我们相信这正是我们工作的价值主张和 文档即代码 方法的核心。

  • 我们的 有机增长方法 是这一战略的一部分,因为它使我们独立于个别资金来源和提供投资回报的压力,这正是导致许多其他项目偏离开源原则的原因。

  • 同样,我们受到社区对核心框架丰富生态系统适应需求的驱动。可扩展性和模块化是这一点的关键,我们正在努力改善开发者体验,提供清晰的接口。

请继续关注我们的更新,因为我们将继续在进展的基础上探索新可能性。我们对未来感到兴奋,并期待在前进过程中与您分享更多内容。

马丁、亚历克斯和凯瑟琳


  1. 我们从企业和其他开源维护者那里收集了宝贵的反馈,这表明实际数字甚至更高。许多组织在私有基础设施中利用该框架,例如像 GitLab 这样的自托管平台,用于内部知识管理。这表明 Material for MkDocs 的真正影响远远超出公开可见的范围。 

  2. Material for MkDocs 附带的 内置插件 完美地概述了这一原则,因为它们彼此互补,可以组合使用以构建复杂的管道。这种模块化设计允许用户选择所需的功能,确保框架保持轻量和灵活。

    例如,隐私插件 可以与 优化插件 一起工作,以便将外部资产通过与其余文档相同的优化管道传递。这意味着您可以在存储库外部存储和编辑未优化的文件,并让这两个插件自动为您构建优化的网站。 

  3. BM25 中提升文档可能会导致挑战,特别是在文档语料库变化时。相关性是基于术语频率和术语在整个语料库中的重要性计算的。提升文档涉及调整其权重,使其在搜索结果中更突出。

    随着新文档的添加或现有文档的修改,术语频率及其重要性的整体分布可能会发生变化。这种重新校准可能会降低提升的有效性,使得在变化的数据集中保持一致的排名变得更加困难。实际上,被提升的文档可能不会像预期的那样保持突出或相关,从而导致搜索结果中的不平衡和可扩展性问题。 

  4. Lunr.js 使用 JavaScript 对象来索引和管理搜索数据,这引入了由于 JavaScript 引擎处理对象操作的方式而导致的低效。JavaScript 引擎使用内联缓存和对象形状优化等技术来优化性能。然而,这些优化依赖于可预测和一致的对象结构。

    Lunr.js 的索引动态特性——文档可以具有不同的结构——使得引擎无法有效地应用这些优化。这意味着,尽管 JavaScript 引擎可以针对固定、可预测的对象结构进行优化,但它们在处理 Lunr.js 索引的多态和流动性特征时却面临困难,导致随着数据量的增长而出现性能问题。 

  5. 在开发 项目插件 时,我们最初取得了 良好的进展,包括添加对嵌套项目的支持,并允许树状结构,其中子项目可以有进一步的子项目。然而,我们很快遇到了困难,特别是在跨项目导航方面。举例来说,想象一下每个项目可以链接到任何其他项目,这使得处理这些相互连接变得复杂,尤其是在处理循环依赖关系时——例如项目 A 链接到项目 B,反之亦然。

    在 MkDocs 中实现多项目支持特别具有挑战性,因为缺乏官方的编程 API,这使得扩展其功能的努力变得复杂。此外,在构建项目之前解决导航问题对于确保适当的互联互通至关重要。这些挑战的结合使得项目插件的开发变得复杂。 

  6. 我们的 概念验证 支持 Material for MkDocs 的某些功能,但并未涵盖所有功能。例如,集成对图标的支持或文档之间的链接将需要重新实现 MkDocs 的部分内容,以避免完全重建——这显然是我们希望避免的。此外,某些链接,例如从模式生成的博客文章链接,不仅仅是翻译,而是动态计算的,这意味着它们不能通过将 .md 扩展名替换为 .html 来推断。 

  7. 在我们再次向 MkDocs 的维护者 [提出此问题] 之后8,并且 [维护权在 2024 年中期发生变化],已开始进行 从头重写,旨在通过 仅渲染当前正在构建的页面 来解决缓慢重载的问题。目前尚不清楚此重写将如何与现有插件的要求集成。复杂的插件,例如 mkdocstrings,或我们的 内置博客标签 插件需要协调构建所有页面,以准确解析页面之间的链接和计算资源,而这在不构建整个项目的情况下是无法确定的。

    更新: 新维护者现在公开表示,他正在朝着一个 不需要或支持插件 的新版本的 MkDocs 努力,并提到它将通过提供模板、主题和样式的自定义功能同样强大,这一点他也在 8 月 1 日的团队电话会议 中提到过。在这次电话会议中,我们 [多次提出异议],关于这将如何影响生态系统,但没有得到回应。没有提供任何插件支持的意图或路线图。这一发展与我们赋予用户和组织通过模块化手段调整核心框架以满足其要求的目标是正交的。我们正在努力解决这一情况,并将为我们的社区提供前进的方向。 

  8. 之前提出的问题包括 #2418#2384#1900。 

  9. 我们正在积极调整未来的开发工作,以解决这一问题,认识到这是一个关键的改进领域。虽然这不是我们能立即交付的内容,但我们致力于在我们的工作中实现这一愿景。