212 lines
5.5 KiB
Markdown
212 lines
5.5 KiB
Markdown
# 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 分钟解决问题。**
|