VS Code 中的 Node.js 调试
Visual Studio Code 编辑器内置了对 Node.js 运行时的调试支持,可以调试 JavaScript、TypeScript 以及许多其他编译成 JavaScript 的语言。使用 VS Code 提供的适当启动配置默认值和代码片段,为 Node.js 调试设置项目非常简单。
有几种方法可以在 VS Code 中调试 Node.js 程序
- 使用 自动附加 调试您在 VS Code 集成终端中运行的进程。
- 使用 JavaScript 调试终端,类似于使用集成终端。
- 使用 启动配置 启动程序,或 附加到在 VS Code 外部启动的进程。
自动附加
如果启用了 **自动附加** 功能,Node 调试器会自动附加到从 VS Code 集成终端启动的某些 Node.js 进程。要启用此功能,可以使用命令面板 (⇧⌘P (Windows、Linux Ctrl+Shift+P)) 中的 **切换自动附加** 命令,或者,如果它已经激活,可以使用状态栏中的 **自动附加** 项目。
自动附加有三种模式,您可以在结果的快速选择中以及通过 **debug.javascript.autoAttachFilter** 设置进行选择
smart
- 如果您在node_modules
文件夹之外执行脚本或使用像 mocha 或 ts-node 这样的通用“运行器”脚本,则会调试该进程。您可以使用 **自动附加智能模式** 设置 (debug.javascript.autoAttachSmartPattern
) 配置“运行器”脚本允许列表。always
- 集成终端中启动的所有 Node.js 进程都将被调试。onlyWithFlag
- 只有使用--inspect
或--inspect-brk
标志启动的进程才会被调试。
启用 **自动附加** 后,您需要通过单击终端右上角的 ⚠ 图标或只创建一个新的终端来重新启动您的终端。然后,调试器应该在一秒钟内附加到您的程序。
当自动附加打开时,自动附加
项目将出现在 VS Code 窗口底部的状态栏中。单击它可以更改自动附加模式,或暂时将其关闭。暂时关闭自动附加在您运行一些不需要调试的一次性程序时很有用,但您不想完全禁用此功能。
其他配置
其他启动配置属性
您可以将 launch.json 中通常找到的其他属性 应用于 **debug.javascript.terminalOptions** 设置中的自动附加。例如,要将节点内部添加到您的 skipFiles,您可以将以下内容添加到您的用户或工作区设置中
"debug.javascript.terminalOptions": {
"skipFiles": [
"<node_internals>/**"
]
},
自动附加智能模式
在 smart
自动附加模式下,VS Code 将尝试附加到您的代码,而不是附加到您不感兴趣调试的构建工具。它是通过将主脚本与 glob 模式 列表进行匹配来实现的。glob 模式可以在 **debug.javascript.autoAttachSmartPattern** 设置中配置,该设置默认值为
[
'!**/node_modules/**', // exclude scripts in node_modules folders
'**/$KNOWN_TOOLS$/**' // but include some common tools
];
$KNOWN_TOOLS$
被替换为一个常见的“代码运行器”列表,例如 ts-node
、mocha
、ava
等等。如果这些设置不起作用,您可以修改此列表。例如,要排除 mocha
并包含 my-cool-test-runner
,您可以添加两行
[
'!**/node_modules/**',
'**/$KNOWN_TOOLS$/**',
'!**/node_modules/mocha/**', // use "!" to exclude all scripts in "mocha" node modules
'**/node_modules/my-cool-test-runner/**' // include scripts in the custom test runner
];
JavaScript 调试终端
与 自动附加 类似,JavaScript 调试终端会自动调试您在其中运行的任何 Node.js 进程。您可以通过运行命令面板 (kbs(workbench.action.showCommands)
) 中的 **调试:创建 JavaScript 调试终端** 命令,或从终端切换器下拉菜单中选择 **创建 JavaScript 调试终端** 来创建一个调试终端。
其他配置
其他启动配置属性
您可以将 launch.json 中通常找到的其他属性 应用于 **debug.javascript.terminalOptions** 设置中的调试终端。例如,要将节点内部添加到您的 skipFiles,您可以将以下内容添加到您的用户或工作区设置中
"debug.javascript.terminalOptions": {
"skipFiles": [
"<node_internals>/**"
]
},
启动配置
启动配置是设置 VS Code 中调试的传统方法,并为您提供了运行复杂应用程序的大多数配置选项。
在本节中,我们将详细介绍更高级调试场景的配置和功能。您将找到使用 源映射、跨越外部代码、进行 远程调试 等的说明。
如果您想观看介绍性视频,请参阅 VS Code 中调试入门。
注意:如果您刚开始使用 VS Code,您可以在 调试 主题中了解一般调试功能和创建
launch.json
配置文件。
启动配置属性
调试配置存储在工作区 .vscode
文件夹中的 launch.json
文件中。关于创建和使用调试配置文件的介绍请参见一般 调试 文章。
以下是特定于 Node.js 调试器的常用 launch.json
属性的参考。您可以在 vscode-js-debug 选项 文档中查看完整的选项集。
以下属性在类型为 launch
和 attach
的启动配置中受支持
outFiles
- 用于查找生成的 JavaScript 文件的 glob 模式 数组。请参阅 源映射 部分。resolveSourceMapLocations
- 用于查找应解析源映射的位置的 glob 模式 数组。请参阅 源映射 部分。timeout
- 在重新启动会话时,在这么多毫秒后放弃。请参阅 附加到 Node.js 部分。stopOnEntry
- 程序启动时立即中断。localRoot
- VS Code 的根目录。请参阅以下 远程调试 部分。remoteRoot
- Node 的根目录。请参阅以下 远程调试 部分。smartStep
- 尝试自动单步执行不映射到源文件的代码。请参见智能单步执行部分。skipFiles
- 自动跳过这些glob 模式覆盖的文件。请参见跳过不感兴趣的代码部分。trace
- 启用诊断输出。
这些属性仅适用于请求类型为launch
的启动配置
program
- 要调试的 Node.js 程序的绝对路径。args
- 传递给要调试的程序的参数。此属性的类型为数组,并期望将各个参数作为数组元素。cwd
- 在此目录中启动要调试的程序。runtimeExecutable
- 要使用的运行时可执行文件的绝对路径。默认值为node
。请参见'npm' 和其他工具的启动配置支持部分。runtimeArgs
- 传递给运行时可执行文件的可选参数。runtimeVersion
- 如果使用 "nvm"(或 "nvm-windows")或 "nvs" 管理 Node.js 版本,则此属性可用于选择特定版本的 Node.js。请参见下面的多版本支持部分。env
- 可选的环境变量。此属性期望环境变量作为字符串类型的键值对列表。envFile
- 包含环境变量定义的文件的可选路径。请参见下面的从外部文件加载环境变量部分。console
- 启动程序的控制台(internalConsole
、integratedTerminal
、externalTerminal
)。请参见下面的Node 控制台部分。outputCapture
- 如果设置为std
,则进程 stdout/stderr 的输出将在调试控制台中显示,而不是通过调试端口监听输出。这对于将输出直接写入 stdout/stderr 流而不是使用console.*
API 的程序或日志库很有用。
此属性仅适用于请求类型为attach
的启动配置
restart
- 在终止时重新启动连接。请参见源代码编辑时自动重新启动调试会话部分。port
- 要使用的调试端口。请参见附加到 Node.js和远程调试部分。address
- 调试端口的 TCP/IP 地址。请参见附加到 Node.js和远程调试部分。processId
- 调试器在发送 USR1 信号后尝试附加到此进程。使用此设置,调试器可以附加到未在调试模式下启动的已运行进程。使用processId
属性时,调试端口将根据 Node.js 版本(和使用的协议)自动确定,不能显式配置。因此,不要指定port
属性。continueOnAttach
- 当我们附加到进程时,如果进程已暂停,是否继续执行进程。如果您使用--inspect-brk
启动程序,此选项很有用。
常见场景的启动配置
您可以在launch.json
文件中触发 IntelliSense(⌃Space(Windows、Linux Ctrl+Space))以查看常用 Node.js 调试场景的启动配置代码段。
您也可以使用launch.json
编辑器窗口右下角的“添加配置...”按钮调出代码段。
以下代码段可用
- 启动程序:在调试模式下启动 Node.js 程序。
- 通过 npm 启动:通过 npm 的“debug”脚本启动 Node.js 程序。如果您的 package.json 中定义了 npm 的调试脚本,则可以使用启动配置中的该脚本。npm 脚本中使用的调试端口必须与代码段中指定的端口一致。
- 附加:附加到本地运行的 Node.js 程序的调试端口。请确保要调试的 Node.js 程序已在调试模式下启动,并且使用的调试端口与代码段中指定的端口一致。
- 附加到远程程序:附加到在
address
属性指定的主机上运行的 Node.js 程序的调试端口。请确保要调试的 Node.js 程序已在调试模式下启动,并且使用的调试端口与代码段中指定的端口一致。为了帮助 VS Code 在工作区和远程主机的文件系统之间映射源文件,请确保为localRoot
和remoteRoot
属性指定正确的路径。 - 按进程 ID 附加:打开进程选择器以选择要调试的 node 或 gulp 进程。使用此启动配置,您甚至可以附加到未在调试模式下启动的 node 或 gulp 进程。
- Nodemon 设置:使用 nodemon 在 JavaScript 源代码发生更改时自动重新启动调试会话。请确保已在全局安装 nodemon。请注意,终止调试会话只会终止要调试的程序,而不是 nodemon 本身。要终止 nodemon,请在集成终端中按Ctrl+C。
- Mocha 测试:调试项目
test
文件夹中的 mocha 测试。请确保您的项目已在node_modules
文件夹中安装了“mocha”。 - Yeoman 生成器:调试 yeoman 生成器。代码段会要求您指定生成器的名称。请确保您的项目已在
node_modules
文件夹中安装了“yo”,并且已通过在项目文件夹中运行npm link
来安装生成项目以供调试。 - Gulp 任务:调试 gulp 任务。请确保您的项目已在
node_modules
文件夹中安装了“gulp”。 - Electron 主进程:调试 Electron 应用程序的主 Node.js 进程。代码段假设 Electron 可执行文件已安装在工作区的
node_modules/.bin
目录中。
Node 控制台
默认情况下,Node.js 调试会话会在 VS Code 的内部调试控制台中启动目标程序。由于调试控制台不支持需要从控制台读取输入的程序,您可以将启动配置中的console
属性分别设置为externalTerminal
或integratedTerminal
,以启用外部终端或使用 VS Code 集成终端。默认值为internalConsole
。
在外部终端中,您可以通过terminal.external.windowsExec
、terminal.external.osxExec
和terminal.external.linuxExec
设置来配置要使用的终端程序。
'npm' 和其他工具的启动配置支持
您可以从启动配置中直接使用“npm”脚本或其他任务运行器工具,而不是直接使用 node 启动 Node.js 程序。
- 您可以使用 PATH 上的任何程序(例如“npm”、“mocha”、“gulp”等)作为
runtimeExecutable
属性,并可以通过runtimeArgs
传递参数。 - 如果您的 npm 脚本或其他工具隐式指定了要启动的程序,则不必设置
program
属性。
让我们来看一个“npm”示例。如果您的package.json
包含一个“debug”脚本,例如
"scripts": {
"debug": "node myProgram.js"
},
相应的启动配置如下所示
{
"name": "Launch via npm",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "npm",
"runtimeArgs": ["run-script", "debug"]
}
多版本支持
如果您使用 "nvm"(或 "nvm-windows")管理 Node.js 版本,则可以在启动配置中指定runtimeVersion
属性来选择特定版本的 Node.js。
{
"type": "node",
"request": "launch",
"name": "Launch test",
"runtimeVersion": "14",
"program": "${workspaceFolder}/test.js"
}
如果您使用 "nvs" 管理 Node.js 版本,则可以使用runtimeVersion
属性来选择特定版本的 Node.js、架构和风格,例如
{
"type": "node",
"request": "launch",
"name": "Launch test",
"runtimeVersion": "chackracore/8.9.4/x64",
"program": "${workspaceFolder}/test.js"
}
请确保已安装要使用runtimeVersion
属性的 Node.js 版本,因为此功能不会自动下载和安装该版本。例如,如果您计划将"runtimeVersion": "7.10.1"
添加到启动配置,则必须从集成终端运行类似nvm install 7.10.1
或nvs add 7.10.1
的命令。
如果您省略次要版本和补丁版本,例如"runtimeVersion": "14"
,则将使用系统上安装的最新14.x.y
版本。
从外部文件加载环境变量
VS Code Node 调试器支持从文件加载环境变量并将其传递给 Node.js 运行时。要使用此功能,请在启动配置中添加envFile
属性,并指定包含环境变量的文件的绝对路径。
//...
"envFile": "${workspaceFolder}/.env",
"env": { "USER": "john doe" }
//...
env
字典中指定的任何环境变量都将覆盖从文件中加载的变量。
以下是一个.env
文件的示例
USER=doe
PASSWORD=abc123
# a comment
# an empty value:
empty=
# new lines expanded in quoted strings:
lines="foo\nbar"
附加到 Node.js
如果您要将 VS Code 调试器附加到外部 Node.js 程序,请按如下方式启动 Node.js
node --inspect program.js
或者,如果程序不应该开始运行,而必须等待调试器附加
node --inspect-brk program.js
将调试器附加到程序的选项
- 打开一个“进程选择器”,该选择器会列出所有可能的候选进程,并让您选择一个进程,或者
- 创建一个“附加”配置,明确指定所有配置选项,然后按F5。
让我们详细了解这些选项
附加到 Node 进程操作
命令面板(⇧⌘P(Windows、Linux Ctrl+Shift+P))中的“附加到 Node 进程”命令会打开一个快速选择菜单,该菜单会列出所有可供 Node.js 调试器使用的潜在进程。
选择器中列出的各个进程会显示调试端口和进程 ID。在该列表中选择 Node.js 进程后,Node.js 调试器将尝试附加到该进程。
除了 Node.js 进程之外,选择器还会显示使用各种形式的--inspect
参数启动的其他程序。这使得可以附加到 Electron 或 VS Code 的辅助进程。
设置“附加”配置
此选项需要更多工作,但与前两个选项相比,它允许您明确配置各种调试配置选项。
最简单的“附加”配置如下所示
{
"name": "Attach to Process",
"type": "node",
"request": "attach",
"port": 9229
}
端口9229
是--inspect
和--inspect-brk
选项的默认调试端口。要使用其他端口(例如12345
),请将其添加到选项中,例如:--inspect=12345
和--inspect-brk=12345
,并将启动配置中的port
属性更改为匹配的值。
要附加到未在调试模式下启动的 Node.js 进程,您可以通过将 Node.js 进程的进程 ID 指定为字符串来实现此操作
{
"name": "Attach to Process",
"type": "node",
"request": "attach",
"processId": "53426"
}
为了避免在启动配置中重复输入新的进程 ID,Node 调试支持一个命令变量PickProcess
,该变量将打开进程选择器(如上所示)。
使用PickProcess
变量,启动配置如下所示
{
"name": "Attach to Process",
"type": "node",
"request": "attach",
"processId": "${command:PickProcess}"
}
停止调试
使用“调试:停止”操作(在调试工具栏或通过“命令面板”提供)可以停止调试会话。
如果调试会话是在“附加”模式下启动的(并且调试工具栏中的红色终止按钮显示一个叠加的“插头”),则按**停止**将 Node.js 调试器从调试目标断开连接,然后调试目标继续执行。
如果调试会话处于“启动”模式,则按**停止**将执行以下操作
-
首次按**停止**时,会通过发送一个 `SIGINT` 信号来请求调试目标正常关闭。调试目标可以自由地拦截此信号并按需清理任何内容,然后关闭。如果关闭代码中没有断点(或问题),则调试目标和调试会话将终止。
-
但是,如果调试器在关闭代码中命中断点,或者调试目标本身没有正常终止,则调试会话不会结束。在这种情况下,再次按**停止**将强制终止调试目标及其子进程(`SIGKILL`)。
如果您发现调试会话在按下红色**停止**按钮时没有结束,请再次按下该按钮以强制关闭调试目标。
在 Windows 上,按**停止**将强制杀死调试目标及其子进程。
源映射
VS Code 的 JavaScript 调试器支持源映射,有助于调试转译语言,例如 TypeScript 或缩小/丑化的 JavaScript。使用源映射,可以单步执行或在原始源中设置断点。如果原始源不存在源映射,或者源映射损坏并且无法成功地在源和生成的 JavaScript 之间进行映射,则断点将显示为未验证(灰色空心圆圈)。
默认值为 `true` 的 `sourceMaps` 属性控制源映射功能。调试器始终尝试使用源映射(如果能找到任何源映射),因此您甚至可以指定一个源文件(例如,app.ts)与 `program` 属性。如果您出于某种原因需要禁用源映射,可以将 `sourceMaps` 属性设置为 `false`。
工具配置
由于源映射并不总是自动创建,因此您应该确保配置您的转译器以创建源映射。例如
TypeScript
对于 TypeScript,您可以通过将 `--sourceMap` 传递给 `tsc` 或在您的 tsconfig.json 文件中添加 `"sourceMap": true` 来启用源映射。
tsc --sourceMap --outDir bin app.ts
Babel
对于 Babel,您需要将 sourceMaps 选项设置为 `true`,或者在编译代码时传递 `--source-maps` 选项。
npx babel script.js --out-file script-compiled.js --source-maps
Webpack
Webpack 有 许多 源映射选项。我们建议在您的 `webpack.config.js` 中将 `devtool: "source-map"` 属性设置为最佳结果保真度,尽管您可以尝试其他设置会导致构建速度变慢。
此外,如果您在 webpack 中有其他编译步骤,例如使用 TypeScript 加载器,您还需要确保这些步骤被设置为生成源映射。否则,webpack 生成的源映射将映射回来自加载器的编译代码,而不是真正的源代码。
源映射发现
默认情况下,VS Code 将搜索您的整个工作区(不包括 `node_modules`),以查找源映射。在大型工作区中,此搜索可能很慢。您可以通过在您的 `launch.json` 中设置 `outFiles` 属性来配置 VS Code 将在其中搜索源映射的位置。例如,此配置将仅发现 `bin` 文件夹中 `js` 文件的源映射
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch TypeScript",
"type": "node",
"request": "launch",
"program": "app.ts",
"outFiles": ["${workspaceFolder}/bin/**/*.js"]
}
]
}
请注意,`outFiles` 应该与您的 JavaScript 文件匹配,而不是源映射文件(它们可能以 `map` 而不是 `js` 结尾)。
源映射解析
默认情况下,只会解析您 `outFiles` 中的源映射。此行为用于防止依赖项干扰您设置的断点。例如,如果您有一个文件 `src/index.ts`,并且一个依赖项有一个源映射,该源映射引用了 `webpack:///./src/index.ts`,那么它将错误地解析为您的源文件,并可能导致意外的结果。
您可以通过设置 `resolveSourceMapLocations` 选项来配置此行为。如果设置为 `null`,则将解析每个源映射。例如,此配置将另外允许解析 `node_modules/some-dependency` 中的源映射
"resolveSourceMapLocations": [
"out/**/*.js",
"node_modules/some-dependency/**/*.js",
]
智能单步执行
在启动配置中将 `smartStep` 属性设置为 `true` 时,VS Code 在调试器中单步执行代码时会自动跳过“不重要的代码”。“不重要的代码”是由转译过程生成的代码,但未被源映射覆盖,因此它不会映射回原始源。当您在调试器中单步执行源代码时,这些代码会阻碍您的操作,因为它会导致调试器在您不感兴趣的原始源代码和生成的代码之间切换。`smartStep` 会自动单步执行未被源映射覆盖的代码,直到它再次到达被源映射覆盖的位置。
智能单步执行对于 TypeScript 中的 async/await 降级编译等情况特别有用,在这些情况下,编译器会注入未被源映射覆盖的辅助代码。
`smartStep` 功能仅适用于从源代码生成的 JavaScript 代码,因此它具有源映射。对于没有源代码的 JavaScript,智能单步执行选项无效。
JavaScript 源映射提示
使用源映射进行调试时,一个常见问题是,您会设置一个断点,它会变成灰色。如果您将光标悬停在其上,您将看到消息“断点被忽略,因为未找到生成的代码(源映射问题?)”。现在怎么办?会导致这种情况的范围很广。首先,简单介绍一下 Node 调试适配器如何处理源映射。
当您在 `app.ts` 中设置断点时,调试适配器必须确定 `app.js` 的路径,即 TypeScript 文件的转译版本,它是在 Node 中实际运行的。但是,从 `.ts` 文件开始,没有一种直接的方法来确定这一点。相反,调试适配器使用 `launch.json` 中的 `outFiles` 属性来查找所有转译的 `.js` 文件,并解析它们以查找源映射,该映射包含其关联的 `.ts` 文件的位置。
当您使用启用的源映射在 TypeScript 中构建 `app.ts` 文件时,它会生成一个 `app.js.map` 文件,或者一个作为 base64 编码字符串内嵌在 `app.js` 文件末尾注释中的源映射。为了找到与此映射相关的 `.ts` 文件,调试适配器会查看源映射中的两个属性,`sources` 和 `sourceRoot`。`sourceRoot` 是可选的 - 如果存在,它会附加到 `sources` 中的每个路径之前,`sources` 是路径数组。结果是一个包含 `.ts` 文件的绝对路径或相对路径的数组。相对路径相对于源映射解析。
最后,调试适配器在此生成的 `.ts` 文件列表中搜索 `app.ts` 的完整路径。如果存在匹配项,它将找到在映射 `app.ts` 到 `app.js` 时要使用的源映射文件。如果没有匹配项,则它无法绑定断点,它将变成灰色。
以下是一些当您的断点变成灰色时可以尝试的操作
- 在调试时,运行**调试:诊断断点问题**命令。此命令将弹出一个工具,该工具可以提供提示来帮助您解决来自命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 的任何问题。
- 您是否启用了源映射构建?确保存在 `.js.map` 文件,或者在您的 `.js` 文件中内嵌源映射。
- 源映射中的 `sourceRoot` 和 `sources` 属性是否正确?它们是否可以组合起来得到 `.ts` 文件的正确路径?
- 您是否在 VS Code 中以错误的大小写打开了文件夹?有可能从命令行以 `code FOO` 的方式打开 `foo/` 文件夹,在这种情况下,源映射可能无法正确解析。
- 尝试在 Stack Overflow 上搜索有关您的特定设置的帮助,或者在 GitHub 上提交问题。
- 尝试添加一个 `debugger` 语句。如果它在 `.ts` 文件中断开,但该位置的断点没有绑定,则这是包含在 GitHub 问题中的有用信息。
覆盖源映射路径
调试器使用 `sourceMapPathOverrides` 来实现自定义源映射到磁盘路径的映射。大多数工具都提供了良好的默认设置,但在高级情况下,您可能需要对其进行自定义。默认路径覆盖是一个类似于这样的对象映射
{
'webpack:///./~/*': "${workspaceFolder}/node_modules/*",
'webpack:////*': '/*',
'webpack://@?:*/?:*/*': "${workspaceFolder}/*",
// and some more patterns...
}
这会将源映射中的路径或 URL 从左侧映射到右侧。模式 `?:*` 是一个非贪婪的、非捕获的匹配,而 `*` 是一个贪婪的捕获匹配。然后,调试器会将右侧模式中的相应 `*` 替换为从源映射路径捕获的片段。例如,上面示例中的最后一个模式会将 `webpack://@my/package/foo/bar` 映射到 `${workspaceFolder}/foo/bar`。
请注意,对于浏览器调试,`webRoot` 将在默认的 `sourceMapPathOverrides` 中代替 `workspaceFolder`。
远程调试
**注意:**VS Code 现在具有通用的 远程开发功能。使用 远程开发 扩展,在远程场景和容器中的 Node.js 开发与本地设置中的 Node.js 开发没有区别。**这是远程调试 Node.js 程序的推荐方法**。查看 入门 部分和 远程教程 以了解更多信息。
如果您无法使用任何远程开发扩展来调试 Node.js 程序,以下是有关如何从您的本地 VS Code 实例调试远程 Node.js 程序的指南。
Node.js 调试器支持远程调试,您可以在其中附加到在不同机器上或容器中运行的进程。通过 `address` 属性指定远程主机。例如
{
"type": "node",
"request": "attach",
"name": "Attach to remote",
"address": "192.168.148.2", // <- remote address here
"port": 9229
}
默认情况下,VS Code 会将调试的源代码从远程 Node.js 文件夹流到本地 VS Code 并将其显示在只读编辑器中。您可以单步执行此代码,但无法修改它。如果您希望 VS Code 打开工作区中的可编辑源代码,则可以设置本地 VS Code 项目和(远程)Node.js 文件夹之间的路径映射。可以使用 `localRoot` 和 `remoteRoot` 属性来映射本地 VS Code 项目和(远程)Node.js 文件夹之间的路径。这甚至可以在同一系统上的本地或跨不同操作系统运行。每当需要将代码路径从远程 Node.js 文件夹转换为本地 VS Code 路径时,都会从路径中剥离 `remoteRoot` 路径并将其替换为 `localRoot`。对于反向转换,`localRoot` 路径将被 `remoteRoot` 替换。
{
"type": "node",
"request": "attach",
"name": "Attach to remote",
"address": "TCP/IP address of process to be debugged",
"port": 9229,
"localRoot": "${workspaceFolder}",
"remoteRoot": "C:\\Users\\username\\project\\server"
}
访问已加载的脚本
如果您需要在不在工作区内且因此无法通过正常的 VS Code 文件浏览轻松定位和打开的脚本中设置断点,则可以通过**运行和调试**视图中的**加载的脚本**视图访问加载的脚本
**加载的脚本**视图允许您通过键入脚本名称或在**启用类型过滤器**处于打开状态时筛选列表来快速选择脚本。
脚本被加载到一个只读编辑器中,您可以在其中设置断点。这些断点会在调试会话之间保留,但您只有在调试会话运行时才能访问脚本内容。
在编辑源代码时自动重新启动调试会话
启动配置的 restart
属性控制 Node.js 调试器在调试会话结束时是否自动重启。如果您使用 nodemon 来重启 Node.js 以应对文件更改,此功能将非常有用。将启动配置属性 restart
设置为 true
将使 Node 调试器在 Node.js 终止后自动尝试重新连接到 Node.js。
如果您已通过以下方式在命令行中通过 nodemon 启动了程序 server.js
nodemon --inspect server.js
您可以使用以下启动配置将 VS Code 调试器附加到它
{
"name": "Attach to node",
"type": "node",
"request": "attach",
"restart": true,
"port": 9229
}
或者,您可以通过启动配置直接通过 nodemon 启动程序 server.js
并附加 VS Code 调试器
{
"name": "Launch server.js via nodemon",
"type": "node",
"request": "launch",
"runtimeExecutable": "nodemon",
"program": "${workspaceFolder}/server.js",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
}
提示:按下 停止 按钮会停止调试会话并断开与 Node.js 的连接,但 nodemon(和 Node.js)将继续运行。要停止 nodemon,您必须从命令行将其杀死(如果您使用如上所示的
integratedTerminal
,则很容易做到)。
提示:如果出现语法错误,nodemon 将无法成功启动 Node.js,直到错误被修复。在这种情况下,VS Code 将继续尝试连接到 Node.js,但最终会放弃(10 秒后)。为避免这种情况,您可以通过添加一个具有更大值(以毫秒为单位)的
timeout
属性来增加超时时间。
重新启动帧
Node 调试器支持在堆栈帧中重启执行。这在您在源代码中发现问题并希望用修改后的输入值重新运行一小部分代码的情况下非常有用。停止然后重启整个调试会话可能很耗时。重启帧 操作允许您在使用 设置值 操作更改变量后重新进入当前函数。
重启帧 不会回滚对函数之外状态的变异,因此它可能并不总是按预期工作。
断点
条件断点
条件断点是指只有在表达式返回真值时才会暂停的断点。您可以通过右键单击行号旁边的代码行并选择“条件断点”来创建一个。
日志点
有时您只想在代码到达某个位置时记录一条消息或值,而不是暂停。您可以使用日志点来做到这一点。日志点不会暂停,而是在到达时将一条消息记录到调试控制台。在 JavaScript 调试器中,您可以使用大括号将表达式插入消息中,例如 current value is: {myVariable.property}
。
您可以通过右键单击行号旁边的代码行并选择“日志点”来创建一个。例如,这可能会记录类似 location is /usr/local
的内容。
命中次数断点
“命中次数条件”控制断点需要命中多少次才能“中断”执行。您可以通过右键单击行号旁边的代码行,选择“条件断点”,然后切换到“命中次数”来放置命中次数断点。
Node.js 调试器支持的命中次数语法是整数或运算符 <
、<=
、==
、>
、>=
、%
后跟整数。
一些示例
>10
在 10 次命中后始终中断<3
仅在前两次命中时中断10
与>=10
相同%2
每隔一次命中就中断
触发断点
触发断点是一种在另一个断点被命中后自动启用的断点。在诊断仅在特定前提条件满足后才会发生的代码中的故障情况时,它们非常有用。
可以通过右键单击符号边距,选择 添加触发断点,然后选择哪个断点启用断点来设置触发断点。
断点验证
出于性能原因,Node.js 会在第一次访问时延迟解析 JavaScript 文件中的函数。因此,断点在 Node.js 未看到(解析)的源代码区域中不起作用。
由于这种行为对于调试来说并不理想,VS Code 会自动将 --nolazy
选项传递给 Node.js。这可以防止延迟解析并确保可以在运行代码之前验证断点(因此它们不再“跳跃”)。
由于 --nolazy
选项可能会显着增加调试目标的启动时间,您可以通过将 --lazy
作为 runtimeArgs
属性传递来轻松选择退出。
在这种情况下,您会发现一些断点不会“粘贴”到请求的行,而是“跳跃”到已解析代码中下一个可能的行。为了避免混淆,VS Code 始终在 Node.js 认为断点所在的位置显示断点。在 断点 部分,这些断点用请求行号和实际行号之间的箭头表示
这种断点验证发生在会话开始时,断点向 Node.js 注册,或者会话正在运行时设置新断点。在这种情况下,断点可能会“跳跃”到另一个位置。在 Node.js 解析完所有代码(例如,通过运行它)之后,可以使用 断点 部分标题中的 重新应用 按钮轻松将断点重新应用到请求的位置。这应该使断点“跳回”到请求的位置。
跳过不重要的代码
VS Code Node.js 调试器具有一个功能,可以避免您不想单步执行的源代码(也称为“仅我的代码”)。此功能可以通过启动配置中的 skipFiles
属性启用。skipFiles
是要跳过的脚本路径的 glob 模式 数组。
例如,使用
"skipFiles": [
"${workspaceFolder}/node_modules/**/*.js",
"${workspaceFolder}/lib/**/*.js"
]
项目中 node_modules
和 lib
文件夹中的所有代码将被跳过。skipFiles
也适用于在调用 console.log
和类似方法时显示的位置:堆栈中的第一个非跳过位置将显示在调试控制台中的输出旁边。
Node.js 的内置 核心模块 可以通过 glob 模式 中的“魔法名称”<node_internals>
来引用。以下示例跳过所有内部模块
"skipFiles": [
"<node_internals>/**/*.js"
]
确切的“跳过”规则如下
- 如果您单步进入跳过的文件,您不会在那里停止 - 您将在下一个执行的不在跳过文件中的行停止。
- 如果您已将选项设置为在抛出异常时中断,那么您将不会在从跳过文件抛出的异常处中断,除非它们冒泡到非跳过文件。
- 如果您在跳过文件中设置断点,您将在该断点处停止,并且可以单步执行它,直到您单步跳出它,此时将恢复正常的跳过行为。
- 来自跳过文件内部的控制台消息的位置将显示为调用堆栈中的第一个非跳过位置。
跳过的源代码在 CALL STACK 视图中以“灰显”样式显示。
将鼠标悬停在灰显的条目上解释了堆栈帧为什么被灰显。
调用堆栈上的上下文菜单项 切换跳过此文件 使您能够轻松地在运行时跳过文件,而无需将其添加到您的启动配置中。此选项仅在当前调试会话中持续有效。您也可以使用它来停止跳过由启动配置中的 skipFiles
选项跳过的文件。
注意:
legacy
协议调试器支持负 glob 模式,但它们必须 位于 正模式之后:正模式添加到跳过文件集中,而负模式从该集中减去。
在以下(仅限 legacy
协议)示例中,除了“math”模块之外的所有模块都被跳过
"skipFiles": [
"${workspaceFolder}/node_modules/**/*.js",
"!${workspaceFolder}/node_modules/math/**/*.js"
]
注意:
legacy
协议调试器必须模拟skipFiles
功能,因为 V8 调试器协议 本身不支持它。这可能会导致单步执行性能下降。
调试 WebAssembly
JavaScript 调试器可以调试编译成 WebAssembly 的代码,如果它包含 DWARF 调试信息。许多工具链支持发出此信息。
- 使用 Emscripten 的 C/C++:使用
-g
标志编译以发出调试信息。 - Zig:DWARF 信息在“调试”构建模式中自动发出。
- Rust:Rust 发出 DWARF 调试信息。但是,wasm-pack 尚未 在构建过程中保留它。因此,用户应手动构建,而不是运行
wasm-pack build
,使用两个命令来构建常见的 wasm-bindgen/wasm-pack 库cargo install wasm-bindgen-cli
一次以安装必要的命令行工具。cargo build --target wasm32-unknown-unknown
来构建您的库。wasm-bindgen --keep-debug --out-dir pkg ./target/wasm32-unknown-unknown/debug/<library-name>.wasm <extra-arguments>
来生成 WebAssembly 绑定,将<library-name>
替换为 Cargo.toml 中的名称,并根据需要配置<extra-arguments>
。
构建完代码后,您需要安装 WebAssembly DWARF 调试 扩展。这作为单独的扩展提供,以便保持 VS Code 核心“精简”。安装完成后,重新启动任何活动的调试会话,然后本机代码应该在调试器中被映射!您应该会看到源代码出现在 加载的源 视图中,断点应该可以工作。
在下图中,调试器在一个 C++ 源代码中的断点处停止,该断点创建了曼德勃罗特分形。调用堆栈是可见的,包括来自 JavaScript 代码到 WebAssembly 到映射的 C++ 代码的帧。您还可以看到 C++ 代码中的变量,以及对与 int32 height
变量关联的内存的编辑。
虽然接近一致,但调试 WebAssembly 与普通 JavaScript 有些不同。
- 变量 视图中的变量不能直接编辑。但是,您可以选择变量旁边的 查看二进制数据 操作来编辑它们关联的内存。
- 调试控制台 和 监视 视图中的基本表达式评估由 lldb-eval 提供。这与普通 JavaScript 表达式不同。
- 未映射到源代码的位置将以反汇编的 WebAssembly 文本格式显示。对于 WebAssembly,命令 禁用源映射单步执行 将导致调试器仅在反汇编代码中单步执行。
VS Code 的 WebAssembly 调试是基于 Chromium 作者的 C/C++ 调试扩展。
支持的类 Node 运行时
当前 VS Code JavaScript 调试器支持 8.x 及更高版本的 Node 版本、最近的 Chrome 版本和最近的 Edge 版本(通过 msedge
启动类型)。
后续步骤
如果您还没有阅读 Node.js 部分,请查看
- Node.js - 使用示例应用程序的端到端 Node 场景
要观看有关 VS Code 中调试基础知识的教程,请查看此视频
要了解有关 VS Code 的任务运行支持的信息,请访问
- 任务 - 使用 Gulp、Grunt 和 Jake 运行任务。显示错误和警告
要编写自己的调试器扩展,请访问
- 调试器扩展 - 从模拟示例开始创建 VS Code 调试扩展的步骤
常见问题
如果我使用符号链接,可以调试吗?
可以,如果您为项目中的文件夹创建了符号链接(例如使用npm link
),则可以通过告诉 Node.js 运行时保留符号链接路径来调试符号链接的源代码。在您的启动配置runtimeArgs
属性中使用 node.exe 的--preserve-symlinks
开关。runtimeArgs
是一个字符串数组,传递给调试会话运行时可执行文件,默认情况下为 node.exe。
{
"runtimeArgs": ["--preserve-symlinks"]
}
如果您的主脚本位于符号链接路径中,那么您还需要添加"--preserve-symlinks-main"
选项。此选项仅在 Node 10+ 中可用。
如何调试 ECMAScript 模块?
如果您使用 esm 或将--experimental-modules
传递给 Node.js 以使用 ECMAScript 模块,则可以通过launch.json
的runtimeArgs
属性传递这些选项。
"runtimeArgs": ["--experimental-modules"]
- 在 Node v8.5.0+ 中使用 实验性的 ECMAScript 模块支持"runtimeArgs": ["-r", "esm"]
- 使用 esm ES 模块加载器(["-r esm"]
不会使用逗号)
如何设置 NODE_OPTIONS?
调试器使用特殊的NODE_OPTIONS
环境变量来设置与您的应用程序的调试,覆盖它将阻止调试正常工作。您应该将它追加到环境变量而不是覆盖它。例如,.bashrc
文件可能包含以下内容
export NODE_OPTIONS="$NODE_OPTIONS --some-other-option=here"