VS Codeのエージェントモードを拡張するには、を試してください!

VS Code での Node.js デバッグ

Visual Studio Code エディターには、Node.js ランタイムのデバッグ サポートが組み込まれており、JavaScript、TypeScript、および JavaScript にトランスパイルされる他の多くの言語をデバッグできます。Node.js デバッグ用のプロジェクト設定は簡単で、VS Code は適切な起動構成の既定値とスニペットを提供します。

VS Code で Node.js プログラムをデバッグするには、いくつかの方法があります。

自動アタッチ

[自動アタッチ] 機能が有効な場合、Node デバッガーは VS Code の統合ターミナルから起動された特定の Node.js プロセスに自動的にアタッチします。この機能を有効にするには、コマンド パレット (⇧⌘P (Windows, Linux Ctrl+Shift+P)) から [Toggle Auto Attach (自動アタッチの切り替え)] コマンドを使用するか、既にアクティブになっている場合は [自動アタッチ] ステータス バー項目を使用します。

自動アタッチには 3 つのモードがあり、表示されるクイック ピックと debug.javascript.autoAttachFilter 設定で選択できます。

  • smart - node_modules フォルダーの外でスクリプトを実行するか、mocha や ts-node のような一般的な「ランナー」スクリプトを使用すると、プロセスがデバッグされます。「ランナー」スクリプトの許可リストは、Auto Attach Smart Pattern (debug.javascript.autoAttachSmartPattern) 設定を使用して構成できます。
  • always - 統合ターミナルで起動されたすべての Node.js プロセスがデバッグされます。
  • onlyWithFlag - --inspect または --inspect-brk フラグで起動されたプロセスのみがデバッグされます。

自動アタッチを有効にした後、ターミナルの右上にある ⚠ アイコンをクリックするか、新しいターミナルを作成してターミナルを再起動する必要があります。その後、デバッガーは 1 秒以内にプログラムにアタッチするはずです。

Auto Attach

自動アタッチがオンの場合、VS Code ウィンドウの下部にあるステータス バーに Auto Attach 項目が表示されます。これをクリックすると、自動アタッチ モードを変更したり、一時的にオフにしたりできます。一時的に自動アタッチをオフにするのは、デバッグが不要な一度限りのプログラムを実行しているが、機能を完全に無効にしたくない場合に便利です。

追加の構成

その他の起動構成プロパティ

通常 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 を含めるには、次の 2 行を追加できます。

