🚀 在 VS Code 中免費取得

在 VS Code 中偵錯 Node.js

Visual Studio Code 編輯器內建支援 Node.js 執行階段的偵錯功能,並且可以偵錯 JavaScript、TypeScript 以及許多其他轉譯成 JavaScript 的語言。在 VS Code 中設定 Node.js 偵錯專案非常簡單,VS Code 提供適當的啟動組態預設值和程式碼片段。

您可以使用幾種方式在 VS Code 中偵錯 Node.js 程式

自動附加

如果啟用「自動附加」功能,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 旗標啟動的處理程序。

啟用「自動附加」之後,您需要按一下終端機右上角的 ⚠ 圖示來重新啟動終端機,或直接建立新的終端機。然後,偵錯工具應該會在幾秒鐘內附加至您的程式

Auto Attach

當自動附加開啟時,「自動附加」項目會出現在 VS Code 視窗底部的狀態列中。按一下它可以變更自動附加模式,或暫時關閉它。如果您正在執行一些不需要偵錯的一次性程式,但您不想完全停用此功能,則暫時關閉自動附加功能會很有用。

其他組態

其他啟動組態屬性

您可以將通常在 launch.json 中找到的其他屬性套用至 debug.javascript.terminalOptions 設定中的自動附加。例如,若要將節點內部項目新增至您的 skipFiles,您可以將以下內容新增至您的使用者或工作區設定

  "debug.javascript.terminalOptions": {
    "skipFiles": [
      "<node_internals>/**"
    ]
  },

自動附加智慧型模式

smart 自動附加模式中,VS Code 會嘗試附加至您的程式碼,而不會附加至您不感興趣偵錯的建置工具。它會透過將主要指令碼與全域模式清單進行比對來完成此操作。全域模式可在 debug.javascript.autoAttachSmartPattern 設定中設定,預設為

[
  '!**/node_modules/**', // exclude scripts in node_modules folders
  '**/$KNOWN_TOOLS$/**' // but include some common tools
];

$KNOWN_TOOLS$ 會取代為常見「程式碼執行器」的清單,例如 ts-nodemochaava 等等。如果這些設定無效,您可以修改此清單。例如,若要排除 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 偵錯終端機」,來建立偵錯終端機。

Create Debug Terminal

其他組態

其他啟動組態屬性

您可以將通常在 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 選項文件中檢視完整的選項集。

以下屬性在類型為 launchattach 的啟動組態中受支援

  • outFiles - 用於尋找產生的 JavaScript 檔案的全域模式陣列。請參閱原始碼對應章節。
  • resolveSourceMapLocations - 用於原始碼對應應剖析位置的全域模式陣列。請參閱原始碼對應章節。
  • timeout - 重新啟動工作階段時,在此毫秒數之後放棄。請參閱附加至 Node.js 章節。
  • stopOnEntry - 程式啟動時立即中斷。
  • localRoot - VS Code 的根目錄。請參閱下方的遠端偵錯章節。
  • remoteRoot - Node 的根目錄。請參閱下方的遠端偵錯章節。
  • smartStep- 嘗試自動逐步執行未對應至原始檔的程式碼。請參閱智慧型逐步執行章節。
  • skipFiles - 自動略過這些全域模式涵蓋的檔案。請參閱略過不重要的程式碼章節。
  • trace - 啟用診斷輸出。

這些屬性僅適用於要求類型為 launch 的啟動組態

  • program - 要偵錯的 Node.js 程式的絕對路徑。
  • args - 傳遞至要偵錯的程式的引數。此屬性的類型為陣列,並預期個別引數為陣列元素。
  • cwd - 在此目錄中啟動要偵錯的程式。
  • runtimeExecutable - 要使用的執行階段可執行檔的絕對路徑。預設值為 node。請參閱「啟動組態支援 'npm' 和其他工具」章節。
  • runtimeArgs - 傳遞至執行階段可執行檔的選用引數。
  • runtimeVersion - 如果使用「nvm」(或「nvm-windows」) 或「nvs」來管理 Node.js 版本,則可以使用此屬性來選取特定版本的 Node.js。請參閱下方的多版本支援章節。
  • env - 選用環境變數。此屬性預期環境變數為字串類型鍵/值組的清單。
  • envFile - 包含環境變數定義的檔案的選用路徑。請參閱下方的從外部檔案載入環境變數章節。
  • console - 用於啟動程式的控制台 (internalConsoleintegratedTerminalexternalTerminal)。請參閱下方的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 configuration snippets for Node.js

