🚀 在 VS Code 中取得

Node.js 在 VS Code 中偵錯

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

您可以使用幾種方式在 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 會嘗試附加至您的程式碼,而不會附加至您不感興趣偵錯的建置工具。它會透過將主要指令碼與 glob 模式清單進行比對來執行此動作。glob 模式可在 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 - glob 模式陣列,用於尋找產生的 JavaScript 檔案。請參閱原始碼地圖章節。
  • 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 - 啟動程式的控制台 (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「偵錯」指令碼啟動 Node.js 程式。如果您的 package.json 中已定義 npm 偵錯指令碼,您可以從啟動組態中使用它。npm 指令碼中使用的偵錯連接埠必須與程式碼片段中指定的連接埠對應。
  • 附加:附加至本機執行之 Node.js 程式的偵錯連接埠。請確定要偵錯的 Node.js 程式已在偵錯模式下啟動,且使用的偵錯連接埠與程式碼片段中指定的連接埠相同。
  • 附加至遠端程式:附加至 address 屬性所指定主機上執行的 Node.js 程式的偵錯連接埠。請確定要偵錯的 Node.js 程式已在偵錯模式下啟動,且使用的偵錯連接埠與程式碼片段中指定的連接埠相同。為了協助 VS Code 對應工作區和遠端主機檔案系統之間的原始檔,請確定為 localRootremoteRoot 屬性指定正確的路徑。
  • 依處理程序識別碼附加:開啟處理程序選取器以選取節點或 gulp 處理程序進行偵錯。透過此啟動組態,您甚至可以附加至未在偵錯模式下啟動的節點或 gulp 處理程序。
  • Nodemon 設定:每當 JavaScript 原始碼變更時,使用 nodemon 自動重新啟動偵錯工作階段。請確定您已全域安裝 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 處理程序動作

命令面板中的附加至 Node 處理程序命令 (⇧⌘P (Windows、Linux Ctrl+Shift+P)) 會開啟一個快速選取功能表,其中列出 Node.js 偵錯工具可用的所有潛在處理程序

Node.js Process picker

選取器中列出的個別處理程序會顯示偵錯連接埠和處理程序識別碼。一旦您在清單中選取 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 處理程序的處理程序識別碼指定為字串來執行此動作

{
  "name": "Attach to Process",
  "type": "node",
  "request": "attach",
  "processId": "53426"
}

為了避免在啟動組態中重複輸入新的處理程序識別碼,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 檔案,或是一個內嵌在 app.js 檔案底部的註解中,以 base64 編碼字串形式呈現的原始碼地圖。為了找到與此地圖相關聯的 .ts 檔案,偵錯配接器會查看原始碼地圖中的兩個屬性:sourcessourceRootsourceRoot 是選填的 - 如果存在,它會被加到 sources 中的每個路徑前面,而 sources 是一個路徑陣列。結果會是一個指向 .ts 檔案的絕對或相對路徑陣列。相對路徑會相對於原始碼地圖來解析。

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

以下是一些當中斷點變成灰色時可以嘗試的事項

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

覆寫原始碼地圖路徑

偵錯工具使用 sourceMapPathOverrides 來實作自訂的原始碼地圖到磁碟路徑的對應。對於大多數工具,都有良好的預設值,但在進階情況下,您可能需要自訂它。預設的路徑覆寫是一個物件地圖,如下所示

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

這會將原始碼地圖中的路徑或 URL 從左側對應到右側。模式 ?:* 是一個非貪婪、非捕獲的匹配,而 * 是一個貪婪的捕獲匹配。然後,偵錯工具會將右側模式中對應的 * 替換為從原始碼地圖路徑捕獲的片段。例如,上面範例中的最後一個模式會將 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 View

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

Breakpoint Actions

略過不感興趣的程式碼

VS Code Node.js 偵錯具有一項功能,可以避免逐步執行您不想逐步執行的原始碼(也稱為「僅我的程式碼」)。可以使用啟動組態中的 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 Debugger Protocol 原生不支援它。這可能會導致逐步執行效能緩慢。

偵錯 WebAssembly

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

  • C/C++ with Emscripten:使用 -g 旗標編譯以發出偵錯資訊。
  • Zig:DWARF 資訊在「Debug」建置模式中自動發出。
  • 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 Debugging 擴充功能。這是作為一個單獨的擴充功能發布的,目的是保持 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,命令停用原始碼地圖逐步執行將導致偵錯工具僅在反組譯的程式碼中逐步執行。

VS Code 的 WebAssembly 偵錯是基於 Chromium 作者的 C/C++ Debugging Extension 建構的。

支援的類 Node.js 執行階段

目前的 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"