mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-30 04:40:37 +00:00
30 lines
5.8 KiB
Markdown
30 lines
5.8 KiB
Markdown
# @deepseek-ai/dsh-client-modules
|
||
|
||
[English](README.md) | 中文
|
||
|
||
客户端模块系统:Node 内部 ESM loader 的浏览器端对等实现,以惰性 CJS 表实现。web 外壳挂载 vendored cordis Loader 来治理配置项(fiber 生命周期、inject 等待、update/refresh),并通过其 `internal` 约定注入该包的 `ClientModuleLoader`;vendored 一侧唯一的消费点是 `EntryTree.import`,因此替换 `internal` 恰好只会替换「插件代码如何到达」,不会改变其他内容。
|
||
|
||
惰性 CJS 模型(web2):执行插件 bundle 只会注册其 factory(`window.__ModuleLoader__.load({id, factory})`);每个模块主体的副作用(包括 CSS 注入)都位于 factory 闭包中,在物化时运行(`factory(require)` → 导出表层,并在 `loadCache` 中记忆化),不会在脚本执行时运行。如果 factory 依赖另一个已注册但尚未物化的模块,系统会递归物化它;图组合会把声明的动态请求提供方放在消费者之前,而 require 循环会抛出异常,因为 factory 形式的 CJS 无法提供部分导出。`<id>/client` 与裸 id 指向同一表层(一个插件 bundle 就是其包的客户端侧)。
|
||
|
||
Host 会先安装 `window.__ModuleLoader__`、预加载所有 application combo 脚本,再执行阻塞 parser 的 bootstrap combo 脚本。`bootstrap` 与 `application` 只是调度阶段,不会成为 URL 路径名,并且每个阶段都可以包含多次请求。Queue 模式的 `load()` 保存 modules registration;`create()` 使用拒绝 external 的 bootstrap require 物化本包 factory,并调用其 `createClientModuleSystem` 导出。构造过程把同一组导出缓存为 modules row,并把同一个 facade 切换到 live registration。Bundle 通过模块闭包保留生成的系统,因此随后 Cordis `apply()` 能把同一实例提供为 `ctx.modules`,无需另一个页面全局变量。
|
||
|
||
解析分支顺序(`import(specifier)`):平台种子词 → 外壳实例;记忆化记录 → 导出;模块图记录(`window.__DSH_BOOT__`)→ 登记其初始 combo 中的 factory;已登记 factory → 物化;其他情况一律抛出异常。这是构建时 bundle 纯度门禁的运行时镜像。交给 factory 的同步 `require` 采用相同顺序,但不含异步 graph-row 加载分支,并把观察到的边记录到模块记录中。`prefetch` 是第一阶段到达钩子;共享同一初始 combo URL 的 row 会共享一个进行中的脚本任务。`invalidate(id, rev)` 会丢弃非 bootstrap factory 与物化记录,并让该 row 改用带 revision 的单资源 combo URL,因此 HMR(热模块替换)只重载一个插件,不会再次执行初始多资源脚本。
|
||
|
||
Node 侧会扫描已启用的 Loader 配置项以发现 web `dsh.client` 包,解析并快照每个 `exports["./client"]` 及其可用 sourcemap,携带包专属 `dsh.client.external` 请求,并把动态提供方排在消费者之前。它把 modules row 调度为 bootstrap,把其余 row 调度为 application。初始传输与 HMR 使用同一条 combo 路由:任意非空资源列表都写成 `/plugins/??<package-a>/client.js,<package-b>/client.js&rev=<rev>`,HMR 单资源重载也不例外。图组合会在更长的 map 形式 URL 超过 3 KiB 前,按顺序贪心切分每个阶段的资源,因此大型 application 会产生多次请求,但路径模型不变。脚本中的绝对 `sourceMappingURL` 把各自的资源列表平行改写成 `/plugins/??<package-a>/client.js.map,<package-b>/client.js.map&rev=<rev>`。每个生成的 map 都是 Indexed Source Map v3:插件有自带 map 时直接用于对应 section;没有时则生成 identity section,内嵌构建后 bundle,并在存在打包路径时命名为其 `lib/client.js`,因此一个 combo 仍能拆回各组件文件。初始逐插件 revision 使用不透明的进程 nonce,因此启动时不会哈希每个插件;HMR 只哈希 watcher 报告发生变化的产物。每个已发布响应都不可变,未发布的组合或 revision 返回 404,绝不提供其他字节。源码启动会把宿主侧导入映射到 TypeScript 源码,但仍消费这些构建后的客户端导出;缺失文件共享一条构建说明,随后以包/路径列表列出各项,而无关的文件系统错误仍是独立故障。
|
||
|
||
`dsh.client.external` 是外壳播种的 React、Cordis 和静态 UI 库这一统一基座之外的可选精确 specifier 请求列表。请求由其命名的动态 package row 或精确静态表键回答;只有末尾 `/client` 会别名到 package row,并且不存在 provider 别名声明。纯类型 import 会被擦除,不产生请求。组合阶段会拒绝畸形请求、缺失提供方、自请求和同步请求环;import 与 prefetch 会在消费者物化前递归登记动态提供方。参见[共享模块与模块图](../AGENTS.md#shared-modules-and-the-module-graph)。
|
||
|
||
## 模型体验
|
||
|
||
无。模块 loader 属于浏览器侧内核机制;这里没有任何内容进入模型请求。
|
||
|
||
#### KV Cache 影响
|
||
|
||
无;该包既不组装也不发送提供方请求。
|
||
|
||
## 已知限制与暂缓事项
|
||
|
||
- **有意采用扁平模块图**:每个 bundle 是一个模块节点,其边只指向表中的叶节点;接口(`loadCache`/`edges`/`invalidate`)已经支持通用模块图,因此可以改变 externalization 粒度而不更改接口。
|
||
- **自身不维护卸载记录**:样式移除与 fiber 拆卸顺序属于 HMR 驱动器(`@deepseek-ai/dsh-client-hmr`);loader 只在每条记录中登记其拥有的样式标签 id。
|
||
- **快照式提供会常驻产物字节**:Host 会在内存中保留每个 bundle、可选 sourcemap、生成的单资源响应及当前启动 combo 响应;HMR 还会保留上一代启动响应。内存会随组合出的客户端产物增长为数份副本,以换取 immutable 响应和一代竞态容忍。
|