您也可以使用 launch.json 編輯器視窗右下角的「新增組態...」按鈕來叫出程式碼片段。

Add Configuration button

以下程式碼片段可用

  • 啟動程式:在偵錯模式中啟動 Node.js 程式。
  • 透過 npm 啟動:透過 npm「debug」指令碼啟動 Node.js 程式。如果您的 package.json 中已定義 npm 偵錯指令碼,您可以從啟動組態中使用它。npm 指令碼中使用的偵錯連接埠必須與程式碼片段中指定的連接埠對應。
  • 附加:附加至在本機執行的 Node.js 程式的偵錯連接埠。請確定要偵錯的 Node.js 程式已在偵錯模式下啟動,且使用的偵錯連接埠與程式碼片段中指定的連接埠相同。
  • 附加至遠端程式:附加至在 address 屬性指定的主機上執行的 Node.js 程式的偵錯連接埠。請確定要偵錯的 Node.js 程式已在偵錯模式下啟動,且使用的偵錯連接埠與程式碼片段中指定的連接埠相同。為了協助 VS Code 在您的工作區和遠端主機的檔案系統之間對應原始檔,請務必為 localRootremoteRoot 屬性指定正確的路徑。
  • 依處理程序 ID 附加:開啟處理程序選取器,以選取節點或 gulp 處理程序進行偵錯。使用此啟動組態,您甚至可以附加至未在偵錯模式下啟動的節點或 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 Main:偵錯 Electron 應用程式的主要 Node.js 處理程序。程式碼片段假設 Electron 可執行檔已安裝在工作區的 node_modules/.bin 目錄中。

Node 控制台

預設情況下,Node.js 偵錯工作階段會在內部 VS Code 偵錯控制台中啟動目標。由於偵錯控制台不支援需要從控制台讀取輸入的程式,您可以透過將啟動組態中的 console 屬性分別設定為 externalTerminalintegratedTerminal,來啟用外部終端機或使用 VS Code 整合式終端機。預設值為 internalConsole

在外部終端機中,您可以透過 terminal.external.windowsExecterminal.external.osxExecterminal.external.linuxExec 設定來設定要使用的終端機程式。

啟動組態支援 'npm' 和其他工具

您可以直接從啟動組態中使用 'npm' 指令碼或其他工作執行器工具,而不是直接使用節點啟動 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.1nvs 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 偵錯工具可用的所有可能處理程序

Node.js Process picker

選取器中列出的個別處理程序會顯示偵錯連接埠和處理程序 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 偵錯工具與偵錯目標中斷連線,然後偵錯目標會繼續執行。

如果偵錯工作階段處於「啟動」模式,則按下「停止」會執行下列動作

  1. 第一次按下「停止」時,會要求偵錯目標透過傳送 SIGINT 訊號來正常關機。偵錯目標可以自由攔截此訊號並視需要清除任何內容,然後關機。如果該關機程式碼中沒有中斷點 (或問題),則偵錯目標和偵錯工作階段將會終止。

  2. 但是,如果偵錯工具在關機程式碼中遇到中斷點,或如果偵錯目標本身未正確終止,則偵錯工作階段將不會結束。在這種情況下,再次按下「停止」將強制終止偵錯目標及其子處理程序 (SIGKILL)。

如果您看到在按下紅色「停止」按鈕時偵錯工作階段未結束,請再次按下按鈕以強制關閉偵錯目標。

在 Windows 上,按下「停止」會強制終止偵錯目標及其子處理程序。

原始碼對應

