MkDocs 实测:从 mkdocs new 到中文界面,Windows 下这六个坑我全踩了

举报
岚枫 发表于 2026/10/22 09:48:47 2026/10/22
【摘要】 实测 MkDocs 1.6.1 搭文档站:new/build/serve,admonition 提示块不渲染、中文界面要补装 babel、端口被占时服务假启动,六个坑附复现与对策。

MkDocs 实测:从 mkdocs new 到中文界面,Windows 下这六个坑我全踩了

每个项目都有一份滚不到底的 README,wiki 又和代码各过各的。MkDocs 的思路很直接:一个 docs/ 文件夹放 Markdown,一个 mkdocs.yml 管全站配置,mkdocs build 出来就是带导航、带搜索、能热重载的纯静态站点。Python 生态出身,pip 一把装完,BSD-2-Clause。

但我在 Windows 上从 mkdocs new 一路跑到中文界面,连踩了六个坑——包括 mkdocs 1.6 默认不渲染提示块、端口被占用时服务"假启动"这种不实测根本不知道的。这篇是全流程实录,每个坑都附复现与对策。

一、它解决什么问题

项目文档的老三样:README 越写越长、wiki 更新永远滞后、Sphinx 配置门槛高。MkDocs 把这三个问题压缩成一条流水线:

docs/*.md --(mkdocs.yml 配置)--> mkdocs build --> site/ 纯静态文件

产出是纯 HTML/CSS/JS,任何静态托管都能放;开发时 mkdocs serve 起本地服务,保存 Markdown 自动重建刷新。对 Python 项目尤其友好:不依赖 Node 生态,一个 pip 包就是全部。

二、核心概念:mkdocs.yml / nav / theme / plugins

整个系统只有四个概念,全部收在 mkdocs.yml 一个文件里:

  • site_name / theme:站点标题和皮肤。内置 mkdocs 主题即可用,theme.locale 控制界面语言;在内置 mkdocs 主题里,theme.navigation_depth(默认 2)只控制右侧「本页目录(TOC)」的展开层级,左侧导航树的层级完全由 nav 自身决定。换 readthedocs 主题时它的含义会变,那边默认 4、管的是左侧导航树的展开深度。我在配置里写 navigation_depth: 2 只是显式标一下默认值;
  • nav:左侧导航树。YAML 缩进即层级,不需要写代码;
  • markdown_extensions:Markdown 扩展开关。这是最容易踩的地方:MkDocs 1.6.1 源码 config/defaults.py 里的默认扩展只有 toc、tables、fenced_code 这三个,admonition 不在其中,文档里常见的 !!! 提示块语法默认不渲染;
  • plugins:搜索插件默认开启,构建时生成 site/search/search_index.json 索引;查询用的 lunr 脚本由搜索插件一起拷进 site/search/,它属于插件运行库,不是索引文件本身。纯前端检索,无后端依赖。

三、我的实测:从 mkdocs new 到四个页面全部 200

实测环境:Windows 10 + Python 3.13.14。安装与版本(真实输出):

$ python -m pip install mkdocs
$ python -m mkdocs --version
python -m mkdocs, version 1.6.1 from <venv>\Lib\site-packages\mkdocs (Python 3.13)

mkdocs new my-docs 生成的骨架只有两个文件(真实输出):

INFO    -  Creating project directory: my-docs
INFO    -  Writing config file: my-docs\mkdocs.yml
INFO    -  Writing initial docs: my-docs\docs\index.md

初始 mkdocs.yml 全文只有一行 site_name: My Docs,docs/index.md 是欢迎页模板。我在这个骨架上自写了四页内容(首页、快速开始、Windows 排错笔记、配置参考),mkdocs.yml 改成(真实内容):

site_name: 本地技术笔记
site_description: 一次 MkDocs 完整实测搭起来的静态文档站

theme:
  name: mkdocs
  locale: zh_CN
  highlightjs: true
  navigation_depth: 2

extra_css:
  - extra.css

markdown_extensions:
  - admonition
  - pymdownx.details
  - pymdownx.superfences

nav:
  - 首页: index.md
  - 使用指南:
      - 快速开始: guide/getting-started.md
      - Windows 排错笔记: guide/windows-tips.md
  - 配置参考: reference/config.md

构建(真实输出,nav 里两个页面还没建时的 WARNING 也如实保留):

INFO    -  Cleaning site directory
INFO    -  Building documentation to directory: <临时目录>\blog-mkdocs\my-docs\site
WARNING -  A reference to 'guide/windows-tips.md' is included in the 'nav' configuration, which is not found in the documentation files.
WARNING -  A reference to 'reference/config.md' is included in the 'nav' configuration, which is not found in the documentation files.
INFO    -  Documentation built in 0.18 seconds

补齐页面后最终构建干净通过,零警告,产物含 4 个页面 HTML、主题静态资源和搜索索引。

起本地服务并验证(真实命令与结果):

$ python -m mkdocs serve -a 127.0.0.1:8123
INFO    -  Building documentation...
INFO    -  [09:13:35] Watching paths for changes: 'docs', 'mkdocs.yml'
INFO    -  [09:13:35] Serving on http://127.0.0.1:8123/

$ curl -s --noproxy '*' -o /dev/null -w "GET / -> %{http_code}\n" http://127.0.0.1:8123/
GET / -> 200

注意带时间戳前缀的 [09:13:35] 只出现在 livereload 模块发的这几行(Watching paths、Serving on、热重载时的 Detected file changes),而 Building documentation... 这类走普通 logger、没有前缀。

四个页面加自定义 CSS 全部 200,标题也核对过:<title>本地技术笔记</title>、<title>快速开始 - 本地技术笔记</title>、<title>Windows 排错笔记 - 本地技术笔记</title>、<title>配置参考 - 本地技术笔记</title>。渲染细节同样验证到位:提示块变成 <div class="admonition tip"> 加标题段落,折叠块变成 <details class="note"> 加 <summary>。

四、配置进阶:nav 嵌套、搜索、主题定制与部署

nav 嵌套:YAML 缩进即层级,nav: 下列一级条目,子条目比父项多缩进、同层对齐即可(上面示例里二级项用的是相对父项 4 空格),不需要任何插件(「使用指南」就是真实可用的两级导航)。

搜索:默认开启,无需配置。构建产物里的 site/search/search_index.json 就是全文索引;内置主题把搜索做成导航栏上的一个 Search 按钮,点开是一个 modal 弹层,输入框就在弹层里,配 theme.locale: zh_CN 后按钮和 placeholder 会翻成中文「搜索...」(前提见坑 4)。

主题定制:不换第三方主题,只用 extra_css 注入自定义样式。我在 docs/extra.css 写了(真实内容):

.hero-card {
  border: 1px solid #d0d7de;
  border-left: 4px solid #2980b9;
  border-radius: 6px;
  padding: 0.8em 1em;
  margin: 1em 0;
  background: #f6f8fa;
}

在首页用 <div class="hero-card"> 引用,curl 验证 HTML 里 <link> 注入成功、class="hero-card" 原样出现在页面上,CSS 文件本身返回 200。想更漂亮可以换 Material 主题(第三方,需另装),本次用的是内置主题,克制够用。

部署:mkdocs build 产物 site/ 传到任何静态托管即可。GitHub Pages 有一条捷径命令 mkdocs gh-deploy,它会构建并通过 ghp-import 推送到 gh-pages 分支(本文只介绍命令,未实际执行推送)。

五、六个坑(实际遇到的)

  1. theme.locale: zh-CN 直接启动失败:报 ERROR - Config value 'theme': Invalid value for locale: ...,随后 Aborted with a configuration error!。合法值是下划线格式 zh_CN,不是 web 常见的连字符 zh-CN;
  2. !!! 提示块原样输出:页面里写 !!! tip "标题",构建后 HTML 里它就是一个普通段落,完全没有提示框样式。原因是默认扩展列表里没有 admonition,需显式加 markdown_extensions: [admonition, pymdownx.details, pymdownx.superfences](??? 折叠块同理);
  3. 加了扩展却报 ModuleNotFoundError: No module named 'pymdownx':MkDocs 本身并不依赖 pymdownx(pip show mkdocs 的 Requires 列表里没有 pymdown-extensions)。对策:pip install pymdown-extensions;
  4. locale 配了中文界面还是英文:theme.locale: zh_CN 写好后,<html lang="zh_CN"> 属性是设上了,但按钮仍是 Next/Previous、搜索框仍是 Search...,而且全程一条警告都没有,只能靠肉眼看文案。别把 lang 属性当成翻译生效的证据:没装 babel 时 MkDocs 走自带的占位 Locale,它只能拼出 zh_CN。界面翻译依赖 babel,而它不是 MkDocs 默认依赖(对策:pip install "mkdocs[i18n]")。装上 babel 后必须重启 serve:真正卡点是 MkDocs 在进程启动、首次 import localization 模块那一刻就用 try: from babel... 把「有没有 babel」定死了;热重载只会重建文档、不会重新 import 这个模块,所以不重启等于没装。重启后 lang 才变成 zh_Hans_CN(babel 给 zh_CN 补了 script=Hans,这才是翻译真正加载的标记),Next 变「下一章」、Close 变「关闭」。(顺带一个同根坑:把 locale: zh_CN 写在顶层而不是 theme: 下面,只会得到一条 WARNING - Config value 'locale': Unrecognised configuration name: locale,构建照常成功、界面照常英文——1.6 的正确键是 theme.locale。)
  5. 端口被占用时 serve 可能"假启动":我遇到的现象是:127.0.0.1:8125 上已经跑着一个 python -m http.server,再起 mkdocs serve -a 127.0.0.1:8125 不报任何错,日志照常打印带时间戳的 [09:xx:xx] Serving on http://127.0.0.1:8125/,但 curl 该地址拿回来的却是那个目录列表页(<title>Directory listing for /</title>),不是文档站。原因出在 socket 选项:mkdocs serve 的 LiveReloadServer 继承自 wsgiref 的 WSGIServer,而它从 http.server.HTTPServer 拿到 allow_reuse_address = 1;http.server 同样如此。两个都开了 SO_REUSEADDR,Windows 上就不会抛「地址已被占用」,日志里的 Serving on ... 只说明本地进程自己绑成功了,到底哪个 socket 接到连接、curl 拿到谁的页面并不确定(实测下来往往是先占者赢)。占端口的不一定是别的程序,一个上次没关干净的 mkdocs serve 自己也能撞上,判据是 netstat -ano | findstr ":8125" | findstr LISTENING 出现两行、PID 还不同。对策:起 serve 后别只信日志,用 curl 或浏览器核对页面标题确实是自己站点。还有个同源坑:mkdocs serve 的产物压根不落在项目下的 site/,它写进一个 tempfile.mkdtemp 临时目录,正常退出/Ctrl+C 时才删(直接强杀会在 %TEMP% 留下一堆 mkdocs_*)。所以想用 site/ 里的文件去排查 serve 的问题,方向从一开始就错了,只有 mkdocs build 才产出 site/。(对比:没开 SO_REUSEADDR 时端口被占会报 WinError 10048;端口落进 Windows 系统保留区间或被拦才报 WinError 10013。)
  6. curl 本地请求被代理拦截:本机 curl 有代理变量,请求 http://127.0.0.1:8123/ 返回 502(upstream connect failed)。加 --noproxy '*' 才拿到真实响应。

六、适合谁,边界在哪

适合:Python 项目想要一份跟代码同仓的文档;个人知识库/笔记站点;不想引入 Node 生态的团队内部文档;会一点 YAML 和 Markdown 就能上手。

边界:内置主题比较朴素,漂亮 UI 要上第三方 Material 主题;本次未验证 Material 主题、mkdocs gh-deploy 真实推送、CI 自动构建部署;多语言站点需要额外插件;页面量大时搜索索引体积会涨(本次四页无感)。MkDocs 不自带 pymdownx,界面翻译又需要额外的 babel,照着「装完就能出中文界面、出提示块」的旧教程配会连续踩坑 2/3/4。搭站本身不难,费时间的是摸清这些依赖和默认值的边界。


参考与署名:本文实测项目为 mkdocs/mkdocs(BSD-2-Clause,实测版本 mkdocs 1.6.1,附装 pymdown-extensions 12.2 / babel 2.18.0);文中配置与页面代码均为本次实跑自写;运行环境 Python 3.13.14 / Windows 10。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。