✨ Highlights

本版本闭合了针对 0.8.10–0.8.12 报告的三个问题的循环:#175 GH Pages 资源路径回归、#177 离线模式 <base> 破坏、以及 #167 离线链接重写。三者的根本原因都是 <base> 标签的判定分散在各个模板中——0.8.13 让生成器成为唯一的真相之源。

另外,自动安装重试路径在 Linux CI 上不再失败于 @docmd/template-summerdocmd-search 和其他按需依赖,因为安装后的加载现在使用手动 node_modules 遍历,绕过了 Node 陈旧的 require.resolve 缓存。

无破坏性变更。无需新的必需配置。现有的配置、插件和 CI 流水线均可继续工作。

🐛 修复:<base> 标签判定在生成器中集中(#175、#167、#177)

0.8.10 在布局模板中添加了一个无条件的 <base href="/">。这修复了一个工作区资源问题,但同时又破坏了其他三件事:

  • #175(GH Pages 子路径):当用户设置 url: "https://user.github.io/repo" 时,<base> 应该是 "/repo/" 而非 "/"。0.8.10 修复了子路径的情况,但根部署的情况仍然发出不必要的 <base href="/">
  • #167(离线链接重写):Markdown 后处理器在离线模式下正确地将 /destination/ 重写为 ./destination/index.html,但 <base href="/"> 随后告诉浏览器通过 file:// 将这些相对路径重新定位到文件系统根。链接在 HTML 源码中"有效",但在浏览器中返回 404。
  • #177(离线 CSS/资源):由于同样的原因,从磁盘打开 site/index.html 产生无样式页面——<base> 重新定位 ./assets/css/... 到文件系统根,导致 404。

修复(0.8.13):生成器现在根据 (isOfflineMode, siteRootAbs) 计算规范 <base> 判定,并在模板渲染后应用。模板本身不再发出 <base>。判定表:

场景 发出 <base> 原因
build(在线,根部署) 相对 URL 相对于文档 URL 解析,这正是我们想要的
build(在线,GH Pages 子路径) <base href="/repo/"> 浏览器需要知道它处于子路径中
build --offline file:// 解析必须使用文档相对路径
file://(直接磁盘查看) n/a 搜索客户端显示有帮助的离线消息

现有用户无需进行模板编辑——构建输出现在默认正确。除非您依赖模板发出自己的 <base>(官方模板没有这样做),否则此更改不可见。

🔧 自动安装重试现在能绕过 Node 陈旧的 resolve 缓存

自动安装路径(tryLoadAfterInstall)对安装后的加载使用纯粹的 import(packageName)。在 Linux CI 上,即使 npm install 已将包放在 node_modules 中,Node 内部的 require.resolve 缓存仍返回陈旧的"未找到"。结果是:构建成功安装了 @docmd/template-summerdocmd-search,然后失败并报 Could not load @docmd/template-summer after auto-install(这是破坏 0.8.12 中 GH Pages 部署的 CI 错误)。

修复:新的 manualResolvePackageEntry() 用全新的 fs.existsSync() 检查遍历 node_modules 目录树,完全绕过 Node 的 resolve 缓存。新流程是:

  1. 尝试 createRequire(consumerCwd).resolve(name)(快速,遵守 exports 字段)。
  2. 如果失败,从 consumerCwd 向上搜索 node_modules/<name>/package.json(可靠,无缓存)。

另外,新的环境变量 DOCMD_INSTALL_VERSION 覆盖 npm install <name>@<version> 中使用的版本,允许用户锁定到特定版本或使用 latest,无论本地安装的是什么。

🐛 修复:搜索客户端在 file:// 下显示有用的消息

关键字搜索和语义搜索都使用 fetch() 加载索引文件。浏览器出于 CORS 原因阻止从 file:// URL 进行 fetch(),因此从磁盘打开 site/index.html 时显示 Failed to load search index.——一个误导性的错误消息,让人觉得有什么东西坏了。

0.8.13 在任何 fetch 之前检测 window.location.protocol === 'file:',并显示清晰的消息:

Search requires a web server. Open this site via http://localhost instead of file:// to enable search.

这使限制变得明确,而不是让用户去猜为什么他们的搜索在离线时"不工作"。真正的离线索引是一个独立的功能(如果需要请单独跟踪)。

🧹 测试和 lint 清理

  • eslint.config.mjs 现在忽略 _ 前缀的变量/参数/捕获的错误(标准约定)
  • tools/prep.js 测试运行器实时流式传输测试输出,而不是静默捕获
  • tools/simulate-consumer.mjs 空 catch 块有解释性注释
  • packages/plugins/openapi/ 删除了一个死代码 const r = ... 绑定和一个过时的 eslint-disable 指令
  • prep.js 删除了死代码 summariseTests() / extractFailures() 辅助函数(用流式传输替代)

迁移

零。现有的配置、插件和 CI 流水线均可继续工作。对于任何 url 配置与实际部署 URL 匹配的站点,<base> 变更完全向后兼容。

完整变更日志https://github.com/docmd-io/docmd/compare/0.8.12...0.8.13