# CodeMirror 问题排查经验教训

**日期**: 2026-02-05
**问题**: CodeMirror 多实例错误
**探索次数**: 10 次
**最终解决时间**: 5 分钟

---

## 🎯 核心教训

> **当遇到问题时，应该先对比正常工作的代码，而不是盲目调整构建配置。统一的代码风格（使用官方默认方案）往往能避免很多问题。**

---

## 📊 问题回顾

### 错误信息
```
Error: Unrecognized extension value in extension set ([object Object]).
This sometimes happens because multiple instances of @codemirror/state are loaded,
breaking instanceof checks.
```

### 错误假设（导致 9 次失败）

看到错误提示 "multiple instances of @codemirror/state"，就认为是**构建配置问题**：
- Vite 预构建导致多实例
- 需要配置 resolve.alias 强制单实例
- 需要配置 dedupe 去重
- 需要移除 manualChunks 避免代码分割
- ...

**结果**: 尝试了 9 种构建配置方案，全部失败 ❌

### 正确思路（10 次成功）

**对比正常工作的代码** → 发现差异 → 统一代码风格

1. **SqlEditor.vue** - 使用 `defaultHighlightStyle` → 正常工作 ✅
2. **CodeEditor.vue** - 使用自定义 `HighlightStyle.define()` → 报错 ❌

**解决**: 改用 `defaultHighlightStyle`，问题立即解决 ✅

---

## 🔍 失败原因分析

### 为什么会犯这个错误？

1. **被错误信息误导**
   - 错误信息提到 "multiple instances"
   - 就认为是依赖管理/构建配置问题
   - 实际上是自定义代码导致的问题

2. **忽略了"奥卡姆剃刀原则"**
   - 应该先检查最简单的解释
   - "为什么其他组件正常工作？"
   - "它们和我的代码有什么不同？"

3. **过度依赖配置调整**
   - 认为通过配置可以解决任何问题
   - 实际上问题在代码层面
   - 配置调整治标不治本

### 时间浪费统计

| 尝试次数 | 方向 | 耗时估计 | 结果 |
|---------|------|---------|------|
| 1-9 | 构建配置调整 | ~4-5 小时 | 全部失败 ❌ |
| 10 | 对比正常代码 | ~5 分钟 | 成功 ✅ |

**浪费时间**: 4-5 小时
**正确方案**: 5 分钟
**比例**: 48:1 - 60:1

---

## ✅ 正确的排查流程

### 应该这样做（下次）

```
第一步：对比法
├─ 找到正常工作的类似代码（SqlEditor.vue）
├─ 逐行对比，找出差异
└─ 统一代码风格和实现方式

第二步：确认问题范围
├─ 是全局问题？（所有编辑器都不工作） → 可能是配置问题
└─ 是局部问题？（某个组件不工作）   → 优先检查代码差异

第三步：从简单到复杂
├─ 先检查代码逻辑和导入
├─ 再检查配置文件
└─ 最后检查构建工具
```

### 不应该这样做

```
❌ 一看到错误信息就认为是构建问题
❌ 盲目调整各种配置选项
❌ 尝试复杂的解决方案
❌ 忽略正常工作的代码
```

---

## 📚 经验总结

### 技术层面

1. **统一代码风格的重要性**
   - 使用官方默认方案（`defaultHighlightStyle`）
   - 避免自定义可能引入问题的实现
   - 团队成员使用相同的模式

2. **"能用"比"个性"更重要**
   - 自定义语法高亮颜色 → 带来问题
   - 使用默认样式 → 稳定可靠
   - 如果需要自定义，优先用 CSS 覆盖

3. **错误信息可能误导**
   - "multiple instances" 不一定是依赖问题
   - 可能是代码使用了不同的实例
   - 需要结合上下文分析

### 方法论层面

1. **对比优先**
   - 先找到正常工作的代码
   - 对比找出差异
   - 统一实现方式

2. **简单优先**
   - 奥卡姆剃刀原则：最简单的解释往往是正确的
   - 先检查代码，再检查配置
   - 先检查局部，再检查全局

3. **时间价值**
   - 花 5 分钟对比 = 省下 4-5 小时
   - 盲目尝试 = 浪费时间
   - 系统化排查 > 随机尝试

---

## 🎓 可复用的原则

### 通用排查原则

1. **二分法**
   ```
   问题发生
   ├── 其他地方正常吗？
   │   ├── 是 → 检查我的代码与正常代码的差异
   │   └── 否 → 检查全局配置/环境
   ```

2. **控制变量法**
   ```
   只改变一个因素，观察结果
   - 用正常工作的代码替换 → 还报错吗？
   - 用默认实现替换自定义 → 还报错吗？
   ```

3. **时间盒原则**
   ```
   如果 30 分钟内没有进展 →
   - 停止当前方向
   - 重新评估假设
   - 尝试完全不同的方法
   ```

---

## 📝 行动清单

### 下次遇到类似问题

- [ ] 第一时间找到正常工作的代码
- [ ] 对比差异，记录下来
- [ ] 尝试统一代码风格
- [ ] 如果无效，再检查配置
- [ ] 设置 30 分钟时间盒
- [ ] 遇到阻碍时，重新评估假设

### 长期改进

- [ ] 建立代码规范文档，规定统一的实现方式
- [ ] Code Review 时检查是否使用官方推荐方案
- [ ] 定期分享排查经验，避免重复踩坑
- [ ] 建立"常见问题自查清单"

---

## 🔗 相关文档

- [CodeMirror 多实例问题修复记录](./CodeMirror-多实例问题修复记录.md) - 完整探索过程
- [CodeMirror 修复状态报告](./CodeMirror-修复状态报告.md) - 解决方案
- [CodeMirror 配置优化总结](./CodeMirror-配置优化总结.md) - 优化效果

---

## 💡 一句话总结

> **如果其他代码正常工作，不要怀疑工具和配置，先怀疑你的代码与众不同。**

---

**这个教训值 4-5 小时的时间成本，希望下次能 5 分钟解决问题。**