[
  '!**/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)) から Debug: Create JavaScript Debug Terminal (デバッグ: JavaScript デバッグ ターミナルの作成) コマンドを実行するか、ターミナル切り替えドロップダウンから Create JavaScript Debug Terminal (JavaScript デバッグ ターミナルの作成) を選択します。

Create Debug Terminal

追加の構成

その他の起動構成プロパティ

通常 launch.json に見られる他のプロパティを、debug.javascript.terminalOptions 設定でデバッグ ターミナルに適用できます。たとえば、ノードの内部を skipFiles に追加するには、ユーザーまたはワークスペースの設定に次のように追加できます。

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

起動構成

起動構成は VS Code でデバッグを設定する伝統的な方法であり、複雑なアプリケーションを実行するための最も多くの構成オプションを提供します。

このセクションでは、より高度なデバッグ シナリオのための構成と機能について詳しく説明します。ソース マップを使用したデバッグ、外部コードのステップ オーバーリモート デバッグなどを行うための手順が見つかります。

紹介ビデオをご覧になりたい場合は、Getting started with debugging in VS Code (VS Code でのデバッグ入門) をご覧ください。

: VS Code を使い始めたばかりの方は、一般的なデバッグ機能と launch.json 構成ファイルの作成について デバッグのトピックで学ぶことができます。

起動構成の属性

デバッグ構成は、ワークスペースの .vscode フォルダーにある launch.json ファイルに格納されます。デバッグ構成ファイルの作成と使用についての紹介は、一般的なデバッグの記事にあります。

以下は、Node.js デバッガーに固有の一般的な launch.json 属性のリファレンスです。オプションの完全なセットは、vscode-js-debug オプションのドキュメントで確認できます。

次の属性は、タイプ launchattach の起動構成でサポートされています。

  • 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 - Node.js のバージョン管理に "nvm" (または "nvm-windows") または "nvs" を使用している場合、この属性を使用して特定のバージョンの Node.js を選択できます。複数バージョンサポートのセクションを参照してください。
  • env - オプションの環境変数。この属性は、環境変数を文字列型のキー/値ペアのリストとして期待します。
  • envFile - 環境変数定義を含むファイルへのオプションのパス。外部ファイルから環境変数を読み込むのセクションを参照してください。
  • console - プログラムを起動するコンソール (internalConsoleintegratedTerminalexternalTerminal)。Node コンソールのセクションを参照してください。
  • outputCapture - std に設定すると、プロセスの stdout/stderr からの出力が、デバッグ ポート経由で出力をリッスンする代わりに、デバッグ コンソールに表示されます。これは、console.* API を使用する代わりに stdout/stderr ストリームに直接書き込むプログラムやログ ライブラリに便利です。

この属性は、リクエスト タイプ 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

次のスニペットが利用可能です。

  • Launch Program (プログラムの起動): Node.js プログラムをデバッグ モードで起動します。
  • Launch via npm (npm 経由で起動): npm の 'debug' スクリプトを通じて Node.js プログラムを起動します。package.json で定義されていれば、npm デバッグ スクリプトを起動構成から使用できます。npm スクリプトで使用されるデバッグ ポートは、スニペットで指定されたポートと一致している必要があります。
  • Attach (アタッチ): ローカルで実行中の Node.js プログラムのデバッグ ポートにアタッチします。デバッグする Node.js プログラムがデバッグ モードで開始されており、使用されるデバッグ ポートがスニペットで指定されたものと同じであることを確認してください。
  • Attach to Remote Program (リモート プログラムにアタッチ): address 属性で指定されたホストで実行中の Node.js プログラムのデバッグ ポートにアタッチします。デバッグする Node.js プログラムがデバッグ モードで開始されており、使用されるデバッグ ポートがスニペットで指定されたものと同じであることを確認してください。VS Code がワークスペースとリモート ホストのファイルシステムとの間でソース ファイルをマッピングできるように、localRootremoteRoot 属性に正しいパスを指定してください。
  • Attach by Process ID (プロセス ID でアタッチ): プロセス ピッカーを開き、デバッグする node または gulp プロセスを選択します。この起動構成を使用すると、デバッグ モードで開始されていない node または gulp プロセスにもアタッチできます。
  • Nodemon Setup (Nodemon セットアップ): nodemon を使用して、JavaScript ソースが変更されるたびにデバッグ セッションを自動的に再起動します。nodemon がグローバルにインストールされていることを確認してください。デバッグ セッションを終了しても、デバッグ対象のプログラムは終了しますが、nodemon 自体は終了しないことに注意してください。nodemon を終了するには、統合ターミナルで Ctrl+C を押します。
  • Mocha Tests (Mocha テスト): プロジェクトの test フォルダーにある mocha テストをデバッグします。プロジェクトの node_modules フォルダーに 'mocha' がインストールされていることを確認してください。
  • Yeoman generator (Yeoman ジェネレーター): yeoman ジェネレーターをデバッグします。スニペットはジェネレーターの名前を指定するように求めます。プロジェクトの node_modules フォルダーに 'yo' がインストールされており、生成されたプロジェクトがプロジェクト フォルダーで npm link を実行してデバッグ用にインストールされていることを確認してください。
  • Gulp task (Gulp タスク): gulp タスクをデバッグします。プロジェクトの node_modules フォルダーに 'gulp' がインストールされていることを確認してください。
  • Electron Main (Electron メイン): Electron アプリケーションのメイン Node.js プロセスをデバッグします。スニペットは、Electron 実行可能ファイルがワークスペースの node_modules/.bin ディレクトリ内にインストールされていることを前提としています。

Node コンソール

デフォルトでは、Node.js デバッグ セッションは、内部の VS Code デバッグ コンソールでターゲットを起動します。デバッグ コンソールはコンソールから入力を読み取る必要があるプログラムをサポートしていないため、起動構成の console 属性をそれぞれ externalTerminal または integratedTerminal に設定することで、外部ターミナルまたは VS Code 統合ターミナルを有効にできます。デフォルトは internalConsole です。

外部ターミナルでは、terminal.external.windowsExecterminal.external.osxExec、および terminal.external.linuxExec 設定を介して使用するターミナル プログラムを構成できます。

'npm' やその他のツールのための起動構成サポート

Node.js プログラムを node で直接起動する代わりに、'npm' スクリプトや他のタスク ランナー ツールを起動構成から直接使用できます。

  • 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"]
}