VS Code 的 JavaScript 偵錯工具支援原始碼對應,這有助於偵錯轉譯語言,例如 TypeScript 或縮小/醜化 JavaScript。使用原始碼對應,可以單步執行或在原始碼中設定中斷點。如果原始碼沒有原始碼對應,或者如果原始碼對應損毀且無法在原始碼和產生的 JavaScript 之間成功對應,則中斷點會顯示為未驗證 (灰色空心圓圈)。

預設為 truesourceMaps 屬性控制原始碼對應功能。偵錯工具一律嘗試使用原始碼對應 (如果可以找到任何原始碼對應),因此,您甚至可以使用 program 屬性指定原始檔 (例如 app.ts)。如果您因為某些原因需要停用原始碼對應,您可以將 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 檔案的位置。

當您在啟用了 Source Map 的 TypeScript 中建置 app.ts 檔案時,它會產生一個 app.js.map 檔案,或是一個 Source Map 以 base64 編碼字串的形式內嵌在 app.js 檔案底部的註解中。為了找到與此 Map 相關聯的 .ts 檔案,偵錯配接器會查看 Source Map 中的兩個屬性:sourcessourceRootsourceRoot 是可選的 - 如果存在,它會被添加到 sources 中每個路徑的前面,而 sources 是一個路徑陣列。結果會是一個 .ts 檔案的絕對或相對路徑陣列。相對路徑會根據 Source Map 進行解析。

最後,偵錯配接器會在產生的 .ts 檔案列表中搜尋 app.ts 的完整路徑。如果找到相符項,它就找到了在將 app.ts 映射到 app.js 時要使用的 Source Map 檔案。如果沒有相符項,則它無法繫結中斷點,並且中斷點會變成灰色。

以下是一些在中斷點變成灰色時可以嘗試的方法

  • 在偵錯時,執行偵錯:診斷中斷點問題命令。此命令會彈出一個工具,可以從命令面板 (⇧⌘P (Windows、Linux Ctrl+Shift+P)) 中提供提示,以協助您解決任何問題。
  • 您是否已啟用 Source Map 建置?請確保有 .js.map 檔案,或是在您的 .js 檔案中有內嵌的 Source Map。
  • 您的 Source Map 中的 sourceRootsources 屬性是否正確?它們是否可以組合以取得 .ts 檔案的正確路徑?
  • 您是否在 VS Code 中以不正確的大小寫開啟了資料夾?有可能從命令列使用類似 code FOO 的方式開啟資料夾 foo/,在這種情況下,Source Map 可能無法正確解析。
  • 嘗試在 Stack Overflow 上搜尋關於您特定設定的幫助,或是在 GitHub 上提交 Issue。
  • 嘗試加入 debugger 陳述式。如果它在那裡中斷到 .ts 檔案,但該位置的中斷點未繫結,這是包含在 GitHub Issue 中的有用資訊。

覆寫 Source Map 路徑

偵錯工具使用 sourceMapPathOverrides 來實作自訂的 Source Map 到磁碟路徑的映射。大多數工具都已預設了良好的設定,但在進階情況下,您可能需要自訂它。預設的路徑覆寫是一個物件映射,看起來像這樣

{
  'webpack:///./~/*': "${workspaceFolder}/node_modules/*",
  'webpack:////*': '/*',
  'webpack://@?:*/?:*/*': "${workspaceFolder}/*",
  // and some more patterns...
}

這會將 Source Map 中的路徑或 URL 從左側映射到右側。?:* 模式是非貪婪、非捕獲的匹配,而 * 是貪婪捕獲的匹配。然後偵錯工具會將右側模式中對應的 * 替換為從 Source Map 路徑捕獲的片段。例如,上面範例中的最後一個模式會將 webpack://@my/package/foo/bar 映射到 ${workspaceFolder}/foo/bar

請注意,對於瀏覽器偵錯,預設的 sourceMapPathOverrides 中會使用 webRoot 來代替 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 開啟工作區中可編輯的來源程式碼,您可以設定遠端和本機位置之間的映射。可以使用 localRootremoteRoot 屬性來映射本機 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 檔案瀏覽輕鬆找到並開啟,您可以透過執行和偵錯檢視中的 LOADED SCRIPTS 檢視存取已載入的腳本

Loaded Scripts Explorer

