记录一次把 expo-doctor 修到 17/17:Clerk + Expo SDK 54 下的 peer 依赖缺失与 native module 重复版本

这篇文章记录一次真实踩坑:expo-doctor15/17(2 项失败) 一路修到 17/17 全绿,并把“以后怎么跑”固化成一个脚本,避免每次临时设置环境变量。

适用范围(先对号入座)

  • Expo SDK:54

  • 使用:@clerk/clerk-expo

  • 包管理器:Bun(但思路对 npm/yarn/pnpm 也一样)

  • 现象关键词:Missing peer dependency / duplicate native module dependencies / expo install --check 显示正常但 expo-doctor 仍失败

TL;DR(结论先行)

  • 缺少 peer dependency:按提示把 expo-auth-session 作为应用的直接依赖安装(用 expo install 对齐 SDK 版本)。

  • native 模块重复版本:根因通常也是上面这件事(peer 没装在顶层导致依赖树里出现第二份 expo-*)。

  • expo install --check 绿但 expo-doctor expo-doctor 里还有 expo-router 的额外检查,它会对 package.json版本范围字符串做严格对比。

  • 防复发:加一个 doctor 脚本,统一入口运行。

1. 现象:为什么会报这两类错误?

运行:

bunx expo-doctor

当时出现两类问题:

  1. 缺少 peer 依赖(以 Clerk 为例)

  • Missing peer dependency: expo-auth-session

  • Required by: @clerk/clerk-expo

  1. duplicate native modules

  • expo-application / expo-constants / expo-crypto / expo-linking / expo-web-browser 出现两份

  • 一份在顶层 node_modules/expo-*

  • 另一份藏在 node_modules/expo-auth-session/node_modules/expo-*

报错输出(摘录)

这段我建议保留在博客里:后续回看能立刻对上当时发生了什么。

15/17 checks passed. 2 checks failed. Possible issues detected:

✖ Check that required peer dependencies are installed
Missing peer dependency: expo-auth-session
Required by: @clerk/clerk-expo
Advice:
Install missing required peer dependency with "npx expo install expo-auth-session"

✖ Check that no duplicate dependencies are installed
Found duplicates for expo-application:
  ├─ expo-application@7.0.8 (at: node_modules\expo-application)
  └─ expo-application@6.1.5 (at: node_modules\expo-auth-session\node_modules\expo-application)
...

2. 为什么“重装 node_modules”也不一定能解决?

很多人第一反应是删掉 node_modules 再装一遍,但这类问题往往会“原样复现”。原因很简单:

  • 重装只能清理安装产物

  • 依赖解析结果是由 package.json 的版本约束 + lockfile 决定的

expo-auth-session 没被应用显式安装、或安装方式不对齐 Expo SDK 时,它可能以“传递依赖”的形式出现,并携带一套自己的 expo-* 依赖版本。由于这些属于 native module,同一个原生构建里只能容纳一份版本,于是 expo-doctor 会要求你去重。

结论:要彻底解决重复版本,关键是让 expo-auth-session 成为应用的直接依赖,并由 Expo 帮你选择 SDK 兼容版本。

3. 修复过程(一步一步复现/验证)

Step 1:按 Expo SDK 对齐安装 expo-auth-session

client 目录执行:

bunx expo install expo-auth-session

预期变化:

  • peer dependency 的错误消失

  • expo-auth-session 相关的 expo-* duplicate 也会跟着消失(依赖树被对齐后可 hoist/去重)

当时状态从 15/17 变为 16/17。

Step 2:处理“expo install --check 没问题,但 expo-doctor 仍失败”

这里是最容易困惑的一段:

你可能看到:

expo install --check
Dependencies are up to date

expo-doctor 仍报:

✖ Check that packages match versions required by installed Expo SDK

原因:expo-doctor 不止做“Expo SDK bundled native modules”的版本校验,它还会跑 expo-router 的额外 doctor 检查。

这类检查有一个非常坑的点:它不仅看你“装了哪个版本”,还会看你 package.json 里写的版本范围字符串

例如某次直接给出了:

🔧 Patch version mismatches
package                        expected  found
@react-navigation/bottom-tabs  ^7.4.0    ^7.4.8

注意:^7.4.8 从语义上是 ^7.4.0 的子集(更严格、只允许 7.4.8 以上的 7.x),但 doctor 这里做的是“字符串/规则匹配”,因此仍可能判定为不符合期望。

处理方式:

  • @react-navigation/* 满足 expo-router 的期望范围

  • 同时把 package.json 的范围写回 doctor 期望的 ^7.4.0

Step 3:把运行方式固化成脚本(避免手动设置环境变量)

为了避免某些环境下 Node warning 输出影响 doctor 的稳定性,我们把运行入口固化为:

"doctor": "cross-env NODE_NO_WARNINGS=1 bunx expo-doctor"

以后只需:

bun run doctor

4. 最终结果

  • bun run doctor17/17 checks passed. No issues detected!

5. 本次改动点(可审计)

  • client/package.json

    • 新增:expo-auth-session(满足 @clerk/clerk-expo peer 依赖,并对齐 Expo SDK)

    • 调整:@react-navigation/bottom-tabs 版本范围回到 ^7.4.0(满足 doctor 期望)

    • 新增脚本:doctor

    • 新增 devDependency:cross-env

6. 防复发 checklist

  • 需要 Expo 原生模块时,优先使用 expo install <pkg>,不要随手 bun add/npm i

  • expo-doctor 标红时,先区分:

    • Expo SDK 依赖校验问题(expo install --check 往往能提示)

    • 其他工具链/框架的额外 doctor 校验(例如 expo-router

  • 给团队统一入口:bun run doctor(避免每个人手动设环境变量、复制命令)。

注:文章使用GPT总结