Visual Studio Code(简称 VS Code)是一款微软开源的现代化、跨平台、轻量级的代码编辑器。VS Code 很好很强大,本节将介绍如何使用 VS Code 来调试 Node.js 代码。
示例代码如下:
app.js
const Paloma = require('paloma')
const app = new Paloma()
app.use(ctx => {
ctx.body = 'hello world!'
})
app.listen(3000)
用 VS Code 加载 test 文件夹,打开 app.js,然后进行如下操作:
- 单击左侧第 4 个 tab,切换到调试模式。
- 单击代码第 5 行
ctx.body='hello world!'
左侧空白处添加断点。 - 单击左上角 ”调试“ 的绿色三角按钮启动调试。
- 单击左上角的终端图标打开调试控制台。
最终如下所示:
从 “调试控制台“ 切换到 ”终端“,运行:
$ curl localhost:3000
如下所示:
可以看出,VS Code 基本覆盖了 Chrome DevTools 的所有功能,并且有两个额外的优点:
- 集成了终端,不用再打开新的终端输入命令了。
- 调试动作里添加了 ”重启“ 和 ”停止“ 按钮,不用每次修改完代码后切回终端去重启了。
但 VS Code 的强大远不止如此,通过 launch.json 可以配置详细的调试功能。
上图可以看出,”调试“ 按钮右边有一个下拉菜单,默认是 ”没有配置“。单击右侧的齿轮状图标,会在项目根目录下创建 .vscode 文件夹及 launch.json 文件。launch.json 的内容如下:
这个默认配置的意思是执行:
$ node ${workspaceFolder}/app.js
launch.json 其实就是存储了一些调试相关的配置,VS Code 在启动调试时,会读取 launch.json 决定以何种方式调试。launch.json 有以下常用选项:
必需字段如下:
- type:调试器类型。这里是 node(内置的调试器),如果安装了 Go 和 PHP 的扩展后,则对应的 type 分别为 go 和 php。
- request:请求的类型,支持 launch 和 attach。launch 就是以 debug 模式启动调试,attach 就是附加到已经启动的进程开启 debug 模式并调试,跟在上一小节中提到的用
node -e "process._debugProcess(PID)"
作用一样。 - name:下拉菜单显示的名字。
可选字段(括号里表示适用的类型)如下:
- program:可执行文件或者调试器要运行的文件 (launch)。
- args:要传递给调试程序的参数 (launch)。
- env:环境变量 (launch)。
- cwd:当前执行目录 (launch)。
- address:IP 地址 (launch & attach)。
- port:端口号 (launch & attach)。
- skipFiles:想要忽略的文件,数组类型 (launch & attach)。
- processId:进程 PID (attach)。
- ...
变量替换:
- ${workspaceFolder}:当前打开工程的路径。
- ${file}:当前打开文件的路径。
- ${fileBasename}:当前打开文件的名字,包含后缀名。
- ${fileDirname}:当前打开文件所在的文件夹的路径。
- ${fileExtname}:当前打开文件的后缀名。
- ${cwd}:当前执行目录。
- ...
如果当前打开的文件是 app.js,则以下配置与默认配置是等效的:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动程序",
"program": "${file}"
}
]
}
若想了解更多的 launch.json 选项,则请查阅:
下面以 5 个实用的技巧讲解部分 launch.json 配置的作用。
VS Code 可以添加条件断点,即执行到该行代码满足特定条件后程序才会中断。在断点小红点上右键选择 ”编辑断点“,可以选择以下两种条件:
- 表达式:当表达式计算结果为 true 时中断,例如设置:
ctx.query.name === 'nswbmw'
,表示当访问localhost:3000?name=nswbmw
时断点才会生效,其余请求断点无效。 - 命中次数:同样当表达式计算结果为 true 时中断,支持运算符 <、<=、==、>、>=、%。例如:
- >10:执行 10 次以后,断点才会生效。
- <3:只有前 2 次断点会生效。
- 10:等价于 >=10。
- %2:隔一次中断一次。
注意:可以组合表达式和命中次数条件一起使用。在切换条件类型时,需要将原来的条件清空,否则会添加两种条件。将鼠标悬浮在断点上,可以查看设置了哪些条件。
从上面图中可以看到,在 VS Code 左侧有一个 ”调用堆栈“ 面板,显示了当前断点的调用堆栈,但无法直观地看出哪些是我们项目的代码,哪些是 node_modules 里模块的代码,而且在单步调试时会进入到 node_modules 里。总之,我们不关心 node_modules 里的代码,我们只关心项目本身的代码。这时,skipFiles 就派上用场了。
skipFiles 顾名思义就是忽略我们不关心的文件。修改 launch.json 如下:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动程序",
"program": "${workspaceFolder}/app.js",
"skipFiles": [
"${workspaceFolder}/node_modules/**/*.js",
"<node_internals>/**/*.js"
]
}
]
}
有以下几点需要解释:
- 支持 ${xxx} 这种变量替换。
- 支持 glob 模式匹配。
- <node_internals> 用来忽略 Node.js 核心模块。
重启调试后,如下所示:
可以看出:在左侧 ”调用堆栈“ 中,我们不关心的调用栈都变灰了,而且单步调试也不会进入到 skipFiles 所匹配的文件里。
在每次修改代码保存后都要手动重启,否则修改后的代码和断点都不会生效。VS Code 开发者们想到了这一点,通过添加配置可以实现修改代码保存后会自动重启调试,需要结合 nodemon 一起使用。
首先,全局安装 nodemon:
$ npm i nodemon -g
然后,修改 launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动程序",
"runtimeExecutable": "nodemon",
"program": "${workspaceFolder}/app.js",
"restart": true,
"console": "integratedTerminal",
"skipFiles": [
"${workspaceFolder}/node_modules/**/*.js",
"<node_internals>/**/*.js"
]
}
]
}
当前的 launch.json 相比较上一个版本的 launch.json,多了以下几个字段:
- runtimeExecutable:用什么命令执行 app.js,这里设置为 nodemon。
- restart:设置为 true,修改代码并保存后会自动重启调试。
- console:当单击停止按钮或者修改代码并保存后自动重启调试,而 nodemon 是仍然在运行的,通过设置为 console 为 integratedTerminal 可以解决这个问题。此时 VS Code 终端将会打印 nodemon 的 log,可以在终端右侧的下拉菜单中选择返回第 1 个终端,然后运行
curl localhost:3000
进行调试。
对于已经使用 nodemon 运行的程序,例如:
$ nodemon --inspect app.js
可使用 attach 模式启动调试,launch.json 如下:
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to node",
"type": "node",
"request": "attach",
"restart": true,
"processId": "${command:PickProcess}"
}
]
}
运行 Attach to node 配置进行调试时,VS Code 会列出正在执行的 node 进程及对应的 PID 以供选择。也可以通过 address 和 port 参数设置 attach 到具体的进程开启调试。
针对不同的操作系统,可能会用到不同的调试配置。可选的参数为:
- windows
- linux
- osx
示例如下:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动调试",
"program": "./node_modules/gulp/bin/gulpfile.js",
"args": ["/path/to/app.js"],
"windows": {
"args": ["\\path\\to\\app.js"]
}
}
]
}
configurations 是个数组而不是个对象,这样设计就是为了可以添加多个调试配置。打开 launch.json,单击右下角的 ”添加配置…“,会弹出配置模板,如下所示:
configurations 可以用来配置不同的调试规则,比如最终将 launch.json 修改如下:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "attach",
"name": "Attach to node",
"restart": true,
"processId": "${command:PickProcess}"
},
{
"type": "node",
"request": "launch",
"name": "启动程序",
"runtimeExecutable": "nodemon",
"program": "${workspaceFolder}/app.js",
"restart": true,
"console": "integratedTerminal",
"skipFiles": [
"${workspaceFolder}/node_modules/**/*.js",
"<node_internals>/**/*.js"
]
}
]
}
VS Code 的调试功能十分强大,本节只讲解了一些常用的调试功能,对于其余的调试功能,还请读者自行尝试。