LOADED SCRIPTS 檢視讓您能夠透過輸入腳本名稱快速選擇腳本,或在啟用類型篩選開啟時篩選列表。

腳本會載入到唯讀編輯器中,您可以在其中設定中斷點。這些中斷點會在偵錯工作階段中被記住,但您只能在偵錯工作階段執行時存取腳本內容。

在編輯原始碼時自動重新啟動偵錯工作階段

啟動設定的 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 偵錯工具支援在堆疊框架中重新啟動執行。當您在原始程式碼中發現問題,並且想要使用修改後的輸入值重新執行一小部分程式碼時,這會很有用。停止然後重新啟動完整的偵錯工作階段可能很耗時。重新啟動框架動作可讓您在使用設定值動作變更變數後重新進入目前的函式

Restart frame

重新啟動框架不會回滾函式外部狀態的變更,因此它可能並非總是如預期般運作。

中斷點

條件式中斷點

條件式中斷點是僅在運算式傳回真值時才會暫停的中斷點。您可以透過在行號旁的邊界中按一下滑鼠右鍵並選取「條件式中斷點」來建立一個。

Conditional breakpoint

記錄點

有時您只想在程式碼到達特定位置時記錄訊息或值,而不是暫停。您可以使用記錄點來執行此操作。記錄點不會暫停,而是在命中時將訊息記錄到偵錯主控台中。在 JavaScript 偵錯工具中,您可以使用大括號將運算式插入訊息中,例如 current value is: {myVariable.property}

您可以透過在行號旁的邊界中按一下滑鼠右鍵並選取「記錄點」來建立一個。例如,這可能會記錄類似 location is /usr/local 的內容

Logpoint

命中計數中斷點

「命中計數條件」控制中斷點在「中斷」執行之前需要被命中的次數。您可以透過在行號旁的邊界中按一下滑鼠右鍵、選取「條件式中斷點」,然後切換到「命中計數」來放置命中計數中斷點。

Hit count breakpoint

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 認為中斷點所在的位置顯示中斷點。在 BREAKPOINTS 區段中,這些中斷點會以請求行號和實際行號之間的箭頭顯示

Breakpoints View

當中斷點驗證發生在工作階段開始且中斷點已向 Node.js 註冊時,或當工作階段已在執行且已設定新的中斷點時。在這種情況下,中斷點可能會「跳轉」到不同的位置。在 Node.js 解析所有程式碼(例如,透過執行程式碼)之後,可以輕鬆地透過 BREAKPOINTS 區段標頭中的重新套用按鈕將中斷點重新套用到請求的位置。這應該會使中斷點「跳回」到請求的位置。

Breakpoint Actions

略過不重要的程式碼

VS Code Node.js 偵錯具有一項功能,可以避免逐步執行您不想逐步執行的原始程式碼(也稱為「Just My Code」)。可以使用啟動設定中的 skipFiles 屬性來啟用此功能。skipFiles 是要跳過的腳本路徑的 glob 模式陣列。

例如,使用

  "skipFiles": [
    "${workspaceFolder}/node_modules/**/*.js",
    "${workspaceFolder}/lib/**/*.js"
  ]

專案中 node_moduleslib 資料夾中的所有程式碼都將被跳過。skipFiles 也適用於在呼叫 console.log 和類似方法時顯示的位置:堆疊中的第一個非跳過位置將顯示在偵錯主控台中的輸出旁邊。

Node.js 的內建核心模組可以使用 glob 模式中的「magic name」 <node_internals> 來引用。以下範例會跳過所有內部模組

  "skipFiles": [
     "<node_internals>/**/*.js"
   ]

確切的「跳過」規則如下

  • 如果您逐步執行到跳過的檔案中,您不會停在那裡 - 您將停在下一個未在跳過檔案中的已執行行上。
  • 如果您已設定在擲回例外狀況時中斷的選項,那麼您將不會在從跳過檔案擲回的例外狀況中斷,除非它們向上冒泡到非跳過檔案中。
  • 如果您在跳過的檔案中設定中斷點,您將在該中斷點停止,並且您可以逐步執行它,直到您逐步退出它,屆時正常的跳過行為將恢復。
  • 來自跳過檔案內部的控制台訊息位置將顯示為呼叫堆疊中的第一個非跳過位置。

