使用 vscode 调试 Node.js 源码中JavaScript 侧代码

963 阅读1分钟

设置 vscode 调试

vscode 可以调试 nodejs 程序,需要先创建 launch.json 文件:

1645010671011.png

自动创建的 launch.json 配置如下:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      "skipFiles": [
        "<node_internals>/**"
      ],
      "program": "${file}"
    }
  ]
}

configurations 的解析如下:

  • type,必填项,调试类型,当前为 node,如果是 PHP 调试,则在安装 PHP 调试插件后写 php
  • request,必填项,有两种类型,分别是 launchattachlaunch 表示在启动时就进行调试,类似于执行 node --inspect index.jsattach 表示在 node 启动后再动态开启调试模式,类似于先执行了 node index.js,然后动态开启调试模式
  • program,程序的启动入口
  • skipFiles,表示调试时忽略的文件,默认 <node_internals/**> 表示 Node 内部模块。

所以要调试 node 源码就要将这个配置去掉:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      // "skipFiles": [
      //   "<node_internals>/**"
      // ],
      "program": "${file}"
    }
  ]
}

但实际运行起来,并没有生效,打在 Node API 的断点并没有生效。原因是vscode调试nodejs的插件采用的是 vscode-js-debug 插件的配置项里针对node-launch启动模式默认的 skipFiles 是忽略 Node 内部模块的,如下图所示:

1645011379096.png

1645011398956.png

所以需要保留 skipFiles 选项,配置项如下:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      "skipFiles": [
        // "<node_internals>/**"
      ],
      "program": "${file}"
    }
  ]
}

这样在配置的时候就可以进入到 nodejs 源码中:

1645011979285.png 1645011991299.png

nodejs 源码调试

nodejs项目代码结构如下:

1645012841280.png

其中 C++ 部分的代码在 src 文件夹下,js 部分的代码在 lib 文件夹下,我们要调试的 javascript 侧的代码都在 lib 文件夹下。

nodejs 源码下载下来之后,进入文件夹在根目录下执行:

./configure --node-builtin-modules-path $(pwd)

make -j4

运行 make -j4 会在 out/Release 文件夹下生成一个 node 的二进制文件,--node-builtin-modules-path 配置指定生成的二进制文件不包含任何的js文件,会从 lib 文件夹中动态的加载js文件。

make 命令会执行很长时间,-j4 选项可以让 make 同时运行 4 个编译作业,用于减少构建时间,也可以选择 make -j8

编译好nodejs后,可以配置 vscode 的 aunch.json 文件了,如下:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch current file",
      "runtimeExecutable": "${workspaceFolder}/out/Release/node",
      "args": [
        "--expose-internals",
        "--nolazy",
        "${workspaceFolder}/${relativeFile}",
      ],
      "request": "launch",
      "type": "node",
      "skipFiles": []
    }
  ]
}
  • runtimeExecutable,使用什么命令启动调试,上面使用的是最近编译好的 node 二进制文件
  • args,启动时的参数
    • --expose-internals,暴露出内部模块
    • --nolazy,保证将断点放到正确的位置,出于性能原因,Node.js 在首次访问时会延迟解析 JavaScript 文件中的函数。因此在nodejs没有解析道道源码区域打断点是不起作用的,--nolazy可以防止延迟解析,能够将断点在运行之前验证正确的位置。
    • ${workspaceFolder}/${relativeFile},指向vscode当前正在编辑的文件,也就是说要调试的文件是当前正在编辑的文件。

配置好之后,在 node 根目录中新建 node-demo 文件夹,在文件夹下新建 index.js 测试文件:

const os = require('os');

const cpus = os.cpus();
console.log('os.cpus()', cpus);

就可以调试 nodejs 源码中JavaScript 侧代码了。

demo

参考资料