Skip to content

init-vitepress 在 Node 16.14.2 项目中的兼容策略

归类:开发工具 / AI 技能 / VitePress 发生时间:2026-03-31 状态:✅ 技能定义已收敛到单一源,并补齐 Node 16 兼容策略


一、当前结论

mds skills 不是把 init-vitepress 的实现硬编码在 mds-cli 里执行逻辑,而是:

  1. 优先从远端技能仓库拉取 skill 内容
  2. 网络不可用时,回退到 mds-cli 内置 snapshot

这意味着:

  • 技能定义的单一事实来源 应该是 mdsfe-agent-workflows
  • mds-cli 负责分发、安装、snapshot 回退和本地命令入口
  • 如果要优化 init-vitepress 的行为,优先修改远端技能仓库中的对应 skill,再把 mds-cli snapshot 同步回来

一句话记住就是:

text
改技能语义,先改 agent-workflows;
改安装器、分发器、目标目录解析,再改 mds-cli。

二、为什么不能只改 mds-cli

如果只改 mds-cli 内置 snapshot,会有两个问题:

  1. 在线拉取远端 skill 的用户仍会拿到旧版 init-vitepress
  2. 远端 canonical source 和本地 fallback snapshot 会逐渐漂移

所以更稳的顺序是:

  1. 修改 mdsfe-agent-workflowsskills/<locale>/init-vitepress/
  2. 如有联动的 Node 兼容策略,同时修改 node-env-guide
  3. 推送远端仓库
  4. 回到 mds-cli 执行 npm run skills:sync
  5. 只有当你需要更新 CLI 内置 fallback 或发版时,才继续改动 / 发布 mds-cli

三、Node 16.14.2 为什么容易踩坑

init-vitepress 在老项目里最常见的坑不是“文档内容有问题”,而是下面三类环境错配:

1. 安装了只支持 Node 18+ 的 VitePress / Vite 主线

新版本 VitePress 已经依赖较新的 Vite 主线,而 Vite 5 的 engines.node 要求是:

text
^18.0.0 || >=20.0.0

这意味着把新版 VitePress 直接塞进 Node 16 项目,哪怕加了 --ignore-engines,后面也很容易在依赖解析、esbuild 二进制、运行时加载阶段继续出错。

四、推荐的三条落地路径

路径 A:现代主线

适用场景:

  • 文档运行环境已经是 Node 18+
  • 或者团队已经统一升级到了 Node 18+

推荐做法:

  • 安装 vitepress@^1
  • 配置文件优先用 docs/.vitepress/config.mjs
  • 直接使用 vitepress dev/build/preview

路径 B:Node 16 兼容主线

适用场景:

  • 项目必须稳定停留在 Node 16.14.2
  • 团队暂时不想额外维护 docs 子运行时

推荐做法:

  • 显式固定 vitepress@0.22.4
  • 不要默认升级到最新 VitePress 主线
  • 配置文件优先使用 docs/.vitepress/config.mjsconfig.js
  • 避免默认生成 config.ts

这样做的原因很直接:

  • vitepress@0.22.4 声明 engines.node >=14.0.0
  • 它更适合作为老项目的兼容文档线

路径 C:双运行时隔离

适用场景:

  • 业务代码必须继续跑在 Node 16
  • 但文档站允许单独跑在 Node 18+

推荐做法:

  • 文档命令通过包装脚本执行
  • 包装脚本里显式加载 nvm.sh 或团队标准版本管理器
  • 再执行 nvm exec 18 npx vitepress ...

五、为什么不要把裸 nvm exec 写进 package.json

这是截图里最容易被忽略、但真实非常高频的问题。

很多人会这样写:

json
{
  "scripts": {
    "docs:build": "nvm exec 18 vitepress build docs"
  }
}

看起来合理,但实际经常失败,因为:

  • npm run / yarn run 默认通过 /bin/sh 执行
  • /bin/sh 往往不会自动加载 ~/.nvm/nvm.sh
  • 于是脚本在终端里手工跑得通,在包管理器脚本里却失败

更稳的做法是显式包装:

bash
#!/usr/bin/env bash
set -e

if [ -s "${NVM_DIR:-$HOME/.nvm}/nvm.sh" ]; then
  . "${NVM_DIR:-$HOME/.nvm}/nvm.sh"
  exec nvm exec 18 npx vitepress "$@"
fi

exec npx vitepress "$@"

然后让 package.json 调这个包装脚本,而不是直接写裸 nvm exec

六、为什么默认更推荐 config.mjs

另一个很常见的问题是:

  • 老项目是 CJS 生态
  • 周边脚手架、测试器或构建器会把 config.ts 当成 CJS 或混合模块处理
  • 最后导致 VitePress 需要的 ESM 配置链路不稳定

因此在 init-vitepress 里,默认优先:

text
docs/.vitepress/config.mjs

只有当仓库已经证明自己的 ESM TypeScript 配置链路稳定时,才去生成 config.ts

七、现在这类技能应该怎么维护

推荐维护流程:

text
1. 修改 agent-workflows 中的 canonical skill
2. 推送远端
3. 在 mds-cli 中执行 npm run skills:sync
4. 如需更新 fallback snapshot 或正式发版,再处理 mds-cli

这样可以同时保证:

  • 在线拉取 skill 的用户拿到最新规则
  • mds-cli 的本地 snapshot 不落后太多
  • 技能定义不会分裂成两份长期漂移

八、可直接复用的对外说明

可以直接复用下面这段说明:

text
init-vitepress 的技能定义真源在 agent-workflows,不在 mds-cli 业务代码里。
如果要优化技能语义或兼容性,应该先改远端 skill,再同步 mds-cli snapshot。

对于 Node 16.14.2 项目,默认不要安装最新 VitePress 主线。
优先固定兼容版本线,或者把文档运行时单独隔离到 Node 18+。
另外,不要把裸 nvm exec 写进 package.json,应该通过显式包装脚本加载 nvm。

九、预防建议

  1. 不要把 mds-cli snapshot 当成技能定义真源。
  2. 对 Node 16 项目,先做版本分流,再决定装哪条 VitePress 线。
  3. 除非项目已经证明 ESM TypeScript 配置稳定,否则不要默认生成 config.ts
  4. 对需要 nvm exec 的场景,优先使用包装脚本,而不是内联到 package.json