複数バージョン サポート

Node.js のバージョンを管理するために 'nvm' (または 'nvm-windows') を使用している場合、特定のバージョンの Node.js を選択するために起動構成に runtimeVersion 属性を指定することができます。

{
  "type": "node",
  "request": "launch",
  "name": "Launch test",
  "runtimeVersion": "14",
  "program": "${workspaceFolder}/test.js"
}

Node.js のバージョンを管理するために 'nvs' を使用している場合、特定のバージョン、アーキテクチャ、およびフレーバーの Node.js を選択するために runtimeVersion 属性を使用できます。たとえば:

{
  "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

デバッガーをプログラムにアタッチするオプション

  • 潜在的な候補プロセスをすべてリスト表示する「プロセス ピッカー」を開き、1 つを選択するか、
  • すべての構成オプションを明示的に指定する「アタッチ」構成を作成し、F5 を押します。

これらのオプションを詳しく見ていきましょう。

Node プロセスにアタッチするアクション

コマンド パレット (⇧⌘P (Windows, Linux Ctrl+Shift+P)) の [Attach to Node Process (Node プロセスにアタッチ)] コマンドは、Node.js デバッガーで利用可能なすべての潜在的なプロセスを一覧表示するクイック ピック メニューを開きます。

Node.js Process picker

ピッカーにリストされている個々のプロセスは、デバッグ ポートとプロセス ID を表示します。そのリストで Node.js プロセスを選択すると、Node.js デバッガーがそれにアタッチしようとします。

Node.js プロセスに加えて、ピッカーはさまざまな形式の --inspect 引数で起動された他のプログラムも表示します。これにより、Electron や VS Code のヘルパー プロセスにアタッチすることが可能になります。

「アタッチ」構成の設定

このオプションはより多くの作業を必要としますが、前の 2 つのオプションとは対照的に、さまざまなデバッグ構成オプションを明示的に構成できます。

最も単純な「アタッチ」構成は次のようになります。

{
  "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}"
}

デバッグの停止

[Debug: Stop (デバッグ: 停止)] アクション (デバッグ ツールバーまたはコマンド パレットから利用可能) を使用すると、デバッグ セッションが停止します。

デバッグ セッションが「アタッチ」モードで開始された場合 (デバッグ ツールバーの赤い終了ボタンに「プラグ」が重ねて表示されている場合)、停止を押すと Node.js デバッガーがデバッグ対象から切断され、デバッグ対象は実行を継続します。

デバッグ セッションが「起動」モードの場合、停止を押すと次のようになります。

  1. 最初に停止を押すと、デバッグ対象に SIGINT シグナルを送信して、正常にシャットダウンするように要求されます。デバッグ対象はこのシグナルをインターセプトして、必要に応じてクリーンアップを行い、その後シャットダウンすることができます。そのシャットダウン コードにブレークポイント (または問題) がなければ、デバッグ対象とデバッグ セッションは終了します。

  2. ただし、デバッガーがシャットダウン コードでブレークポイントにヒットしたり、デバッグ対象が単独で適切に終了しない場合、デバッグ セッションは終了しません。この場合、再度停止を押すと、デバッグ対象とその子プロセスが強制終了されます (SIGKILL)。

赤い停止ボタンを押してもデバッグ セッションが終了しない場合は、ボタンをもう一度押してデバッグ対象を強制的にシャットダウンしてください。

Windows では、停止を押すとデバッグ対象とその子プロセスが強制的に終了します。

ソース マップ

VS Code の JavaScript デバッガーは、TypeScript や minify/uglify された JavaScript のようなトランスパイルされた言語のデバッグを助けるソース マップをサポートしています。ソース マップを使用すると、元のソースをシングル ステップで実行したり、ブレークポイントを設定したりすることが可能です。元のソースにソース マップが存在しない場合、またはソース マップが壊れていてソースと生成された JavaScript を正常にマッピングできない場合、ブレークポイントは未検証 (灰色の空の円)として表示されます。

sourceMaps 属性は、デフォルトで true になっており、ソース マップ機能を制御します。デバッガーは常にソース マップを使用しようと試みるため (もし見つけられれば)、結果として、program 属性でソース ファイル (例: app.ts) を指定することさえできます。何らかの理由でソース マップを無効にする必要がある場合は、sourceMaps 属性を false に設定できます。

ツール構成

ソース マップは常に自動的に作成されるわけではないため、トランスパイラーがそれらを作成するように構成する必要があります。たとえば:

TypeScript

TypeScript の場合、tsc--sourceMap を渡すか、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.jsdevtool: "source-map" プロパティを設定することをお勧めしますが、他の設定を試すとビルドが遅くなる可能性があります。

また、webpack で TypeScript ローダーを使用するなど、追加のコンパイル ステップがある場合は、それらのステップもソースマップを生成するように設定されていることを確認する必要があります。そうしないと、webpack が生成するソースマップは、実際のソースではなく、ローダーからのコンパイル済みコードにマップバックされます。

ソース マップの検出

デフォルトでは、VS Code はワークスペース全体 (node_modules を除く) でソースマップを検索します。大きなワークスペースでは、この検索が遅くなる可能性があります。launch.jsonoutFiles 属性を設定することで、VS Code がソースマップを検索する場所を構成できます。たとえば、この構成では bin フォルダー内の .js ファイルのソースマップのみが検出されます。

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch TypeScript",
      "type": "node",
      "request": "launch",
      "program": "app.ts",
      "outFiles": ["${workspaceFolder}/bin/**/*.js"]
    }
  ]
}

