在 Vite+Vue3 项目中集成 Monaco Editor

最近接到一个需求,需要将系统中的文本预览功能迭代成在线代码编辑器形式,支持行数显示、代码高亮、主题配置等功能。经调研后,选择了功能强大的 Monaco Editor。作为 VS Code 背后的代码编辑器核心,完成这些功能绰绰有余,后续也很方便扩展新的功能。

本以为照着教程做很简单,但在开发过程中,还是遇到了一些问题。现将开发的重点和问题的解决方案整理如下,希望对大家有帮助。

安装和初始化

bash 复制代码
# 安装依赖
pnpm i monaco-editor
ts 复制代码
// 初始化
import { ref, onMounted, watch, onBeforeUnmount } from 'vue';
import * as monaco from 'monaco-editor';

const editorContainer = ref(null); // 绑定容器元素节点
const editorInstance = ref(null);

const languageMap = {
  js: 'javascript',
  ts: 'typescript',
  // 其他语言映射...
};

// 创建编辑器实例
onMounted(() => {
  editorInstance.value = monaco.editor.create(editorContainer.value, {
    value: props.value,
    language: languageMap[props.language] || 'plaintext',
    theme: 'vs-dark',
    automaticLayout: true,    // 窗口resize时自适应
    readOnly: true, // 是否设置为只读模式
  });
});

// 组件卸载时销毁实例
onBeforeUnmount(() => {
  if (editorInstance.value) {
    editorInstance.value.dispose();
  }
});

设置好容器,传入文本内容和对应的代码语言参数,初始化后,编辑器就会显示在页面中了。

大文件分片加载优化

因项目中可能会有较大体积的文本预览需求,需要做文件分片加载和读取。之前的版本是监听 scroll 事件来实现的,在 Monaco Editor 中,也提供了类似的函数支持。

ts 复制代码
// 获取编辑器的配置选项
const options = editorInstance.value.getOptions();

// 获取行高
const lineHeight = options.get(monaco.editor.EditorOption.lineHeight);

// 节流函数
function throttle(func, wait) {
    let lastTime = 0;
    return function(...args) {
      const now = Date.now();
      if (now - lastTime >= wait) {
        lastTime = now;
        func.apply(this, args);
      }
    };
}

// 监听滚动事件
editorInstance.value.onDidScrollChange(throttle((e) => {
    const layoutInfo = editorInstance.value.getLayoutInfo();
    const scrollTop = e.scrollTop; // 当前滚动位置
    const visibleHeight = layoutInfo.height; // 可见区域的高度

    const model = editorInstance.value.getModel();
    const lineCount = model.getLineCount(); // 总行数

    // 判断是否滑到底部
    if (scrollTop >= lineCount * lineHeight - visibleHeight) {
      console.log('滚动条滑到底部了!');
      emit('load-more'); // 发出 load-more 事件
    }
}, 1000)); // 1000ms 的节流间隔

// 监听 value 变化,加载新的文本内容
watch(() => props.value, (newValue) => {
  console.log('value changed:', newValue.length);
  if (editorInstance.value) {
    const oldValue = editorInstance.value.getValue(); // 获取编辑器内容
    editorInstance.value.setValue(oldValue + newValue); // 更新编辑器内容
  }
});
  

同时我们使用了节流函数来提高性能,降低不必要的开销。

性能优化:解决卡死问题

开发中发现一个问题,编辑器初始化和显示没有问题。但每当调用 getValuesetValuedispose 等方法,就会导致页面卡死。经测试后定位到是 Vue3 的代理机制导致的,解决方案是使用 toRaweditorInstance.value 进行包装。

Vue3 中,响应式系统会通过 Proxy 对对象进行深层代理,当直接操作被代理的 Monaco Editor 实例时,每次调用 setValue 等方法都会触发 Proxy 的拦截和依赖追踪,这种额外的代理开销在频繁操作大量数据时会形成性能黑洞。而 toRaw 通过剥离代理层直接操作原始编辑器实例,避免了响应式系统的性能损耗,如同卸下编辑器身上的"监控枷锁",使得操作性能回归原生级别。

ts 复制代码
import { ref, onMounted, watch, onBeforeUnmount, toRaw } from 'vue';

const oldValue = toRaw(editorInstance.value).getValue(); 

toRaw(editorInstance.value).setValue(oldValue + newValue);

toRaw(editorInstance.value).dispose();

解决 vite-plugin-monaco-editor 引入报错

使用 vite-plugin-monaco-editor 插件可以简化 Vite 加载 Monaco Editor 的过程。

ts 复制代码
// vite.config.ts
import { defineConfig } from 'vite';
import monacoEditorPlugin from 'vite-plugin-monaco-editor';

export default defineConfig({
  plugins: [monacoEditorPlugin()],
});

但是在项目开发过程中发现,引入该插件会报错:TypeError: monacoEditorPlugin is not a function。原因是该插件与 ViteESM 模块规范冲突。解决方案很简单,社区有人提供了 ESM 规范的插件,将原有的插件替换成 vite-plugin-monaco-editor-esm 即可。

以上便是我搞定 Vite + Vue3 + Monaco Editor 集成的全过程。从基础配置到性能优化,解决了大文件分片加载、响应式陷阱和构建报错等问题。希望这些技巧能帮你快速上手,减少踩坑,打造高效的 Web IDE!

相关推荐
黄智勇1 天前
xlsx-handlebars 一个用于处理 XLSX 文件 Handlebars 模板的 Rust 库,支持多平台使
前端
brzhang1 天前
为什么 OpenAI 不让 LLM 生成 UI?深度解析 OpenAI Apps SDK 背后的新一代交互范式
前端·后端·架构
brzhang1 天前
OpenAI Apps SDK ,一个好的 App,不是让用户知道它该怎么用,而是让用户自然地知道自己在做什么。
前端·后端·架构
井柏然1 天前
前端工程化—实战npm包深入理解 external 及实例唯一性
前端·javascript·前端工程化
IT_陈寒1 天前
Redis 高性能缓存设计:7个核心优化策略让你的QPS提升300%
前端·人工智能·后端
井柏然1 天前
从 npm 包实战深入理解 external 及实例唯一性
前端·javascript·前端工程化
羊锦磊1 天前
[ vue 前端框架 ] 基本用法和vue.cli脚手架搭建
前端·vue.js·前端框架
brzhang1 天前
高通把Arduino买了,你的“小破板”要变“AI核弹”了?
前端·后端·架构
她说..1 天前
通过git拉取前端项目
java·前端·git·vscode·拉取代码
智能化咨询1 天前
玩转ClaudeCode:通过Chrome DevTools MCP实现高级调试与反反爬策略
前端·chrome·chrome devtools