client 半端

别名:__DSH_BOOT__、客户端半端、双半端、client bundle、dsh.client

一个插件可以有两半:宿主侧(在 Node 进程里跑)与客户端侧(在浏览器里跑)。客户端半端靠 package.json 的 dsh.client 声明、exports 里的 ./client 产物、以及服务端注入的 window.__DSH_BOOT__ 入口图挂进页面。

一句话

宿主半端加能力,客户端半端加界面。 两半在同一个 npm 包里分发,但跑在两个进程里:宿主侧在你启动 DSH 的那个 Node 进程里,客户端侧在浏览器里。

一个插件必须提供的三样东西

  1. package.json 的 dsh.client 声明。字段只有三个:platform(字符串,必需)、inject(字符串数组,可选,声明它依赖哪些别的客户端包先加载)、immediately(布尔,可选,表示要立刻加载而不是等图里轮到它)。缺 platform、inject 不是字符串数组、immediately 不是布尔,都会在组合阶段直接抛错。
  2. exports 里的 "./client"。服务端要把声明解析成一个真实文件路径:接受两种写法——直接给字符串,或者给一个带字符串 default 的对象。解析不到聚合报 MissingClientBundleError,并连带报出它在找哪个路径。
  3. 产物本身(惯例是 lib/client.js)。它是构建出来的浏览器 bundle,不是源码。

一个真实的声明长这样(@deepseek-ai/dsh-client-ui-theme 的 package.json):

"exports": { "./client": { "default": "./lib/client.js" } },
"dsh": {
  "client": {
    "inject": ["@deepseek-ai/dsh-client-connection", "…"],
    "platform": "web",
    "immediately": true
  }
}

从声明到页面上的脚本

服务端扫描已加载的插件行,把每个客户端半端变成入口图里的一行:

{ id, url: "/plugins/<id>/client.js?rev=<12 位 sha1>", rev, inject?, immediately? }

rev 是内容哈希,只用来破缓存。整个图会被序列化成一行脚本,插在 <head> 的最前面:

<script>window.__DSH_BOOT__ = {"rev":"…","entries":[…]}</script>

注入时会把 < 转义成 \u003c,这样插件控制的字符串不能提前闭合 script 标签。缺图或图畸形时前端选择大声失败:页面不能引导任何东西,报错比半死不活好。

三条容易踩的边界

  • 跨插件引用是构建错误:inject 决定加载顺序,但值导入(直接 import 别人模块里的对象)在打包时就被拦下。工厂里的同步 require 只能要求已经注册的包——异步加载还没落地。
  • 加载失败要可诊断:client.js 拿不到时聚合错误会列出包名与它期待的路径,别只报「插件没生效」。
  • 客户端半端不是「换界面」:它挂在某个界面里(侧边栏、设置页、输入框附近)。换掉界面本身属于客户端形态,见「界面与客户端」分区。

与安全的关系

客户端半端是第三方代码在你的浏览器里跑,和宿主半端一样在同一个信任面上。发布前请按规范检查:只有 exports 与 dsh.client 声明得干净,加载顺序才是确定的。插件安装与加载的完整链路见 tutorial/3。

出处

  • 声明解析与入口图:@deepseek-ai/dsh-client-modules 的 lib/index.js(parseDshClient、clientExportOf、graphRow、injectBootManifest)。
  • 浏览器侧解析边界:同包 lib/client.js 的 parseBootManifest。
  • 真实声明样本:@deepseek-ai/dsh-client-ui-theme 的 package.json(dsh.client 三个字段齐全)。
  • 插件侧另一样本:dsh-pack-plugin 的 package.json(dsh.bundle.patch + dsh.client 同时声明,见 plugin/2)。

相关教程

谁引用了这一条

信息表

category
concept.plugin
layer
plugin
spec
~/.dsh/profiles/node_modules/@deepseek-ai/dsh-client-modules/lib/index.js(parseDshClient / graphRow / injectBootManifest)与 lib/client.js(parseBootManifest)
updatedAt
2026-10-02

标签:插件、机制、界面