outFiles は、ソース マップ ファイル (.js ではなく .map で終わる可能性があります) ではなく、JavaScript ファイルと一致する必要があることに注意してください。

ソース マップの解決

デフォルトでは、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 にブレークポイントを設定すると、デバッグ アダプターは、TypeScript ファイルのトランスパイル版である app.js へのパスを見つけ出す必要があります。これが実際に Node で実行されているものです。しかし、.ts ファイルから直接これを単純に見つけ出す方法はありません。代わりに、デバッグ アダプターは launch.jsonoutFiles 属性を使用して、トランスパイルされたすべての .js ファイルを見つけ、それらを解析してソース マップを探します。ソース マップには、関連する .ts ファイルの場所が含まれています。

ソース マップを有効にして TypeScript で app.ts ファイルをビルドすると、app.js.map ファイルが生成されるか、または app.js ファイルの末尾のコメントに base64 エンコードされた文字列としてインライン化されたソース マップが生成されます。このマップに関連付けられた .ts ファイルを見つけるために、デバッグ アダプターはソース マップの 2 つのプロパティ、sourcessourceRoot を見ます。sourceRoot はオプションです。存在する場合、それは sources の各パスの前に追加されます。sources はパスの配列です。結果は .ts ファイルへの絶対パスまたは相対パスの配列になります。相対パスはソース マップを基準に解決されます。

最後に、デバッグ アダプターは、この結果の .ts ファイルのリストで app.ts のフルパスを検索します。一致するものがあれば、app.tsapp.js にマッピングするときに使用するソース マップ ファイルが見つかったことになります。一致するものがない場合、ブレークポイントをバインドできず、灰色に変わります。

ブレークポイントが灰色になった場合に試すべきいくつかのことを次に示します。

  • デバッグ中に、[Debug: Diagnose Breakpoint Problems (デバッグ: ブレークポイントの問題を診断)] コマンドを実行してください。このコマンドは、コマンド パレット (⇧⌘P (Windows, Linux Ctrl+Shift+P)) から問題を解決するためのヒントを提供するツールを起動します。
  • ソース マップを有効にしてビルドしましたか? .js ファイルに .js.map ファイルまたはインライン ソース マップがあることを確認してください。
  • ソース マップの sourceRootsources プロパティは正しいですか? これらを組み合わせて .ts ファイルへの正しいパスを取得できますか?
  • VS Code でフォルダを間違った大文字小文字で開いていませんか? コマンドラインから foo/ フォルダを code 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 にマッピングします。

ブラウザーのデバッグでは、デフォルトの sourceMapPathOverridesworkspaceFolder の代わりに webRoot が使用されることに注意してください。

