# VS Code 调试 Node.js
在上一篇文章 创建 Node.js 服务 中,我们简单介绍了 VS Code 调试 Node.js。但是有一个问题,如果在调试过程中发现了问题,随即修改代码,但是服务没有自动重启,而是需要我们手动刷新。如果我们一时忘记了刷新,调试时发现问题依然存在,而我们觉得已经改了代码,问题不应该存在,给我们带来了困惑。这篇文章我们将详细介绍 VS Code 调试 Node.js 的四种方法,并且解决修改代码没有重启服务的问题。
正如上一篇文章 创建 Node.js 服务 中说的,VS Code 调试 Node.js 有四种方法:
- 使用 自动附加 (opens new window)调试您在 VS Code 的集成终端中运行的进程。
- 使用 JavaScript 调试终端 (opens new window) 调试程序。
- 附加到在 VS Code 外部启动的 进程 (opens new window)。
- 使用 启动配置 (opens new window)启动程序。
同时我们知道,使用 nodemon
(opens new window) 命令行工具,可以在修改代码之后自动重启服务。
$ nodemon index.js
接下来我们研究怎么将 nodemon
(opens new window) 工具与 VS Code 调试方式结合起来,实现既能使用 VS Code 调试,又能修改代码之后重启服务,并且可以继续调试。
# 自动附加
自动附加功能让 Node 调试器自动附加到从 VS Code 集成终端启动的 Node.js 进程。通过在命令面板(⇧⌘P)中的 Debug: Toggle Auto Attach
命令,启动自动附加功能。
自动附加有三种模式:
always
:将调试在 VS Code 集成终端中启动的所有 Node.js 进程onlyWithFlag
:将仅调试使用--inspect
或--inspect-brk
标志启动的进程。smart
:将调试node_modules
文件夹未包含的脚本或使用常见的 “运行程序” 脚本(如mocha
或ts-node
)
开启自动附加功能之后,可以通过 VS Code 窗口底部的 Auto Attach
状态栏切换模式。启动自动附加功能或者切换模式之后,需要重新创建一个新终端,然后运行程序。
# always
首先我们来看看 always
,当选择这个选项时,只要我们在 VS Code 集成终端运行 Node.js 程序(无论是在终端命令行里运行还是通过 NPM Script
运行,但是不能在别的终端应用运行),VS Code 就打开了调试。
所以我们可以在 VS Code 集成终端运行 nodemon
命令
$ nodemon index.js
或者在 package.json
里添加脚本命令,然后运行
"scripts": {
"dev": "nodemon index.js",
}
2
3
这样就实现了既打开了 VS Code 调试,又在修改代码之后重启服务。但是 always
模式有个缺陷:因为自动附加功能作用于全局,开启 always
模式之后,所有的项目只要通过 VS Code 集成终端运行,都会打开调试,这对于一些 web 前端项目是没有必要的。
# onlyWithFlag
onlyWithFlag
仅调试使用 --inspect
或 --inspect-brk
标志启动的进程,所以我们可以使用 --inspect
选项在 VS Code 集成终端运行 Node.js 程序。
$ node --inspect index.js
# 或者
$ nodemon --inspect index.js
2
3
通过 nodemon --inspect index.js
,实现了既使用了 VS Code 调试,又在修改代码之后重启服务,同时避免 web 前端项目自动开启调试。
注意,onlyWithFlag
模式同样要求在 VS Code 集成终端运行,在别的终端应用运行无效。
# smart
smart
:将调试 node_modules
文件夹未包含的脚本或使用常见的 “运行程序” 脚本(如 mocha
或 ts-node
),可以通过 Auto Attach Smart Pattern
(debug.javascript.autoAttachSmartPattern
) 配置 “运行程序” 脚本允许列表
因为 node
和 nodemon
命令都不在 node_modules
文件夹里,所以也能实现打开 VS Code 调试,同时修改代码之后重启服务。对于 web 前端项目,如果使用了 node_modules
文件夹里的脚本,比如 umijs
的 max
命令,CRA
的 react-scripts
命令,就不会开启调试,如果没有使用,比如 CRA
eject
之后的 node scripts/start.js
就会打开调试。
注意,smart
模式同样要求在 VS Code 集成终端运行,在别的终端应用运行无效。
# JavaScript 调试终端
JavaScript 调试终端将自动调试您在其中运行的任何 Node.js 进程,无论是否使用了 --inspect
或 --inspect-brk
选项。
创建 JavaScript 调试终端有下面两个方法:
命令面板(⇧⌘P)中的
Debug: JavaScript Debug Terminal
命令在 VS Code 终端界面创建一个 JavaScript 调试终端
然后,我们在 JavaScript 调试终端里运行 nodemon
,实现 VS Code 调试,同时修改代码之后重启服务
$ nodemon index.js
除此之外,通过 NPM Script 面板,也能创建 JavaScript 调试终端,并调试 Node.js 程序
因此我们可以在 package.json
里创建 nodemon
脚本命令
"scripts": {
"dev": "nodemon index.js",
}
2
3
通过 NPM Script 面板,调试 dev
命令,实现 VS Code 调试,同时修改代码之后重启服务
# 附加到 Node.js
如果您在别的终端应用(比如 iTerm)里运行 Node.js 程序
$ node --inspect index.js
# 或者
$ nodemon --inspect index.js
2
3
然后想通过 VS Code 进行调试,这个时候就需要使用附加到 Node.js。通过命令面板 (⇧⌘P) 中的 Debug: Attach to Node Process
命令将打开一个 Quick Pick 的菜单,其中列出了所有的 Node.js 进程。
没有使用
--inspect
选项的 Node.js 进程也显示在这里,但是选择之后不能进行断点调试。
我们选择通过 --inspect
选项运行 Node.js 程序,比如上面的 PID 为 40931 进程,然后就可以调试了。
但是修改代码保存之后,nodemon 重启进程,本身的 PID 没有变化,但是 nodemon 内部使用的 Node 进程发生了变化,导致 VS Code 调试被关闭。因此这个方案不可取。
# 启动配置
启动配置是在 VS Code 中设置调试的传统方式,可以为您提供运行复杂应用程序的配置选项。
在上一篇文章 创建 Node.js 服务 中,我们介绍了怎么创建启动配置,但是只配置了 Node.js: 启动程序
,其实 VS Code 还有很多的配置选项。
这里我们只关注 Node.js
调试器
# Node.js: 启动程序
在调试模式下启动 Node.js 程序。默认配置如下:
{
"name": "Launch Program",
"program": "${workspaceFolder}/index.js",
"request": "launch",
"skipFiles": ["<node_internals>/**"],
"type": "node"
}
2
3
4
5
6
7
配置项参数:
request
:launch
或者attach
,launch
表示从 VS Code 启动程序,attach
表示附加已经从别的应用启动的程序,例如上面介绍的 “附加到 Node.js”type
:调试器,VC Code 内置了 Node.js 的调试器node
,别的语言的调试器可能需要安装相应的扩展name
:配置项的名称program
:启动调试器时要运行的文件,${workspaceFolder}
表示项目根目录,关于变量的更多详情,请参考 Variables Reference (opens new window)skipFiles
:表示调试要跳过哪些文件,<node_internals>
表示 Node.js 的内置核心模块
此外我们还可以添加其它配置选项,如:
runtimeExecutable
:运行时可执行文件的绝对路径,默认是node
runtimeArgs
:运行时可执行文件的可选参数,比如要运行node --inspect
,runtimeArgs
设置为["--inspect"]
args
:运行程序的参数,就是我们自己写的程序需要的参数restart
:终止时是否重新启动连接,默认为false
cwd
:启动程序所在的目录
关于配置项的完整列表,请参考 VS Code 启动配置参数 (opens new window)
我们可以将 runtimeExecutable
设置为 nodemon
,从而实现开启 VS Code 调试,同时修改代码之后重启服务
{
"name": "Launch Program",
"program": "${workspaceFolder}/index.js",
"request": "launch",
"skipFiles": ["<node_internals>/**"],
"type": "node",
+ "runtimeExecutable": "nodemon"
}
2
3
4
5
6
7
8
# Node.js: Nodemon 安装程序
使用 nodemon
在代码发生更改时自动重新启动调试会话,默认配置如下:
{
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"name": "nodemon",
"program": "${workspaceFolder}/index.js",
"request": "launch",
"restart": true,
"runtimeExecutable": "nodemon",
"skipFiles": ["<node_internals>/**"],
"type": "node"
}
2
3
4
5
6
7
8
9
10
11
这里新增了几个选项参数:
console
:启动程序的控制台,默认是internalConsole
- VS Code 默认的调试控制台。integratedTerminal
- VS Code 的集成控制台。externalTerminal
- 外部控制台,当选择externalTerminal
可以配置要选择的外部终端
internalConsoleOptions
:VS Code 默认的调试控制台是否打开,因为启动程序的控制台选择的是 VS Code 的集成控制台,所以这里不需要打开neverOpen
这个跟我们前面修改的 Node.js: 启动程序
类似,只是添加了console
、internalConsoleOptions
和 restart
,所以它也实现了开启 VS Code 调试,同时修改代码之后重启服务。
# Node.js: 通过 npm 启动
通过 NPM Script 启动 Node.js 程序。默认配置如下:
{
"name": "Launch via NPM",
"request": "launch",
"runtimeArgs": ["run-script", "debug"],
"runtimeExecutable": "npm",
"skipFiles": ["<node_internals>/**"],
"type": "node"
}
2
3
4
5
6
7
8
调试时,我们可以通过调试控制台查看调试信息
我们可以看到,其实就是执行了 npm run-script dev
。
我们通过在 package.json
里配置
"scripts": {
"dev": "nodemon index.js",
}
2
3
可以实现开启 VS Code 调试,同时修改代码之后重启服务
# Node.js: 附加
附加到本地运行的 Node.js 程序的调试端口。
确保 Node.js 要调试的程序已在调试模式下启动,并且使用的调试端口与代码段中指定的端口相同,即使用 --inspect
选项运行 Node.js
默认配置如下:
{
"name": "Attach",
"port": 9229,
"request": "attach",
"skipFiles": ["<node_internals>/**"],
"type": "node"
}
2
3
4
5
6
7
port
: 要使用的调试端口,node --inspect index.js
默认端口号是9229
首先运行 nodemon --inspect index.js
,然后启动 Attach
,VS Code 就会自动连接上启动的进程,并打开调试。
和 “附加到 Node.js” 一样,修改代码保存之后,nodemon 重启进程,本身的 PID 没有变化,但是 nodemon 内部使用的 Node 进程发生了变化,导致 VS Code 调试被关闭。
但是通过设置 restart
为 true
,可以重新启动连接,从而实现开启 VS Code 调试,同时修改代码之后重启服务
{
"name": "Attach",
"port": 9229,
"request": "attach",
"skipFiles": ["<node_internals>/**"],
"type": "node",
"restart": true,
}
2
3
4
5
6
7
8
# Node.js: 附加到进程
和 Node.js: 附加
功能一样,不同的是 Node.js: 附加
通过端口,而 Node.js: 附加到进程
通过进程 ID。默认配置如下:
{
"name": "Attach by Process ID",
"processId": "${command:PickProcess}",
"request": "attach",
"skipFiles": ["<node_internals>/**"],
"type": "node"
}
2
3
4
5
6
7
processId
: Node.js 运行进程 ID。${command:PickProcess}
让你选择一个进程
和 “附加到 Node.js” 一样,修改代码保存之后,nodemon 重启进程,本身的 PID 没有变化,但是 nodemon 内部使用的 Node 进程发生了变化,导致 VS Code 调试被关闭。
但是同样通过设置 restart
为 true
,可以重新启动连接,从而实现开启 VS Code 调试,同时修改代码之后重启服务
{
"name": "Attach by Process ID",
"processId": "${command:PickProcess}",
"request": "attach",
"skipFiles": ["<node_internals>/**"],
"type": "node",
"restart": true,
}
2
3
4
5
6
7
8
# 总结
这篇文章讲解了 VS Code 调试 Node.js 有四种方法,同时搭配 nodemon
工具,实现既能打开调试,又能修改代码重启服务。现在总结一下:
方法 | 能否实现 | 是否推荐 |
---|---|---|
自动附加 | 能 | always 和 smart 可能会影响别的项目, onlyWithFlag 需要添加 --inspect 选项,不是很推荐 |
JavaScript 调试终端 | 能 | 推荐,很方便 |
附加到 Node.js | 不能 | 重启服务之后不能继续调试,因此不推荐 |
启动配置 | 能 | 推荐使用 Node.js: Nodemon 安装程序 配置 |