MkDocs 实测:从 mkdocs new 到中文界面,Windows 下这六个坑我全踩了
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 分支(本文只介绍命令,未实际执行推送)。
五、六个坑(实际遇到的)
theme.locale: zh-CN直接启动失败:报ERROR - Config value 'theme': Invalid value for locale: ...,随后Aborted with a configuration error!。合法值是下划线格式zh_CN,不是 web 常见的连字符zh-CN;!!!提示块原样输出:页面里写!!! tip "标题",构建后 HTML 里它就是一个普通段落,完全没有提示框样式。原因是默认扩展列表里没有admonition,需显式加markdown_extensions: [admonition, pymdownx.details, pymdownx.superfences](???折叠块同理);- 加了扩展却报
ModuleNotFoundError: No module named 'pymdownx':MkDocs 本身并不依赖 pymdownx(pip show mkdocs的 Requires 列表里没有 pymdown-extensions)。对策:pip install pymdown-extensions; - 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 在进程启动、首次 importlocalization模块那一刻就用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。) - 端口被占用时 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。) - 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。
- 点赞
- 收藏
- 关注作者
评论(0)