リモート デバッグ

注: 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 Explorer

[読み込まれたスクリプト] ビューでは、スクリプト名を入力してすばやく選択したり、[入力時にフィルターを有効にする] がオンの場合はリストをフィルター処理したりできます。

スクリプトは読み取り専用エディターに読み込まれ、そこでブレークポイントを設定できます。これらのブレークポイントはデバッグ セッション間で記憶されますが、スクリプトの内容にアクセスできるのはデバッグ セッションが実行中の間だけです。

ソースが編集されたときにデバッグ セッションを自動的に再起動する

起動構成の restart 属性は、デバッグ セッションが終了した後に Node.js デバッガーが自動的に再起動するかどうかを制御します。この機能は、ファイルの変更時に Node.js を再起動するために nodemon を使用する場合に便利です。起動構成の属性 restarttrue に設定すると、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 デバッガーでは、中括弧を使用して式をメッセージに補間できます。例: 現在の値は: {myVariable.property}

行番号の横にあるガターを右クリックし、「ログポイント」を選択して作成できます。たとえば、これにより 場所は /usr/local です のようなものがログに記録される場合があります。

Logpoint

ヒット カウント ブレークポイント

「ヒット カウント条件」は、ブレークポイントが実行を「中断」するまでに何回ヒットする必要があるかを制御します。行番号の横にあるガターを右クリックし、「条件付きブレークポイント」を選択してから「ヒット カウント」に切り替えることで、ヒット カウント ブレークポイントを設定できます。

Hit count breakpoint

Node.js デバッガーでサポートされているヒットカウントの構文は、整数、または <, <=, ==, >, >=, % のいずれかの演算子の後に整数が続く形式です。

いくつかの例

  • >10 10 回ヒットした後に常にブレークします。
  • <3 最初の 2 回のヒットでのみブレークします。
  • 10 >=10 と同じです。
  • %2 2 回に 1 回ブレークします。

トリガーされたブレークポイント

トリガーされたブレークポイントとは、別のブレークポイントに到達すると自動的に有効になるブレークポイントです。これらは、特定の事前条件の後にのみ発生するコードの失敗ケースを診断する際に非常に役立ちます。

トリガーされたブレークポイントは、グリフマージンを右クリックし、トリガーされたブレークポイントの追加を選択し、その後、どの他のブレークポイントがこのブレークポイントを有効にするかを選択することで設定できます。

ブレークポイントの検証

パフォーマンス上の理由から、Node.js は JavaScript ファイル内の関数を最初にアクセスされたときに遅延的に解析します。その結果、Node.js によってまだ見られていない (解析されていない) ソースコード領域ではブレークポイントが機能しません。

この動作はデバッグには理想的ではないため、VS Code は自動的に --nolazy オプションを Node.js に渡します。これにより遅延解析が防止され、コードを実行する前にブレークポイントを検証できるようになり、ブレークポイントが「ジャンプ」することがなくなります。

--nolazy オプションはデバッグターゲットの起動時間を大幅に増加させる可能性があるため、runtimeArgs 属性として --lazy を渡すことで簡単にオプトアウトできます。

そうすると、いくつかのブレークポイントが要求された行に「固執」せず、代わりに既に解析されたコード内の次の可能な行に「ジャンプ」することがわかります。混乱を避けるため、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 フォルダー内のすべてのコードはスキップされます。skipFilesconsole.log や同様のメソッドを呼び出したときに表示される場所にも適用されます。スタック内の最初のスキップされていない場所がデバッグコンソールの出力の横に表示されます。

Node.js の組み込みのコア モジュールは、glob パターン内の「マジック ネーム」<node_internals> で参照できます。次の例では、すべての内部モジュールをスキップします。

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

正確な「スキップ」ルールは次のとおりです。

  • スキップされたファイルにステップインした場合、そこでは停止せず、スキップされたファイルにない次に実行される行で停止します。
  • スローされた例外で中断するオプションを設定している場合、スキップされたファイルからスローされた例外が、スキップされていないファイルにバブルアップしない限り、中断しません。
  • スキップされたファイルにブレークポイントを設定した場合、そのブレークポイントで停止し、そこからステップアウトするまでステップ実行できます。その後、通常のスキップ動作が再開されます。
  • スキップファイル内からのコンソールメッセージの場所は、コールスタック内の最初のスキップされていない場所として表示されます。

