# 诊断与验证

定位未渲染、命令失败、资源泄漏和复杂扩展的交互问题。

## 保留一个可复现的最小文件

问题报告应包含原始 Markdown、安装扩展及配置、模式/只读状态、复现步骤和版本。不要只截取渲染后的 HTML：源码拼写、围栏是否闭合以及选区位置都可能决定行为。

先保留未保存源码，再缩减扩展组合；同一 UI 问题可以暂时切换 source 模式判断文本是否仍正确。不要通过重新创建实例“修复”问题并丢掉撤销历史。

## 常见问题定位

| 现象 | 先检查 |
| --- | --- |
| 插件语法原样显示 | 是否安装、是否闭合、类型名是否注册、解析是否 pending |
| 自定义节点显示但不能改 | 字段验证、patch 是否实现、只读、原范围是否过期 |
| 组件不出现 | 是否使用对应 renderer，Host 是否仍在 Provider 树里 |
| 自定义代码块只有工具栏 | CodeBlock NodeView 本来只控制 header；整块预览需要 block 层 |
| 双份组件或重复安装错误 | 是否同时安装 StarterKit 的原功能和同名派生功能 |
| 切换语言后仍不高亮 | codeLanguages 是否包含精确名称/别名，加载是否失败 |
| 图表空白 | 容器尺寸、数据校验、引擎错误及加载状态 |
| 中文输入中光标跳动 | 是否在 composition 中改 DOM、抢焦点或重建 editor |
| 弹窗确认改错位置 | 是否丢失 target，或使用了旧数值偏移 |
| 只读仍有替换入口 | 控件是否读取实际 readOnly，最终是否检查命令结果 |

## 观察错误与语义

~~~ts
const options = {
  onError(error: unknown) { console.error('MSFE integration error', error) },
}
const query = editor.querySource('customContainer')
const outcome = editor.lastCommandResult
const work = editor.work
~~~

由宿主把 `onError` 接到开发诊断和产品错误边界。不要把文档正文、凭证或整个 editor 对象直接发送到外部日志服务。命令拒绝通常是可处理结果，并不都会作为异常抛出。

`querySource` 的 pending 和 unsupported 需要分别处理。工作计数适合比较同一动作前后的差值，不能把累计值当作渲染耗时；替换冲突检查 `projectionConflicts`。

## 自定义功能最低验证矩阵

| 方面 | 验证动作 | 必须成立 |
| --- | --- | --- |
| 源码 | 原样加载、模式切换、显示预览 | 未发写命令时逐字不变 |
| 写回 | 改字段、撤销、重做 | 只改声明的范围，恢复原拼写 |
| 输入 | 中文组合、删除半个 token、粘贴 | 不抢输入，未完成语法保持源码 |
| 选区 | 点击、键盘、拖过预览、搜索 | 命中正确源码，拖动过程连续 |
| 权限 | source/live 只读、locked | 不能通过组件绕过写保护 |
| 生命周期 | 快速更新、卸载、换文档 | 没有迟到结果和资源泄漏 |
| 视觉 | 深浅色、窄屏、放大文字 | 使用主题 token，控件可达 |
| 性能 | 光标移动、局部改字、长文件 | 不做无关全文扫描或全量重挂载 |

## 文档示例如何作为起点

本网站的接入源码与交互示例来自同一组文件，发布时验证依赖闭包，并对 Vue / TypeScript 示例执行类型检查。带服务端端点的 recipe 明确要求宿主实现服务，不会伪造一个成功的后端。

复制示例后，先运行其说明中的验收动作，再增加业务字段和外部请求。遇到能力边界请对照 [支持范围](/support)，不要为获得一张正确截图而关闭源码、选区或只读保护。
