vscode调试技巧
本篇vscode调试场景全面、并结合实际项目场景,建议收藏
在现代前端与全栈开发的日常工作中,代码调试是不可或缺的一环,而一款优秀的调试工具能够显著提升开发效率,减少问题定位的时间成本。Visual Studio Code(简称 VSCode)作为一款备受开发者喜爱的轻量化编辑器,不仅提供了丰富的插件生态和高效的代码编辑体验,更以其强大的调试功能成为开发者工作流中不可或缺的一部分
无论是调试 Node.js 后端代码、前端浏览器代码,还是更复杂的容器化微服务系统,VSCode 都提供了灵活的调试支持。而这种强大的调试能力,并不仅限于简单地设置断点或查看变量,更体现在其对多种语言、运行时环境的无缝支持以及对调试配置的高度自定义能力上。通过掌握 VSCode 调试工具,开发者不仅能够轻松解决代码问题,还可以培养更系统化的调试思维,提升整体开发质量
在接下来的内容中,我们将围绕 VSCode 的调试功能展开深入剖析,从基本的断点设置到复杂的调试场景,带您全面解锁 VSCode 调试的潜能,助力高效开发
调试界面
和大多数调试器的功能模块界面基本上一致,包含:执行器、变量、执行栈、调试终端等等,比较简单这里就不多做介绍了;如果你对调试面板的操作步骤还不是很熟悉,可以看我的往期文章或者「vscode调试基本介绍」
调试分类
vscode支持多种形式的调试,从调试配置的复杂度来划分,可以分两大类:简单、复杂;
简单的调试可以快速的进入调试,无需关心过多的外在因素,通常这类的调试偏向于简单、无需相关工具辅助之类的项目,如:简单的原生js工程、NodeJS工程等等。简单的调试这里会介绍:auto attach
、Javascript Debug Terminal
而相对复杂的工程就不能使用这种模式了,当然也要具体的场景。面对复杂的场景,vscode提供了launch.json
配置文件来定制化debug的功能,可以很方便的适配到不同的应用场景
Auto attach
auto attach顾名思义就是自动链接的意思,也就是当程序启动debug模式时,vscode就会自动连接到目标debug,然后根据vscode提供的调试UI进行调试
若要使用此功能需要在vscode中开启配置,cmd+shift+p
输入 >Debug: Toggle Auto Attach
后回车,支持多种形式的选项,大体分为:
- always:当程序启动debug时总是自动连接上
- flag:当监听到
--inspect
或--inspect-brk
时才自动连接 - disabled:禁止
注意:当选择相关配置后,可能需要重启IDE
下图中小编启动的是flag
模式,在IDE底部栏会有对应的显示,然后在终端输入 node --inspect script
启动程序,此时IDE就会自动连接上目标debug
🚦 可能心细得同学就已经发现了,当使用调试模式运行程序后,调试器会启动一个ws
服务,为什么会有这个东西❓也有同学会疑问为啥vscode就能自动链接上目标debugger呢❓并且可以调试程序呢❓
现在让我们打开chrome
浏览器并输入 chrome://inspect/#devices
打开调试TAB,会发现我们的目标程序,当点击 inspect
后会打开一个 Dev Tool
并且也可以调试目标程序
通过Chrome链接基本上可以肯定的是,调试UI会通过ws
进行调试数据的传输,而vscode之所以会自动链接一定做了相关事件监听或者触发。后面部分我们会揭晓调试UI和目标Debugger之间的数据传输原理
如果没看到目标程序,需要将启动node程序后的ws服务ip和端口配置到
Discover network targets
即可
Javascript Debug Terminal
如果说上面的auto attach调试方式已经足够简单,那么Javascript Debug Terminal
可以说是更加傻瓜式调试,简直有手都会系列‼️让我们来看看怎么个简单法
只需要打开Javascript Debug Terminal
终端,然后像往常一样启动程序一样:
打开对应的终端
启动程序
vscode对于调试的友好性已经考虑到非常周全了
到这里就将简单形式的调试已经介绍完毕了,确实很简单,很时候一些需要快速、简单的调试场景,当然,实际场景中往往程序都是以复杂的工程出现的,那么这种简单的调试模式可能就不适用了,接下来看看vscode是如何支持复杂性工程的调试的
Debug Configuration
在 Visual Studio Code(VSCode)中,Debug Configuration(调试配置)是调试功能的核心。它允许开发者根据项目需求自定义调试环境、参数和行为。调试配置通常存储在项目的 .vscode/launch.json
文件中,通过 JSON 格式定义调试任务
创建launch.json
文件有多种方式,支持手动、可视化等等,你可以打开Debug
扩展,然后根据提示创建对应的文件:
在选择debugger时选择我们熟悉的node、chrome都行,最终都是可以通过配置文件调整
一个典型的 launch.json 文件由以下部分组成:
{
"version": "0.2.0", // 配置文件的版本号,固定为 0.2.0
"configurations": [
// 调试任务列表
{
"type": "node", // 调试类型,例如 "node", "python", "chrome"
"request": "launch", // 调试请求类型:"launch"(启动程序)或 "attach"(附加到运行的进程)
"name": "测试NodeJS", // 调试任务的名称,显示在调试面板中
"program": "${workspaceFolder}/index.js", // 主程序文件路径
"cwd": "${workspaceFolder}", // 当前工作目录
"env": {
// 环境变量
"NODE_ENV": "development"
},
"args": ["--verbose"], // 启动参数
"port": 9229 // 调试所需的端口(仅部分配置需要)
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
配置文件模式最大的区别就是type
,总体来说它把调试划分成两大分类:
- launch:以调试模式启动程序
- attach:附加到正在运行的Debuger进程
创建配置
在launch.json
中可以快速创建对应类型的配置,vscode给了对应的配置
输入花括号后会有对应的提示
也点击右下角的Add COnfiguration
按钮
Task
在正式介绍调试配置文件前,先来介绍下Task;这又是什么❓在 VSCode 中,Task 是一个功能强大的任务管理工具,用于执行各种自动化操作,例如运行构建工具、执行脚本、启动开发服务器、或调用外部命令。通过配置 Task,可以将常用的命令集成到 VSCode 中,大幅提升开发效率
说明了就是可以帮助我们执行一些自动化的任务,如:脚本、npm等等,结合调试就可以做一些自动化的东西。比如,我们需要调试一个目标程序前,可能需要将其编译才行,那么就可以将编译的任务交给Task,调试配置文件也确实提供了对应的属性:postLaunchTask
、preLaunchTask
{
// postLaunchTask ...
"preLaunchTask": "tsc: build" // 定义的 task 的 label 值
}
2
3
4
那么如何配置task呢,可以通过输入对应命令生成:.vscode/tasks.json
可以根据具体的场景调试配置:
{
"version": "2.0.0",
"tasks": [
{
"type": "typescript",
"tsconfig": "ts-examples/tsconfig.json",
"problemMatcher": [
"$tsc"
],
"group": "build",
"label": "tsc: build"
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
接下来我们来看两大调试方式吧
attach
attach调试比较简单,就是链接到对应的目标Debugger调试程序进程上,以下是一个attach例子,通过attach方式链接到9229
端口目标调试器上
{
"name": "Attach NodeJS Break Debugger",
"port": 9229,
"address": "localhost",
"request": "attach",
"skipFiles": [
"<node_internals>/**"
],
"type": "node"
}
2
3
4
5
6
7
8
9
10
当我们在终端以调试的方式启动程序后,在调试插件界面,启动这个调试后就会自动链接上目标调试器:
这个其实和前面介绍的auto attach
以及用 Chrome 进行调试道理是一样的
此模式下也包含很多相关的属性配置,这里简单列举几个:
- outFiles:源文件输出的目标文件,一般对于编译文件,vscode会自动匹配来做sourcemap映射
- resolveSourceMapLocations:用于指定调试器在解析源映射(Source Maps)时可以加载的文件路径或 URL
- continueOnAttach:用于控制调试器在附加到正在运行的进程时,是否自动继续执行程序,如:
--inspect-brk
模式调试时的场景
launch
如果说到这里还觉得配置文件方式的调试也比较的话,那么launch
模式调试就会多样化了,我觉得它可以代表配置文件调试的核心,此种模式功能有很多
launch顾名思义就是启动的意思,的确它通过配置文件告诉vscode以debug形式启动目标程序,然后自动链接到调试UI上,这种模式自动化完成了启动与连接的过程
launch支持多种启动程序的方式,下面是常用形式:
- url:通常是启动浏览器打开对应的地址
- program:指定启动的应用程序文件
- runtimeExecutable:通过执行器执行,如:npm、yarn、pnpm等等,这些执行器必须能正常使用
url
此种方式会直接打开设置的url,vscode内部会根据内置的策略将页面通过sourcemap与源码关联起来,如果程序需要编译但没有提供对应的sourcemap,将无法进行调试,此时打的断点都是灰色的
{
"name": "Launch Chrome",
"request": "launch",
"type": "chrome",
"url": "http://localhost:8082",
"webRoot": "${workspaceFolder}"
}
2
3
4
5
6
7
请注意:以上url服务需要提前运,这里使用 http-server 指定 8082 端口运行
program
program则指定vscode要运行的程序文件,比如运行node程序main.js
{
"type": "node",
"request": "launch",
"name": "Test Launch Debugger",
"args": ["author=ihengshuai"],
"program": "${workspaceFolder}/node/index.js",
"env": { "website": "https://blog.usword.cn" }
}
2
3
4
5
6
7
8
此种形式通常可以搭配args
、env
提供相关的参数变量等等
同样的如果程序也需要转义,请提供相关的sourcemap
runtimeExecutable
runtimeExecutable
用于指定调试程序的运行时可执行文件,该字段通常用于指定运行调试目标所需的特定运行环境,例如 Node.js 的可执行文件、Python 解释器或其他自定义的可执行程序
{
"type": "node",
"request": "launch",
"name": "Test Launch Debugger",
"skipFiles": [
"<node_internals>/**"
],
"cwd": "${workspaceFolder}/node",
"args": ["author=ihengshuai"],
"runtimeExecutable": "npm", // 使用npm启动
"runtimeArgs": ["run", "debug", "github=ihengshuai"], // npm 后面的参数, npm run debug
"env": { "website": "https://blog.usword.cn" }
}
2
3
4
5
6
7
8
9
10
11
12
13
此种方式的效果图和以上基本一致
重要的属性
launch方式调试有多种属性可以选择,这里我们列举几个
args:用来给目标程序传递对应的变量
cwd:指定启动目标程序的基本路径,一般都会在项目的根目录,如果对于多仓库项目,可以你可以指定对应的文件路径
runtimeArgs:传给
runtimeExecutable
的参数,比如对应的执行脚本命令:build、lint等等env和envFile:环境变量,和
.env
配置文件定义类似console:启动程序的终端,默认是debug终端,如果对于程序执行过程中一些特殊要求,你可以选择vscode终端或者外部的终端,有
internalConsole
、integratedTerminal
、externalTerminal
几个配置
除了这些属性配置外,可以很多其他的属性选项,请结合不同的type提示选择使用对应的属性
设置sourcemap
对于大多数的真实场景来说,都会是基于各种打包器的比较复杂的大型工程,那么生成的文件都会是经过压缩或者含义后的内容,而调试则需要对应sourcemap的支持,这样才能和源码映射起来
配置文件提供了sourcemap相关的配置:
- sourceMaps:默认为true,启用sourcemap
- outFiles:用于指定编译后的文件路径的位置,调试器会使用这些文件来加载 Source Map
- webRoot:用于指定 Web 应用的根目录
- sourceMapPathOverrides:用于覆盖和重映射源代码路径,当 Source Map 文件中记录的路径与实际文件路径不一致时,通过此字段解决路径匹配问题
- resolveSourceMapLocations:控制调试器加载 Source Map 文件的路径范围
比如我们基于webpack进行路径映射的调整:
{
"sourceMapPathOverrides": {
"webpack:///./*": "${webRoot}/src"
},
}
2
3
4
5
注意:以上只是简单的一个例子,请根据具体的项目场景设置
分组调试
vscode支持将多个调试分组,可以按组运行调试器
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Chrome Browser",
"request": "launch",
// ...
},
{
"name": "Launch Node Server",
"type": "node",
// ...
},
],
"compounds": [ // 定义组
{
"name": "Run Debugger",
"configurations": ["Launch Chrome Browser", "Launch Node Server"]
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
到这里基本上将vscode的调试功能讲完了,接下来我们来几个真实的调试案例
调试案例
调试Vue源码
配置好调试,终端启动对应的服务脚本:
启动debug会打开对应的浏览器,这里我们点进对应的文件目录和文件:
在对应的源码文件中打断点:
调试NodeJS
{
"name": "Test Express App",
"request": "launch",
"runtimeArgs": [
"run-script",
"express-app"
],
"runtimeExecutable": "npm",
"skipFiles": [
"<node_internals>/**"
],
"type": "node"
}
2
3
4
5
6
7
8
9
10
11
12
13
调试NestJS
{
"version": "0.2.0",
"configurations": [
{
"name": "Test NestJS",
"request": "launch",
"runtimeArgs": [
"run-script",
"start:dev"
],
"runtimeExecutable": "pnpm",
"skipFiles": [
"<node_internals>/**"
],
"type": "node"
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
调试Typescript
由于目标程序是ts,所以需要sourcemap的支持,上面我们讲了几种方式配置
{
"name": "Launch Typescript",
"type": "node",
"request": "launch",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/ts-examples/demo1.ts",
"outFiles": [
"${workspaceFolder}/ts-examples/dist/*.(m|c|)js",
"!**/node_modules/**"
],
}
2
3
4
5
6
7
8
9
10
11
12
13
调试SSR
ssr有服务端和前端,我们可以使用组合方式进行调试,页面通过启动浏览器的方式进行调试,node端通过脚本形式启动服务,这样就可以调试了
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Chrome Browser",
"request": "launch",
"type": "chrome",
"url": "http://localhost:10011",
"webRoot": "${workspaceFolder}/client",
"sourceMaps": true,
},
{
"name": "Launch Node Server",
"type": "node",
"request": "launch",
"skipFiles": [
"<node_internals>/**"
],
"runtimeExecutable": "pnpm",
"runtimeArgs": ["dev"],
"sourceMapPathOverrides": {
"webpack:///./*": "${webRoot}/src"
},
},
],
"compounds": [
{
"name": "Run Debugger",
"configurations": ["Launch Chrome Browser", "Launch Node Server"]
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
切记soucemap支持
调试其他语言
vscode不光支持js语言的调试,同时它也支持其他语言的调试,如:Java、C#、Python等等,如果你需要调试其他语言,可以下载对应的语言的调试插件 Debug Extensions Marketplace
核心原理
从上面的attach模式我们就知道目标程序启动debug模式后,可以和不同的调试UI进行连接通信,然后完成一系列的调试,而调试的核心就是debugger和UI进行数据通信的形式,只要两端根据协商好的协议进行数据的传输,就可以完成一系列操作
Chrome DevTools Protocol(CDP)
Chrome DevTools Protocol (CDP) 是由 Google 提供的一套调试协议,用于调试、诊断、分析和操作运行中的 Chrome 浏览器或其他基于 Chromium 的环境。它允许开发者通过远程调用控制浏览器的行为,比如拦截网络请求、调试 JavaScript、操作 DOM、性能分析等
开启Protocol Monitor
:
查看Protocol Monitor
:
Debug Adapter Protocol (DAP)
VSCode 使用 Debug Adapter Protocol (DAP) 作为调试的标准协议。由于vscode支持多种语言的调试,因此中间使用适配协议,不同语言的调试器是要对接了对应的适配器数据定义,就可以完成数据通信
你也可以直接阅读官方的「Debugging Architecture of VSCode」
参考文档
- debugging
- typescript-debugging
- nodejs-debugging
- vscode-js-debug options
- vscode debug recipes
- vue webpack5 debuggers