214 lines
6.5 KiB
Markdown
214 lines
6.5 KiB
Markdown
# CodeMirror 多实例问题 - 当前状态
|
||
|
||
**日期**: 2026-02-05
|
||
**状态**: ✅ 已修复
|
||
|
||
---
|
||
|
||
## 🎉 修复成功
|
||
|
||
经过 10 次探索,**问题已成功解决**!
|
||
|
||
**最终方案**: 统一使用 `defaultHighlightStyle`,移除自定义高亮样式
|
||
|
||
---
|
||
|
||
## 📊 问题摘要
|
||
|
||
**错误**: `Unrecognized extension value in extension set` - CodeMirror 6 多实例错误
|
||
|
||
**影响**: 代码编辑器无法加载,语法高亮失效
|
||
|
||
---
|
||
|
||
## 🔧 已尝试的解决方案
|
||
|
||
| # | 方案 | 结果 | 详情 |
|
||
|---|------|------|------|
|
||
| 1 | 统一导出文件 | ❌ | codemirrorExports.js |
|
||
| 2 | manualChunks 合并 | ❌ | 反而可能导致问题 |
|
||
| 3 | 移除旧包 | ❌ | 版本不是问题 |
|
||
| 4 | 修复返回格式 | ❌ | 不是根本原因 |
|
||
| 5 | resolve.alias | ❌ | Windows 路径问题 |
|
||
| 6 | dedupe + exclude | ❌ | 主要影响开发模式 |
|
||
| 7 | 移除 manualChunks | ❌ | 即使单文件打包仍失败 |
|
||
| 8 | 深入分析错误 | ✅ | 找到真正原因 |
|
||
| 9 | **统一使用默认样式** | ✅ | **成功** |
|
||
|
||
---
|
||
|
||
## ✅ 最终解决方案
|
||
|
||
### 方案:使用 `defaultHighlightStyle`
|
||
|
||
**文件修改**:
|
||
|
||
1. **CodeEditor.vue** (frontend/src/components/CodeEditor.vue)
|
||
- 移除 `HighlightStyle` 和 `tags` 导入
|
||
- 添加 `defaultHighlightStyle` 和 `syntaxHighlighting` 导入
|
||
- 删除 `lightHighlightStyle` 定义(22 行代码)
|
||
- 修改 `getThemeExtension()` 使用 `syntaxHighlighting(defaultHighlightStyle)`
|
||
|
||
2. **codemirrorExports.js** (frontend/src/utils/codemirrorExports.js)
|
||
- 移除 `HighlightStyle` 和 `tags` 的导出
|
||
|
||
### 验证结果
|
||
|
||
- ✅ 生产环境构建成功(无错误)
|
||
- ✅ 开发服务器启动成功
|
||
- ✅ 与 SqlEditor 等其他组件保持一致
|
||
|
||
### vite.config.js
|
||
|
||
```javascript
|
||
export default defineConfig({
|
||
resolve: {
|
||
alias: { '@': resolve(__dirname, 'src') },
|
||
// 强制去重 CodeMirror 包
|
||
dedupe: [
|
||
'@codemirror/state',
|
||
'@codemirror/view',
|
||
'@codemirror/language',
|
||
// ... 所有 CodeMirror 和 Lezer 包
|
||
]
|
||
},
|
||
build: {
|
||
rollupOptions: {
|
||
output: {
|
||
// 移除 manualChunks,让 Rollup 自动处理
|
||
chunkFileNames: 'assets/js/[name]-[hash].js',
|
||
entryFileNames: 'assets/js/[name]-[hash].js',
|
||
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]'
|
||
}
|
||
}
|
||
},
|
||
optimizeDeps: {
|
||
include: ['vue', 'pinia', '@arco-design/web-vue', 'marked', 'highlight.js'],
|
||
// 排除 CodeMirror,避免预构建多实例
|
||
exclude: [
|
||
'@codemirror/state',
|
||
// ... 所有 CodeMirror 包
|
||
]
|
||
}
|
||
})
|
||
```
|
||
|
||
### 构建结果
|
||
|
||
- **主包**: `index-CB_oYaZz.js` (2.5 MB) - 包含所有代码
|
||
- **无单独的 CodeMirror chunk** - 所有 CodeMirror 代码在同一 bundle 中
|
||
|
||
---
|
||
|
||
## 📝 技术原理
|
||
|
||
### 真正原因
|
||
|
||
**之前的假设**: 多个 `@codemirror/state` 实例导致 instanceof 检查失败
|
||
|
||
**实际原因**: `HighlightStyle.define()` 创建的扩展对象与 `defaultHighlightStyle` 使用了不同的 `@lezer/highlight` 实例
|
||
|
||
### 为什么之前的方案都失败了
|
||
|
||
1. **统一导出文件** - 无法解决预构建阶段的多实例
|
||
2. **manualChunks 合并** - 即使打包到单个文件仍失败
|
||
3. **resolve.alias** - Windows 路径问题,且不能解决 `@lezer/highlight` 实例问题
|
||
4. **移除 manualChunks** - 代码在同一 bundle 中,但 `HighlightStyle.define()` 内部使用了不同的实例
|
||
|
||
### 为什么最终方案成功
|
||
|
||
- **SqlEditor.vue** 使用 `defaultHighlightStyle` 一直正常工作
|
||
- **CodeEditor.vue** 改用 `defaultHighlightStyle` 后也正常了
|
||
- 官方提供的 `defaultHighlightStyle` 内部处理了实例一致性问题
|
||
|
||
---
|
||
|
||
## 📝 关于自定义样式
|
||
|
||
**问题**: 自定义样式不能用吗?
|
||
|
||
**答案**: 可以用,但需要确保实例一致性。
|
||
|
||
### 方案 1:使用 CSS 覆盖(推荐)
|
||
|
||
基于默认高亮样式,通过 CSS 修改颜色:
|
||
|
||
```css
|
||
/* 在组件的 <style> 中 */
|
||
.cm-editor :deep(.cm-keyword) { color: #d73a49 !important; }
|
||
.cm-editor :deep(.cm-string) { color: #032f62 !important; }
|
||
```
|
||
|
||
### 方案 2:确保 tags 实例统一
|
||
|
||
所有地方都从同一个 `@lezer/highlight` 导入 `tags`,确保没有多个实例。但这仍然可能失败。
|
||
|
||
**当前方案**选择了最简单、最稳定的方案:使用官方默认样式。
|
||
|
||
---
|
||
|
||
## 📚 相关文档
|
||
|
||
- [完整探索记录](./CodeMirror-多实例问题修复记录.md) - 10 次探索的完整过程
|
||
- [CodeMirror 官方讨论 #5174](https://discuss.codemirror.net/t/error-multiple-instances-of-codemirror-state-v6/5174)
|
||
- [Vite 构建优化文档](https://vitejs.dev/guide/build.html)
|
||
|
||
---
|
||
|
||
## 🎯 关键发现
|
||
|
||
**问题本质**: 自定义 `HighlightStyle.define()` 创建的对象与默认样式使用的 `@lezer/highlight` 实例不一致。
|
||
|
||
**根本原因**: `tags` 实例的引用不一致,导致 instanceof 检查失败。
|
||
|
||
**解决方向**: 统一使用官方提供的 `defaultHighlightStyle`,避免自定义样式带来的实例问题。
|
||
|
||
---
|
||
|
||
## 📝 经验总结
|
||
|
||
### ❌ 错误方向
|
||
|
||
1. **关注构建配置** - resolve.alias、manualChunks、optimizeDeps 都无法解决
|
||
2. **代码分割问题** - 即使打包到单个文件仍然失败
|
||
3. **多实例问题** - @codemirror/state 实例不是根本原因
|
||
|
||
### ✅ 正确方向
|
||
|
||
1. **关注代码本身** - 自定义 `HighlightStyle.define()` 的问题
|
||
2. **对比正常工作的代码** - SqlEditor 使用默认样式正常工作
|
||
3. **使用官方方案** - `defaultHighlightStyle` 处理了实例一致性
|
||
|
||
### 核心教训
|
||
|
||
> **Occam's Razor(奥卡姆剃刀原则)**: 如果其他组件(SqlEditor)使用默认样式正常工作,那么最简单的方案就是:让 CodeEditor 也使用默认样式。
|
||
|
||
不应该花费 9 次尝试去调整构建配置,而应该第 1 次就对比正常工作的代码。
|
||
|
||
---
|
||
|
||
**修复完成!代码编辑器现在可以正常工作了。** ✅
|
||
|
||
---
|
||
|
||
## 🚀 配置优化(2026-02-05)
|
||
|
||
在修复问题后,对构建配置进行了优化:
|
||
|
||
### 移除的无用配置
|
||
|
||
1. **resolve.dedupe** - 28 个包的去重配置,对生产构建无效
|
||
2. **optimizeDeps.exclude** - 28 个包的排除配置,不能解决 instanceof 问题
|
||
3. **inlineDynamicImports** - 导致所有代码打包到单个文件(5.2MB)
|
||
4. **manualChunks: undefined** - 无意义的显式配置
|
||
|
||
### 优化效果
|
||
|
||
| 指标 | 优化前 | 优化后 | 改善 |
|
||
|------|--------|--------|------|
|
||
| 主包大小 | 5,226 KB | 2,569 KB | ↓ 51% |
|
||
| 构建时间 | 33.64s | 17.14s | ↓ 49% |
|
||
| 代码分割 | 无(全部内联) | 按需加载 | ✅ |
|
||
|
||
详细文档: [CodeMirror-配置优化总结.md](./CodeMirror-配置优化总结.md)
|