122 lines
6.4 KiB
Markdown
122 lines
6.4 KiB
Markdown
# 75 · 插件评估新增「托管友好性」与「资源成本」两个维度(2026-09-12)
|
||||
|
|
|
|||
|
|
- 日期:2026-09-12
|
|||
|
|
- 状态:📋 **标准已立(本档只立标准,未改预检脚本)**
|
|||
|
|
- 触发:`dsh-univer-office` 静态预检判 `ok` 却在平台上完全不可用,且加载成本 **+65.1 MiB** → 用户提出「把这个作为插件评估和改造的一个点」
|
|||
|
|
- 范围:**评估维度**(候选池导入预检)+ **改造规范**(自研 / 改造插件)
|
|||
|
|
- 关系:**接续档案 71**(插件兼容性预检:依赖范围 + 导出符号),本档是**新增维度**,不改变其机制与分级语义
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、为什么需要(案例暴露的两个盲区)
|
|||
|
|
|
|||
|
|
`dsh-univer-office` 在**档案 71 的静态兼容性预检里判 `ok`**(依赖与导出符号全满足)——**但它在平台上完全不可用**:
|
|||
|
|
|
|||
|
|
| 预检现状 | 案例暴露的盲区 |
|
|||
|
|
|---|---|
|
|||
|
|
| 查 semver 依赖范围 | ✅ 通过(依赖没问题) |
|
|||
|
|
| 查运行时导出符号 | ✅ 通过(符号都在) |
|
|||
|
|
| ❌ **不查「它假设的部署形态」** | 把 `http://127.0.0.1:${port}` 交给浏览器 → **托管平台必然失效,且平台侧无法补救** |
|
|||
|
|
| ❌ **不查资源成本** | 加载 `rss` **+65.1 MiB**(实测)= 实例配额的 1/6 |
|
|||
|
|
|
|||
|
|
**⇒ 兼容 ≠ 可用。** 需要补两个维度。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、新维度 A:托管友好性(Hostability)
|
|||
|
|
|
|||
|
|
### 判据(一句话)
|
|||
|
|
|
|||
|
|
> **插件的一切对外交互,是否都能走「平台已有的那一条入口」?**
|
|||
|
|
> 即:**浏览器侧只用相对路径;实例侧不依赖本机 loopback 上的网络服务。**
|
|||
|
|
|
|||
|
|
### 检查项
|
|||
|
|
|
|||
|
|
| ID | 检查 | 检测方法(复用档案 71 的 `walkJs` 框架) | 等级 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| **H1** | bundle 里出现硬编码 loopback 服务地址 | 文本扫描 `127.0.0.1:<port>` / `localhost:<port>` | 🟡 出现即警告 |
|
|||
|
|
| **H2** | **client bundle 里出现绝对 URL**(`http://` 字面量) | 只扫 client 侧产物;命中即「会交给浏览器」 | 🔴 **阻断** |
|
|||
|
|
| **H3** | 自建网络监听且非 unix socket | 扫描 `listen(` / `createServer` 参数形态 | 🟡 需人工确认是否 loopback-only |
|
|||
|
|
| **H4** | 交付浏览器的 URL 由 Host 生成,还是客户端自行拼接 | 人工研判(架构文档 + client 代码) | 🔴 若客户端自拼绝对地址 |
|
|||
|
|
|
|||
|
|
**为什么 H2 是阻断级**:绝对地址一旦交给浏览器,在托管平台上**必失效**——跨机器(`127.0.0.1` 指向用户本机)+ HTTPS 混合内容会被浏览器硬拦,**且平台侧无补救手段**(不能靠配置、不能靠反代)。这正是本案例的死因。
|
|||
|
|
|
|||
|
|
### 反面样板(本案例实测)
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
viewerUrl = `${gateway}/?file=...` // ← 交给浏览器的绝对 URL
|
|||
|
|
gateway = `http://127.0.0.1:${port}` // ← 硬编码 loopback,且被浏览器 iframe 使用
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**两条独立阻碍,缺一都打不开**:
|
|||
|
|
1. **Host → Gateway**:实例内进程 uid 100002 → `127.0.0.0/8` 被 nft `reject with tcp reset`
|
|||
|
|
2. **Browser → Gateway**:绝对 loopback URL,浏览器在用户电脑上 → **即使解封第 1 条也打不开**
|
|||
|
|
|
|||
|
|
### 正面样板(同一插件内)
|
|||
|
|
|
|||
|
|
- **Client**(浏览器模块):只走 `/univer-api/*` 同域相对路径 → ✅ 平台可反代
|
|||
|
|
- **平台自研 ×3**:加载成本 **0.0 MiB**、无自建监听 → ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、新维度 B:资源成本(Resource Cost)
|
|||
|
|
|
|||
|
|
| 项 | 判据 | 方法 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| **加载内存** | 插件 `import` 后的 `rss` 增量 | 隔离 cgroup 内逐个 `import` 实测(`node --expose-gc`,`MemoryMax` 兜底) |
|
|||
|
|
| **标注阈值** | **> 30 MiB → 标注**;**> 60 MiB → 强提示** | 同上 |
|
|||
|
|
|
|||
|
|
### 实测基线(guest 实例,2026-09-12)
|
|||
|
|
|
|||
|
|
| 插件 | rss 增量 |
|
|||
|
|
|---|---|
|
|||
|
|
| `dsh-univer-office` | **+65.1 MiB** |
|
|||
|
|
| `libsql`(间接依赖) | +7.8 MiB |
|
|||
|
|
| 平台自研 ×3(portal-entry / workspace-scoped-picker / business-plugins) | **0.0 MiB** |
|
|||
|
|
| `puppeteer-core`(仅 import 主入口、未启动浏览器) | **0.0 MiB** |
|
|||
|
|
|
|||
|
|
**⇒ 成本由「装了什么」决定,不是「装了几个」** —— 一个重型插件 ≈ 无穷多个轻量插件。
|
|||
|
|
**⇒ 平台自研插件的 0.0 MiB 是正面基线**,应作为自研插件的验收参考。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、改造规范(自研 / 改造插件必须满足)
|
|||
|
|
|
|||
|
|
| # | 规范 | 理由 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| **R-a** | **对外入口唯一**:浏览器可达面全部挂在 Host 的 webServer(同域相对路径) | 复用平台反代,零新增暴露面 |
|
|||
|
|
| **R-b** | **内部通信走 IPC**:unix domain socket 或 stdio,**不用 TCP loopback** | 不经 IP 层 ⇒ nft 管不到;天然无端口冲突 |
|
|||
|
|
| **R-c** | **不新增监听端口** | 多租户同主机下,端口 = 跨租户风险 + 端口漂移 |
|
|||
|
|
| **R-d** | **重型依赖懒加载**:原生绑定、引擎等改 `await import()` | 实测有效:`puppeteer-core` 仅 import 主入口 = **0.0 MiB** |
|
|||
|
|
| **R-e** | 交付浏览器的地址**一律由 Host 生成且为相对路径** | 绝对地址在托管平台必失效 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、落地方式(**未实施,待排期**)
|
|||
|
|
|
|||
|
|
| 步 | 动作 | 落点 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 1 | 兼容性预检加 **H1/H2** 静态扫描(复用 `walkJs`) | `dsh-server-docs/scripts/plugin-compat-check.mjs` |
|
|||
|
|
| 2 | H2 命中 → 判 `blocked`,理由「向浏览器交付绝对地址,托管平台不可用」 | 同上(沿用档案 71 的分级语义) |
|
|||
|
|
| 3 | 资源成本:预检阶段先做**静态体积提示**(解包后 `artifacts/` 体积),精确值留隔离实测 | 同上 |
|
|||
|
|
| 4 | 自研插件按 §四 规范执行(**T03 的 MCN suite 起适用**) | `交接单/T03` |
|
|||
|
|
|
|||
|
|
> ⚠️ 本档**只立标准**。改预检脚本属**生产代码变更**,须另立交接单执行(**规划与执行分离**)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、与既有档案的关系
|
|||
|
|
|
|||
|
|
| 档案 | 关系 |
|
|||
|
|
|---|---|
|
|||
|
|
| 71(兼容性预检:导入/上传即判定) | **本档是其新增维度**,机制与分级语义沿用,不替换 |
|
|||
|
|
| 66(业务插件 P0 误报 → admin 显式信任) | 本档 🟡 级沿用「放行 + 标注 + admin 可见」口径 |
|
|||
|
|
| 70(anysearch 不兼容致崩溃循环) | 同属「预检盲区导致线上事故」,本档是**系统性补盲** |
|
|||
|
|
| 74(实例内存治理:V8 堆限 256→160) | §三 资源成本维度与 74 的配额治理同源 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 七、决策记录
|
|||
|
|
|
|||
|
|
- **2026-09-12** · 用户提出「把这个作为插件评估和改造的一个点」→ 本档立标准
|
|||
|
|
- **待定**:是否立即实现 §五 步骤 1–3(需另立交接单)
|