# 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 分钟解决问题。**