LV112-自动侧边栏的限制与避坑
本文是自动侧边栏系列最后一篇,汇总配置时"不看源码不知道"的限制:生成时机、忽略机制、命名约定匹配、排序规则,以及 README 与实际实现之间的偏差清单。前四篇见 总览、配置详解、filePath 模式、rewrites 模式。
一、生成时机限制
1. 启动时一次性生成
数据生成只发生在 Vite config() 钩子里,闭包变量 isExecute 保证 dev + build 全程只执行一次。因此运行期间的一切文件变动(新增、删除、改名、移动、改 frontmatter 标题)都不会反映到导航/侧边栏,必须重启 dev 服务或重新 build。改了文档标题侧边栏没变、新加的文档侧边栏没有,先重启再说。
2. restart 配置项无效
SidebarOption 类型里声明了 restart?: boolean("md 创建或删除时是否重启服务"),但 auto-nav-sidebar 没有实现对应的 configureServer 监听——这个能力只在 sidebar-resolve 版插件里存在(watcher 监听 md 增删后调 restart())。在 mist 主题下配置它没有任何效果。
3. 路径不存在时的静默兜底
扫描目录不存在时,插件不会报错,而是注入一份内置的测试数据(createTestSidebarData 里写死的 Guide/Config 等英文示例)。看到侧边栏出现一堆无关的英文条目,第一反应应该是:path 配错了或目录被移动了。
二、忽略机制
1. 默认黑名单只增不减
侧边栏与导航栏都固定忽略 ["node_modules", "dist", ".vitepress", "public"],用户 ignoreList 是追加合并([...DEFAULT_IGNORE_DIR, ...ignoreList])。没有配置项能把默认目录从黑名单里捞出来——比如想在 public 旁放文档目录,只能换名字。
2. 匹配的是名字不是路径
ignoreList 与黑名单都按条目名精确匹配(正则则 test 名字),不是路径匹配。ignoreList: ["test"] 会忽略每一层叫 test 的目录;想只忽略某一层的,用正则配合完整文件名,或用 beforeCreateSidebarItems 钩子按需过滤。
3. index.md 的三重开关
(1)根目录 index.md:scannerRootMd 分支里永远排除;
(2)各目录 index.md:mist 默认 ignoreList: ["index.md", "README.md"] 排除;不配置则目录页会以"目录名"为标题出现在侧边栏;
(3)ignoreIndexMd: true:再显式排除一层(含 .MD 大写扩展名)。
三、命名约定匹配限制
这是对 mist 文档库影响最大的一节。插件的序号体系是为 01.标题.md(数字 + 点分隔)设计的,而 mist 库统一用 LVxxx-标题.md 和 NN-中文目录(连字符),两套约定并不匹配:
1. 序号解析不认识连字符
resolveFileName 只按点(或 indexSeparator 自定义分隔符)切序号。LV001-pnpm工作区.md 解析不出数字序号 → 进无序号队列、sort 值取缺省 9999;01-开发 目录名解析不出 01 → 侧边栏目录文本原样带 01- 前缀(实测如此,本站侧边栏显示的就是 01-独立插件包)。
2. 排序侥幸正确的原因
无序号条目按 readdirSync 返回顺序进入稳定排序,readdirSync 在 Windows/Linux 上都近似字母序,而 LV001 < LV004 < LV007 的三位零填充字典序恰好等于数值序——这正是库规范强制 LVxxx 三位宽度的原因之一。一旦出现两位编号(LV99 与 LV100 混排)字典序就错乱。
3. 想要正确行为的两条路
(1)用回点分隔命名(01.标题.md):序号、标题剥离全部生效,但与库规范冲突,不推荐;
(2)frontmatter sidebarSort:给关键文档手工设排序值,或开启 sortNumFromFileName(但连字符命名解析不出序号,对 mist 库无效)。目录标题想去掉 01- 前缀,可开 titleFormMd: true 让标题取自各目录 index.md 的 frontmatter title(tdoc 生成的目录页 title 恰好是去掉序号的目录名),代价是文章标题也会转而读 md 一级标题。
4. 同名 md 抑制是隐藏行为
目录旁边存在同名 md(01-开发/ 与 01-开发.md 并存)时,目录节点被跳过。误创建同名文件会让整个目录从侧边栏消失,且只有一条不起眼的逻辑分支,排查时不容易想到。
四、排序与序号规则
(1)同序号覆盖:同一层两个文件解析出相同序号(点分隔命名下),后处理的覆盖先处理的,仅有一条警告;
(2)fileIndexPrefix 默认关闭:类型与 README 里"默认 true"不一致(见第六节),序号非法只有警告不拦截;
(3)sort 的性能账:sort: true 时每个 md 都要 readFileSync + gray-matter 解析。文档量大(几百篇)时启动耗时增加明显,纯靠文件名字典序排序的库可以关掉它换启动速度;
(4)无序号垫底:解析不出序号的条目永远排在有序号条目之后(sidebarItemsNoIndex 拼接在尾部)。
五、结构与功能限制
1. 多语言未实现
SidebarOption.localeRootDir、locales 相关的类型定义继承自 sidebar-resolve,但 auto-nav-sidebar 的 config 钩子里没有任何 locales 分支——配置了国际化的站点,各语言的侧边栏会拿到同一份数据。需要多语言侧边栏时只能用 sidebar-resolve 版插件。
2. 侧边栏 key 依赖一级目录的同前缀
rewrites 模式下侧边栏 key 取重写值的第二段,默认同一目录下所有文件的重写前缀一致(sdoc/plugin/...)。某目录下混入不同前缀的重写规则时,key 互相覆盖,部分侧边栏丢失。sidebar-resolve 提供的 checkRewritesPrefix 校验在 auto-nav-sidebar 里没有接线(类型里有、代码不读)。
3. 中文 URL 与部署环境
filePath 模式的链接带中文与空格,部署到部分静态托管(Nginx 未配编码、对象存储等)时可能 404。VitePress 内部会 encodeURI,一般场景可用,但对外分享链接不友好——这是切到 rewrites 模式(permalink 全英文)的主要动机之一。
4. 注入只认对象或数组
type: "object" 时手写 sidebar 必须也是对象,type: "array" 时必须是数组,类型不符时手写部分被丢弃(只有一条告警)。混合场景先确认手写数据的形态。
六、README 与实现的差异清单
文档(README / 类型注释)与代码行为有出入的地方,配置时以本清单为准:
| 条目 | 文档说法 | 实际行为 |
|---|---|---|
fileIndexPrefix 默认值 | README 表格写 true | 代码默认 false(序号非法仅警告) |
collapsed 默认值 | README 表格写 true | 代码默认 undefined(不折叠) |
resolveRule | 类型里有、Teek README 详述 | auto-nav-sidebar 不读此配置,模式由 __create__ 标记自动判定 |
restart | 类型注释"md 增删时重启" | 未实现(仅 sidebar-resolve 有) |
checkRewritesPrefix | 类型里有 | 未接线,配置无效 |
localeRootDir / locales | 类型里有 | 未实现,多语言不生效 |
nav-sidebar 的 getNavData(config, docsRoot) | README 示例带第二个路径参数 | 函数签名只收一个参数,第二个被忽略;根目录实际取 process.cwd() + rootDir |
| nav-sidebar 的序号剥离 | README 提到带序号文件排序 | 仅识别 ^[0-9]{2}- 两位数字 + 连字符,三位 LV001- 不剥离 |
【注意】
排查侧边栏问题的通用顺序:先 debugInfo: true 确认模式判定 → 再 saveToFile: true 拿到完整生成数据对照预期 → 最后对照本清单检查是不是踩了命名或时机限制。