VS Code 调试 Node.js 代码

4,768 阅读6分钟

作为前端开发者,在日常工作过程中,我们已经习惯了使用 Chrome 等浏览器去调试代码。但是随着目前前端工作流越来越复杂,距离我们的代码运行在浏览器之前,会在本地进行一套复杂的构建过程,通常是运行在 Node 环境下的 JS 代码。如果这一过程出现了问题,我们需要找到一定的办法去调试代码,查找问题。另外当你去研究各种前端工具代码库如 Webpack Vue-CLI 的时候,代码的断点调试通常是源码阅读的一大利器。

今天就介绍下,在 VS Code 中怎么调试 Node.js 代码。首先要说明的是,能实现 Node.js 的调试是 Node 提供的底层支持[1]。当 Node.js 开启调试模式的时候,我们可以通过 websocket 连接和 Node 进程通信,从而控制 Node.js 的执行过程,同时也能够获取程序执行中的各种信息,我们平时最常用的就是窥探代码执行过程中调用堆栈和各种变量的信息。这种通信方式也是基于 V8 Inspector Protocol 。另外要说明的是,Node.js 代码的调试方式有很多种,而 VS Code 给我们提供了一个可视化的界面,为我们调试 Node.js 提供了极大的方便,和我们在 Chrome 中调试源代码的体验几乎一样。

想要调试 Node.js 代码,有两个工作。

  1. Node.js 开启调试模式,指定调试端口;
  2. 让 VS Code 与调试端口连接;

接下来用具体例子介绍下怎么完成这两个步骤。

调试 build-w.js 代码

真正启用调试的过程很简单,我们会通过示例项目 ts-hello 去介绍。这个项目中是一段 TS 示例代码。build-w.js 的工作是使用 webpack 编译打包 TS 代码。build-w.js 会接收一个参数去控制编译工作是要使用 ts-loader 还是 babel-loader

然后我们会去调试这段代码,看下我们传递的参数是否被成功接收到。

【步骤一】:你需要启动执行你的 build-w.js 代码,并且开启调试。你只需要在命令行里执行 node --inspect-brk build/build-w.js --loader ts-loader。其中 --inspect-brk 参数就是告诉 Node.js 启用调试,同时会在代码的开始处等待调试命令去继续执行,并且使用本机 9229端口启用 websocket 接收控制消息。更多和启用调试相关的参数参考文档

【步骤二】:我们需要让 VS Code 能够和 Node.js 的 websocket 连接起来。此时可以在 VS Code 里使用 Shift + Command + P 搜索命令 Debug,你会看到:

vscode-attach

选择 Attach to Node Process 之后会看到正在执行的 Node 进程。选择我们刚才执行的 Node 进程。

vscode-debug-list

之后 VS Code 就会进入调试模式,就和我们在 Chrome 中调试几乎一样了。

vscode-debug-init

继续执行的话就会看到,我们传入的参数被正确解析了。

vscode-debug-params

launch.json

上面是我们先运行的 Node.js 程序,然后使用 VS Code 去连接 Node 进程。实际上这两步可以并作一步都交给 VS Code 去做。操作如下图:

vscode-debug-launch

你只需要添加一个 launch.json 文件,然后在 VS Code 中启用调试即可。其中 program 字段指定了程序运行的入口。args 字段指定了程序的参数。skipFiles 指定了我们要跳过 Node 内部代码。在 launch.json 文件内我们可以进行更多的配置,详细的配置项可以参考官方文档

这里需要注意的是:你需要在代码中先标记一个断点,否则代码是直接运行不会停下来的(前面的例子是因为我们传递了 --inspect-brk 参数)。

调试 webpack 程序

如果我们想要去调试 webpack 命令行工具的执行过程。比如我们 npm-scripts 的配置如下:

{
  "scripts": {
    "rollup-t": "node build/build-r.js --ts",
    "rollup-b": "node build/build-r.js",
    "webpack-b": "node build/build-w.js",
    "webpack-t": "node build/build-w.js --loader 'ts-loader'",
    "debug": "webpack --config webpack.config.js"
  }
}

针对 "debug": "webpack --config webpack.config.js",我们应该怎么指定程序入口,开启调试呢?

这时候要清楚,这里的 webpack 命令,实际的可执行文件是在 node_modules/.bin 文件夹下[2]。因此,这里我们的 launch.json 文件的配置应该如下。注意其中 program 字段指定的入口文件位置。

{
  "version": "0.2.0",
  "configurations": [
    {
     "type": "node",
      "request": "launch",
      "name": "启动程序",
      "program": "${workspaceFolder}/node_modules/.bin/webpack",
      "args": ["--config", "webpack.config.js"],
      "skipFiles": [
        "<node_internals>/**"
      ]
    }
  ]
}

同时,因为 .bin 文件夹下的文件都是软链接,你应该在源文件中去打断点。webpack 可执行文件的源文件路径为:node_modules/webpack/bin/webpack.js。这个路径是 webpack 项目中的 package.json bin 指定的。你也可以通过 ls -l node_modules/.bin/webpack 命令看到该软链接的源文件地址:

> ls -l node_modules/.bin/webpack
lrwxr-xr-x  1 didi-feng  staff  25 11 29 01:30 node_modules/.bin/webpack -> ../webpack/bin/webpack.js

调试 npm 程序

还有一种情况,当我们使用 npm run debug 的时候,在执行到我们 "debug": "webpack --config webpack.config.js" 中指定的 webpack 代码前,npm 会做一些初始化操作,比如将所有的的 npm 配置项添加到环境变量中[3]。因此如果代码中使用到了 npm 配置项,比如 process.env.npm_package_version ,那前面的操作是不满足的,因为你 program 指定的入口是 webpack 。所以我们需要程序从 npm 命令开始执行。那么 launch.json 的配置应该为:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch via NPM",
      "runtimeExecutable": "npm",
      "runtimeArgs": [
        "run-script",
        "debug"
      ],
      "port": 9229,
      "skipFiles": [
        "<node_internals>/**"
      ]
    }
  ]
}

这里 runtimeExecutable 字段指定的是,npm 命令。其实这里可以指定任何你系统中的可执行命令。runtimeArgs 字段指定的是传递给 npm 命令的参数。

另外你的 npm-scripts-debug 命令配置应该改为 "debug": "node --inspect-brk node_modules/.bin/webpack --config webpack.config.js"。也就是说,当 npm 命令执行到我们配置的 webpack 代码时,需要 Node.js 开启调试。

前面我们是通过指定 program 字段指定 Node.js 入口文件,VS Code 在运行入口文件的时候会自动开启调试。但是目前我们的启动入口是 npm 命令,npm 运行后可能会运行很多 Node.js 程序,至于你希望调试哪些 Node.js 程序,需要你自己指定哪些 Node.js 进程需要开启调试。同时 launch.json 中指定的 port 端口号,要和 Node.js 调试端口号对应。(--inspect-brk 默认指定的端口号就是 9229。)

最后

以上基本能满足我们平时调试 Node.js 代码的需求。但这里介绍的还不是 VS Code 调试的所有能力。

更多和 VS Code 调试相关的技巧可以查看官方文档

如果有问题,可以在评论中留言。