You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Monaco Editor中添加运行调试功能

Monaco Editor 逐行代码调试实现方案

核心依赖与基础逻辑

Monaco Editor 原生支持基于 Debug Adapter Protocol (DAP) 的调试能力,核心是通过调试适配器(Debug Adapter)连接编辑器与目标代码运行环境,实现断点管理、执行控制、数据同步等功能。如果是JavaScript、Python等常见语言,可直接复用开源调试适配器;自定义语言则需要自行实现符合DAP的适配器。

核心功能实现步骤

1. 初始化编辑器与调试模块

先完成Monaco Editor的基础初始化,再注册调试适配器工厂,建立编辑器与调试服务的连接:

import * as monaco from 'monaco-editor';
// 以JS调试为例,引入对应调试客户端
import { DebugClient } from 'vscode-debugadapter';

// 创建编辑器实例
const editor = monaco.editor.create(document.getElementById('editor-container'), {
  value: 'function add(a, b) { return a + b; }\nadd(1, 2);',
  language: 'javascript',
  lineNumbers: 'on',
  gutter: 'on'
});

// 注册调试适配器工厂
monaco.debug.registerDebugAdapterDescriptorFactory('javascript', {
  createAdapter: () => new DebugClient('node', './node_modules/vscode-js-debug/out/src/debugAdapter.js')
});

2. 断点管理实现

监听编辑器 gutter 的点击事件,同步断点到调试适配器,并维护断点状态:

// 监听断点变更事件
monaco.debug.onDidChangeBreakpoints(({ added, removed }) => {
  // 新增断点
  added.forEach(bp => {
    debugClient.setBreakpointsRequest({
      source: { path: bp.source?.path || 'inline-code' },
      breakpoints: [{ line: bp.lineNumber }]
    });
  });
  // 删除断点
  removed.forEach(bp => {
    debugClient.setBreakpointsRequest({
      source: { path: bp.source?.path || 'inline-code' },
      breakpoints: []
    });
  });
});

3. 逐行调试控制逻辑

实现启动、暂停、步进(步过/步入/步出)等调试控制按钮,绑定对应的DAP命令:

// 启动调试会话
document.getElementById('btn-start').addEventListener('click', async () => {
  const session = monaco.debug.startDebugSession({
    type: 'javascript',
    request: 'launch',
    program: '/path/to/target-code.js',
    console: 'integratedTerminal'
  });
});

// 步过(下一步)
document.getElementById('btn-step-over').addEventListener('click', () => {
  debugClient.nextRequest();
});

// 步入
document.getElementById('btn-step-in').addEventListener('click', () => {
  debugClient.stepInRequest();
});

// 步出
document.getElementById('btn-step-out').addEventListener('click', () => {
  debugClient.stepOutRequest();
});

// 暂停调试
document.getElementById('btn-pause').addEventListener('click', () => {
  debugClient.pauseRequest({ threadId: activeThreadId });
});

4. 运行结果与状态同步

监听调试适配器的stopped事件,高亮当前执行行,并获取栈帧、变量数据展示:

// 监听调试停止事件(命中断点/步进触发)
debugClient.on('stopped', async (event) => {
  const threadId = event.threadId;
  // 获取当前栈帧
  const stackResp = await debugClient.stackTraceRequest({ threadId });
  const currentFrame = stackResp.stackFrames[0];
  // 高亮当前执行行
  editor.setDecorations('debug-current-line', [{
    range: new monaco.Range(currentFrame.line, 1, currentFrame.line, 1),
    options: { className: 'debug-highlight-line' }
  }]);
  // 获取当前作用域变量
  const scope = currentFrame.scopes[0];
  const varsResp = await debugClient.variablesRequest({ variablesReference: scope.variablesReference });
  // 渲染变量面板(需自行实现DOM更新逻辑)
  renderVariablePanel(varsResp.variables);
});

关键注意事项

  • 跨域处理:若调试适配器部署在独立服务,需配置CORS允许编辑器域名的请求
  • 自定义语言适配:需自行实现符合DAP的调试适配器,处理断点验证、执行控制、数据序列化等逻辑
  • 状态一致性:调试过程中若编辑器代码修改,需同步更新调试环境的代码(如热重载),避免调试状态不一致
  • 性能优化:批量处理断点变更请求,减少编辑器与适配器的通信次数,避免卡顿

内容的提问来源于stack exchange,提问作者Syed Irshad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 13:14:53