スキップされたソースは、コールスタックビューで「淡色表示」されます。

Skipped source is dimmed in call stack view

淡色表示されたエントリの上にカーソルを置くと、スタック フレームが淡色表示されている理由が説明されます。

コール スタックのコンテキスト メニュー項目である Toggle skipping this file (このファイルのスキップを切り替える) を使用すると、起動構成に追加することなく、実行時にファイルを簡単にスキップできます。このオプションは現在のデバッグ セッション中のみ持続します。また、起動構成の skipFiles オプションでスキップされているファイルのスキップを停止するためにも使用できます。

注: legacy プロトコル デバッガーは負の glob パターンをサポートしていますが、それらは正のパターンのになければなりません。正のパターンはスキップされたファイルのセットに追加し、負のパターンはそのセットから差し引きます。

次の (legacy プロトコルのみの) 例では、「math」モジュールを除くすべてがスキップされます。

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

注: legacy プロトコル デバッガーは skipFiles 機能をエミュレートする必要があります。なぜなら、V8 デバッガー プロトコルがネイティブにサポートしていないからです。これにより、ステップ実行のパフォーマンスが低下する可能性があります。

WebAssembly のデバッグ

JavaScript デバッガーは、DWARF デバッグ情報が含まれている場合、WebAssembly にコンパイルされたコードをデバッグできます。多くのツールチェーンがこの情報の発行をサポートしています。

  • Emscripten を使用した C/C++: -g フラグを指定してコンパイルし、デバッグ情報を出力します。
  • Zig: DWARF 情報は「Debug」ビルドモードで自動的に出力されます。
  • Rust: Rust は DWARF デバッグ情報を出力します。しかし、wasm-pack はビルド中にそれをまだ保持しません。したがって、wasm-pack build を実行する代わりに、一般的な wasm-bindgen/wasm-pack ライブラリのユーザーは、2 つのコマンドを使用して手動でビルドする必要があります。
    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 コアを「合理化」するために別の拡張機能として提供されています。インストール後、アクティブなデバッグ セッションを再起動すると、ネイティブ コードがデバッガーにマッピングされるはずです。ソース コードが [読み込まれたソース] ビューに表示され、ブレークポイントが機能するはずです。

下の画像では、デバッガーはマンデルブロ集合を作成する C++ ソースコードのブレークポイントで停止しています。コールスタックが表示されており、JavaScript コードから WebAssembly、そしてマッピングされた C++ コードへのフレームが確認できます。また、C++ コード内の変数や、int32 の height 変数に関連するメモリの編集も確認できます。

Debugger stopped on a breakpoint in C++ source code

ほぼ同等ですが、WebAssembly のデバッグは通常の JavaScript とは少し異なります。

  • [変数] ビューの変数は直接編集できません。ただし、変数の横にある [バイナリ データの表示] アクションを選択して、関連するメモリを編集できます。
  • デバッグ コンソールWatch ビューでの基本的な式評価は、lldb-eval によって提供されます。これは通常の JavaScript 式とは異なります。
  • ソースコードにマップされていない場所は、逆アセンブルされた WebAssembly テキスト形式で表示されます。WebAssembly の場合、[ソースマップ ステッピングを無効にする] コマンドにより、デバッガーは逆アセンブルされたコードでのみステップ実行します。

VS Code の WebAssembly デバッグは、Chromium の作者による C/C++ Debugging Extension を基に構築されています。

サポートされている Node ライクなランタイム

現在の VS Code JavaScript デバッガーは、Node バージョン 8.x 以上、最近の 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 モジュールをデバッグするにはどうすればよいですか?

ECMAScript モジュールを使用するために esm を使用するか、--experimental-modules を Node.js に渡す場合、これらのオプションを launch.jsonruntimeArgs 属性を介して渡すことができます。

NODE_OPTIONS を設定するにはどうすればよいですか?

デバッガーは、アプリケーションのデバッグを設定するために特別な NODE_OPTIONS 環境変数を使用します。これを上書きすると、デバッグが正しく機能しなくなります。上書きする代わりに、追加する必要があります。たとえば、.bashrc ファイルには次のような記述があるかもしれません。

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