跳過的來源會在 CALL STACK 檢視中以「變暗」樣式顯示

Skipped source is dimmed in call stack view

將滑鼠游標懸停在變暗的項目上會說明堆疊框架變暗的原因。

呼叫堆疊上的內容選單項目切換跳過此檔案可讓您在執行階段輕鬆跳過檔案,而無需將其新增至啟動設定。此選項僅在目前的偵錯工作階段中持續存在。您也可以使用它來停止跳過啟動設定中 skipFiles 選項跳過的檔案。

注意: legacy 通訊協定偵錯工具支援負面的 glob 模式,但它們必須遵循正面的模式:正面的模式會新增到跳過檔案的集合中,而負面的模式會從該集合中減去。

在以下(僅限 legacy 通訊協定)範例中,除了「math」模組之外的所有模組都被跳過

"skipFiles": [
    "${workspaceFolder}/node_modules/**/*.js",
    "!${workspaceFolder}/node_modules/math/**/*.js"
]

注意: legacy 通訊協定偵錯工具必須模擬 skipFiles 功能,因為 V8 偵錯工具通訊協定本身不支援它。這可能會導致逐步執行效能緩慢。

偵錯 WebAssembly

JavaScript 偵錯工具可以偵錯編譯成 WebAssembly 的程式碼,如果它包含 DWARF 偵錯資訊。許多工具鏈都支援發出此資訊

  • C/C++ 與 Emscripten:使用 -g 旗標編譯以發出偵錯資訊。
  • Zig:DWARF 資訊會在「偵錯」建置模式中自動發出。
  • Rust:Rust 發出 DWARF 偵錯資訊。但是,wasm-pack 尚未在建置期間保留它。因此,常見的 wasm-bindgen/wasm-pack 程式庫的使用者不應執行 wasm-pack build,而應使用兩個命令手動建置
    1. 執行一次 cargo install wasm-bindgen-cli 以安裝必要的命令列工具。
    2. cargo build --target wasm32-unknown-unknown 以建置您的程式庫。
    3. 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 核心的「精簡」。安裝完成後,重新啟動任何活動的偵錯工作階段,然後原生程式碼應該會在偵錯工具中映射!您應該會在 Loaded Sources 檢視中看到您的原始程式碼出現,並且中斷點應該可以運作。

在下圖中,偵錯工具停在 C++ 原始程式碼中的中斷點上,該程式碼建立了一個曼德博分形。呼叫堆疊是可見的,其中包含來自 JavaScript 程式碼、WebAssembly 和映射的 C++ 程式碼的框架。您還可以查看 C++ 程式碼中的變數,以及對與 int32 height 變數關聯的記憶體的編輯。

Debugger stopped on a breakpoint in C++ source code

雖然接近同等水平,但偵錯 WebAssembly 與普通的 JavaScript 有些不同

  • 變數檢視中的變數無法直接編輯。但是,您可以選取變數旁邊的檢視二進位資料動作來編輯它們關聯的記憶體。
  • 偵錯主控台監看式 檢視中的基本運算式評估由 lldb-eval 提供。這與普通的 JavaScript 運算式不同。
  • 未映射到原始程式碼的位置將以反組譯的 WebAssembly 文字格式顯示。對於 WebAssembly,命令停用 Source Map 逐步執行會導致偵錯工具僅在反組譯的程式碼中逐步執行。

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 執行工作。顯示錯誤和警告

若要編寫您自己的偵錯工具擴充功能,請造訪

常見問題

可以,如果您已為專案內的資料夾建立符號連結,例如使用 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.jsonruntimeArgs 屬性傳遞這些選項

如何設定 NODE_OPTIONS?

偵錯工具使用特殊的 NODE_OPTIONS 環境變數來設定與應用程式的偵錯,覆寫它會阻止偵錯正常運作。您應該附加到它,而不是覆寫它。例如,.bashrc 檔案可能會有類似這樣的內容

export NODE_OPTIONS="$NODE_OPTIONS --some-other-option=here"