通过 vscode 调试 nodejs 源代码
2023年11月08日
我是 nodejs 开发,所以一直想要深入了解 nodejs 底层的一些东西,想要了解 nodejs 是如何启动的,底层的 v8、libuv 等是如何组合在一起的。
通过 debug 去打一些断点,然后运行命令,看程序是如何去运行的,可以帮助自己去了解它的一些运行流程。
通过我的一些学习与实践,本文就记录一下通过 vscode 去调试 nodejs 源代码的过程。
编译步骤:
首先需要将 nodejs 克隆至本地,然后我将分支切换至最近的一个 node 稳定版本 v20.9.0。然后参考 building 官方文档,去编译出 debug 版本的 node 二进制文件。
1git clone git@github.com:nodejs/node.git 2cd node 3git checkout v20.9.0 4 5# 编译 6./configure --debug 7make -j4
编译过程很慢,我是 mac 电脑,感觉中间编译了有半个小时以上了。编译好了之后,out/Debug/node
即为编译出来的可用于 debug 的 node 二进制程序。
此时可以尝试运行一下 helloworld.js
,看一下是不是符合预期。
1./out/Debug/node test/fixtures/test-repl-tab-completion/helloworld.js
vscode debug 配置
编译好了之后,就是 vscode 的 debug 配置了。
因为 nodejs 源代码也是 c/c++写的,所以 vscode 需要首先安装扩展 CodeLLDB。
debug c/c++
然后设置 .vscode/launch.json
的内容如下,program 项设置为 debug 版本的 node 二进制文件,args 跟随我们要运行的 js 脚本即可:
1{ 2 "version": "0.2.0", 3 "configurations": [ 4 { 5 "type": "lldb", 6 "request": "launch", 7 "name": "lldb:node", 8 "program": "${workspaceFolder}/out/Debug/node", 9 "args": ["test/fixtures/test-repl-tab-completion/helloworld.js"], 10 "cwd": "${workspaceFolder}" 11 } 12 ] 13}
先在 src/node_main.cc
的 int main
入口 debug 打点,之后运行 vscode 侧边栏的 debug,就可以看到程序可以在断点处停下了,之后就可以调试 c/c++ 文件了。
chrome 中 debug js
除了 c/c++文件,我还想 debug js 文件,这个时候我们就需要再做一些配置了。修改 .vscode/launch.json
内容如下,在 node 启动时,新增 --inspect-brk
启动参数:
1{ 2 "version": "0.2.0", 3 "configurations": [ 4 { 5 "type": "lldb", 6 "request": "launch", 7 "name": "lldb:node", 8 "program": "${workspaceFolder}/out/Debug/node", 9 "args": ["--inspect-brk", "test/fixtures/test-repl-tab-completion/helloworld.js"], 10 "cwd": "${workspaceFolder}" 11 } 12 ] 13}
新增的 --inspect-brk
参数表示开启 js 的调试,设置好了之后,在 vscode 中开启 debug 后。通过 chrome 浏览器进入地址 chrome://inspect
,就会自动监听显示可以 debug 的 js 代码。
vscode 中 debug js
chrome 中可以调试 js,但是 vscode 本来就支持调试 js,所以我们再进一步,修改 ./vscode/launch.json
文件如下,添加 node:attach
一项配置:
1{ 2 "version": "0.2.0", 3 "configurations": [ 4 { 5 "name": "node:attach", 6 "port": 9229, 7 "request": "attach", 8 "skipFiles": ["<node_internals>/**"], 9 "type": "node" 10 }, 11 { 12 "type": "lldb", 13 "request": "launch", 14 "name": "lldb:node", 15 "program": "${workspaceFolder}/out/Debug/node", 16 "args": ["--inspect-brk", "test/fixtures/test-repl-tab-completion/helloworld.js"], 17 "cwd": "${workspaceFolder}" 18 } 19 ] 20}
debug 时先启动 lldb:node
,然后当终端打印出可以接入 js debug 时,再在 vscode 侧边 debug 栏开启 node:attach
debug 选项。之后就可以愉快地在 c/c++和 js 文件 dubug 了。
compounds
上一步 debug 还是需要先后点两次,此时更近一步,我就点一次,就可以了。(但是偶尔会碰到它并没有 attach 上的情况,这时就要重来了。)
1{ 2 "version": "0.2.0", 3 "configurations": [ 4 { 5 "name": "node:attach", 6 "port": 9229, 7 "request": "attach", 8 "skipFiles": ["<node_internals>/**"], 9 "type": "node" 10 }, 11 { 12 "type": "lldb", 13 "request": "launch", 14 "name": "lldb:node", 15 "program": "${workspaceFolder}/out/Debug/node", 16 "args": ["--inspect-brk", "test/fixtures/test-repl-tab-completion/helloworld.js"], 17 "cwd": "${workspaceFolder}" 18 } 19 ], 20 "compounds": [ 21 { 22 "name": "node debug", 23 "configurations": ["lldb:node", "node:attach"] 24 } 25 ] 26}
可以看到修改的配置中多了 compounds
内容,之后 debug 时,在 debug 栏开启 node debug
这个即可。
debug 过程可以通过视频来进一步详细了解
视频介绍了 debug 的过程,且了解了一下 nodejs 的启动过程,然后简单 debug 一下 nodejs 的事件循环(event loop)与 microTask。