Skip to content

fix(mobile): 图标导出跨版本兼容,修 0.1.7-rc 之后移动抽屉整条失效 - #140

Open
pydsl43 wants to merge 1 commit into
shaobeichen:mainfrom
pydsl43:fix/mobile-icon-compat
Open

pydsl43 wants to merge 1 commit into
shaobeichen:mainfrom
pydsl43:fix/mobile-icon-compat

Conversation

@pydsl43

@pydsl43 pydsl43 commented Sep 25, 2026

Copy link
Copy Markdown

问题

在 dsh 0.1.7-rc.2 + dsh-pocket 2.10.6 下,手机端(Chrome Android 153,innerWidth=360)打开 DSH:

  • 左侧 56px 侧栏图标条一直占位,正文被挤成一列;
  • 侧栏不会变成抽屉,会话标题栏没有抽屉开关按钮、也没有悬浮按钮 —— 移动端适配整体失效;
  • ?dsh-layout=mobile、清 localStorage、换一个没打开过 DSH 的浏览器都救不回来(这些都不是原因)。

根因

@deepseek-ai/dsh-client-ui-primitives 在 0.1.7-rc 之后把图标导出从

IconPanelLeftOutline16 / IconDownloadOutline16 / IconFolderOpenOutline16

改成了

Icon<Name>OutlineRegular / Icon<Name>OutlineMedium

而 client/mobile/MobileNavOverlay.tsx、MobileNavToggle.tsx、MobileDrawerFooter.tsx 是直接具名导入旧名字,运行期拿到 undefined:

Error: Minified React error #130 ... args[]=undefined
slot entry crashed in 'shell.overlay': Error: Minified React error #130
slot entry crashed in 'sidebar.footer.action': Error: Minified React error #130

mobile-apply.tsx 的样式表注入在更早的 effect 里,所以 CSS 依旧注入并生效(这正是症状迷惑人的地方);崩掉的是后面三个 ctx.slots.register(...)。于是 data-mobile-nav="frame" 永远挂不上 —— 而移动样式表里所有抽屉规则都以这个标记为前缀,全部不匹配,只剩下零散的窄屏规则在起作用。

改法(跨版本兼容,不写死任何一代命名)

  • 新增 client/mobile/icon-compat.mjs:候选名列表在运行时解析(新名优先、旧名兜底);解析不到返回 null,绝不返回 undefined;
  • 新增 client/mobile/MobileIcon.tsx:拿到图标就渲染,拿不到就退化成文字字形,保证按钮永远可见可点,任何一代 DSH 上都不会再把整条 slot 打崩;
  • 三个组件改用命名空间导入 + 解析结果,源码里不再出现任何带版本后缀的图标名;
  • client/client.js 是 node client/build.mjs 的产物(本包发版流程不重新打包,必须一起提交)。

验证(运行时证据)

本机用 CDP 驱动无头 Chrome,在 360px 视口下对同一台 dsh web 复现并复验:

控制台异常 data-mobile-nav="frame" frame 计算 grid 侧栏
修复前 18 条(React #130) ❌ 无 56px 0px 0px(侧栏占轨道) 在流内可见、56px 常驻
修复后 0 条 ✅ 有 360px 0px 0px position:absolute + translateX(-211px) 出屏

复现/复验方式:node client/build.mjs 后把产物拷进 ~/.dsh/profiles/web/node_modules/dsh-pocket/client/client.js,手机/浏览器刷新即可(客户端资源每次请求现读磁盘,不需要重启 dsh web)。

测试

  • 新增 test/icon-compat.test.js(10 例):覆盖新旧两代命名、两代并存时优先新名、解析不到时的 null 兜底、非组件值(数字/字符串/null)、命名空间缺失或非对象不抛异常、兜底字形存在;并加两条护栏 —— ① 三个移动组件不得再静态引用具体图标名;② client/client.js 必须已重新打包(防「改了源码忘了打包」)。
  • npm test:其余用例全部通过。test/tunnel-args.test.js 的两个 issue [Bug] cloudflared 2026.8.2 移除 run 级 --no-autoupdate,命名/快速隧道开启即失败(code=0) #78 用例在 Windows 本机失败,已用 pristine worktree(未改动的 HEAD)对照确认修改前后同样失败 ⇒ 与本改动无关(未触及 lib/tunnel*;CI 跑 ubuntu-latest)。

备注

  • 只动客户端半,host 侧零改动;对旧版 DSH(只有 ...16)行为完全不变。
  • 若希望更保守,可以只保留「候选解析 + null 兜底」而不加文字字形,我可以按你的偏好调整。

dsh 0.1.7-rc 起 @deepseek-ai/dsh-client-ui-primitives 把图标导出从
Icon*Outline16 改成了 Icon*OutlineRegular / ...Medium。client/mobile 的三个组件
是直接具名导入,运行期拿到 undefined,组件一渲染就抛 React shaobeichen#130
("Element type is invalid ... got: undefined"),slot 条目整条崩掉:

  slot entry crashed in 'shell.overlay'
  slot entry crashed in 'sidebar.footer.action'

mobile-apply 的样式表注入在更早的 effect 里,所以 CSS 依旧生效,但
data-mobile-nav="frame" 永远挂不上 —— 移动样式表里所有抽屉规则都以它为前缀,
于是全部不匹配。手机上的可见症状:56px 侧栏图标条一直占位、正文被挤成一列,
会话标题栏没有抽屉开关、也没有悬浮按钮,移动端适配整体失效(实测 dsh 0.1.7-rc.2
+ 本包 2.10.6,Chrome Android 153 / 360px 视口,控制台 18 条 React shaobeichen#130)。

改法(跨版本兼容,不写死任何一代命名):
- 新增 client/mobile/icon-compat.mjs:候选名列表在运行时解析(新名优先、
  旧名兜底),解析不到返回 null 而绝不返回 undefined;
- 新增 client/mobile/MobileIcon.tsx:拿到图标就渲染,拿不到退化成文字字形,
  保证按钮永远可见可点,任何一代 DSH 上都不会再把整条 slot 打崩;
- 三个组件改用命名空间导入 + 解析结果,源码里不再出现带版本后缀的图标名;
- client/client.js 重新打包(本包发版不重新打包,产物必须一起提交)。

验证:CDP 驱动无头 Chrome 在 360px 视口复现/复验 —— 修复前 18 条 React shaobeichen#130、
data-mobile-nav="frame" 缺失、frame grid 为 56px+侧栏占轨;修复后 0 异常、
标记存在、grid 360px 0px 0px、侧栏 translateX(-211px) 出屏。

测试:新增 test/icon-compat.test.js(10 例,覆盖新旧两代命名 / 缺失兜底 /
非组件值 / 命名空间缺失,并加护栏:源码不得静态引用具体图标名、产物必须已重新打包)。
test/tunnel-args.test.js 的两个 issue shaobeichen#78 用例在 Windows 本机失败,已用 pristine
worktree 对照确认修改前后同样失败(与本次改动无关,未触及 lib/tunnel*)。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant