VS Code での Node.js デバッグ

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

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

自動アタッチ (Auto Attach)

自動アタッチ機能が有効になっている場合、Node デバッガーは VS Code の統合ターミナルから起動された特定の Node.js プロセスに自動的にアタッチします。この機能を有効にするには、コマンドパレットから Toggle Auto Attach コマンドを使用する(⇧⌘P (Windows, Linux Ctrl+Shift+P))か、すでにアクティブな場合はステータスバーの 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 フラグを付けて起動されたプロセスのみがデバッグされます。

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

Auto Attach

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

追加の構成

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

debug.javascript.terminalOptions 設定で、通常 launch.json にあるその他のプロパティを自動アタッチに適用できます。たとえば、ノードの内部コードを 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 コマンドを実行するか、ターミナルスイッチャーのドロップダウンから Create JavaScript Debug Terminal を選択します。

Create Debug Terminal

追加の構成

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

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

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

起動構成 (Launch Configuration)

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

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

入門ビデオをご覧になりたい場合は、Getting started with debugging in VS Code を参照してください。

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

起動構成の属性

デバッグ構成は、ワークスペースの .vscode フォルダーにある launch.json ファイルに保存されます。デバッグ構成ファイルの作成と使用方法の入門は、一般的なデバッグの記事にあります。

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

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

Add Configuration button

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

  • Launch Program: Node.js プログラムをデバッグモードで起動する。
  • Launch via 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 がワークスペースとリモートホストのファイルシステム間でソースファイルをマッピングできるように、localRoot および remoteRoot 属性に正しいパスを指定してください。
  • Attach by Process ID: プロセスセレクターを開き、デバッグする node または gulp プロセスを選択する。この起動構成では、デバッグモードで開始されなかったプロセスにもアタッチできます。
  • Nodemon Setup: JavaScript ソースが変更されるたびにデバッグセッションを自動的に再起動するために nodemon を使用する。nodemon がグローバルにインストールされていることを確認してください。デバッグセッションの終了は、nodemon 自体ではなくデバッグ対象のプログラムのみを終了させることに注意してください。nodemon を終了するには、統合ターミナルで Ctrl+C を押します。
  • Mocha Tests: プロジェクトの test フォルダーにある mocha テストをデバッグする。プロジェクトの node_modules フォルダーに 'mocha' がインストールされていることを確認してください。
  • Yeoman generator: yeoman ジェネレーターをデバッグする。スニペットはジェネレーター名の指定を求めてきます。プロジェクトの node_modules フォルダーに 'yo' がインストールされており、プロジェクトフォルダーで npm link を実行して生成されたプロジェクトがデバッグ用にインストールされていることを確認してください。
  • Gulp task: gulp タスクをデバッグする。プロジェクトの node_modules フォルダーに 'gulp' がインストールされていることを確認してください。
  • Electron Main: 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' スクリプトやその他のタスクランナーツールを使用できます。

  • runtimeExecutable 属性には PATH で利用可能な任意のプログラム(例: 'npm', 'mocha', 'gulp' など)を使用でき、引数は 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') を使用している場合、起動構成に runtimeVersion 属性を指定して特定の Node.js バージョンを選択できます。

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

Node.js バージョンの管理に 'nvs' を使用している場合、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 へのアタッチ

外部の Node.js プログラムに VS Code デバッガーをアタッチしたい場合は、以下のように Node.js を起動します。

node --inspect program.js

または、プログラムを実行開始せず、デバッガーがアタッチされるのを待機させる必要がある場合は、以下のようにします。

node --inspect-brk program.js

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

  • 考えられるすべての候補プロセスをリストアップする「プロセスセレクター」を開いて選択する。
  • すべての構成オプションを明示的に指定する「attach」構成を作成し、F5 キーを押す。

これらのオプションを詳しく説明します。

Attach to Node Process アクション

コマンドパレット(⇧⌘P (Windows, Linux Ctrl+Shift+P))から Attach to Node Process コマンドを実行すると、Node.js デバッガーが利用可能なすべての候補プロセスをリストしたクイックピックメニューが開きます。

Node.js Process picker

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

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

"Attach" 構成の設定

このオプションは手間がかかりますが、前の2つのオプションとは異なり、さまざまなデバッグ構成オプションを明示的に設定できます。

最も単純な "attach" 構成は次のようになります。

{
  "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 アクション(デバッグツールバーから利用可能、または コマンドパレット経由)を使用すると、デバッグセッションが停止します。

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

デバッグセッションが「launch」モードの場合、Stop を押すと以下が行われます。

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

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

赤い Stop ボタンを押してもデバッグセッションが終了しない場合は、もう一度ボタンを押してデバッグ対象の強制終了を行ってください。

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

ソースマップ

VS Code の JavaScript デバッガーは、TypeScript や圧縮/難読化された JavaScript などのトランスパイル済み言語のデバッグを支援するソースマップをサポートしています。ソースマップがあれば、元のソースでステップ実行したり、ブレークポイントを設定したりできます。元のソースにソースマップが存在しない場合、あるいはソースマップが壊れており元のソースと生成された JavaScript を正しくマッピングできない場合、ブレークポイントは検証されていない(灰色の空の円)状態で表示されます。

デフォルトで true に設定されている sourceMaps 属性がソースマップ機能を制御します。デバッガーは常に(見つけることができれば)ソースマップを使用しようとするため、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" プロパティを設定することを推奨しますが、ビルドが遅くなる可能性があることを理解した上で他の設定を試すことも可能です。

また、TypeScript ローダーを使用するなど、webpack に追加のコンパイルステップがある場合は、それらのステップでもソースマップが生成されるように構成する必要があります。そうしないと、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 ソースマップのヒント

ソースマップでデバッグする際の一般的な問題は、ブレークポイントを設定しても灰色になることです。カーソルを合わせると、"Breakpoint ignored because generated code not found (source map problem?)" というメッセージが表示されます。どうすればよいでしょうか?これにはさまざまな理由が考えられます。まず、Node デバッグアダプターがソースマップをどのように処理するかを簡単に説明します。

app.ts にブレークポイントを設定すると、デバッグアダプターは、Node で実際に実行されている TypeScript ファイルのトランスパイル済みバージョンである app.js へのパスを見つける必要があります。しかし、.ts ファイルからこれを見つける直接的な方法はありません。代わりに、デバッグアダプターは launch.jsonoutFiles 属性を使用してすべてのトランスパイル済み .js ファイルを見つけ、それらを解析して関連する .ts ファイルの場所を含むソースマップを取得します。

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

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

ブレークポイントが灰色になる場合に試すべきこと

  • デバッグ中に Debug: Diagnose Breakpoint Problems コマンドを実行してください。コマンドパレット(⇧⌘P (Windows, Linux Ctrl+Shift+P))から実行できるこのコマンドは、問題を解決するためのヒントを提供するツールを起動します。
  • ソースマップを有効にしてビルドしましたか? .js.map ファイルがあるか、.js ファイルにインライン化されているかを確認してください。
  • ソースマップ内の sourceRootsources プロパティは正しいですか? それらを組み合わせて .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 にマッピングします。

ブラウザーデバッグでは、デフォルトの sourceMapPathOverrides 内の workspaceFolder の代わりに 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 に開かせたい場合は、リモートとローカルの場所の間にマッピングを設定できます。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 ファイルブラウジングでは簡単に特定・開封できないスクリプトにブレークポイントを設定する必要がある場合、実行とデバッグビューの 読み込まれたスクリプト (LOADED SCRIPTS) ビューを介してスクリプトにアクセスできます。

Loaded Scripts Explorer

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

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

ソース編集時にデバッグセッションを自動的に再起動する

起動構成の restart 属性は、デバッグセッション終了後に Node.js デバッガーが自動的に再起動するかどうかを制御します。この機能は、ファイル変更時に Node.js を再起動するために nodemon を使用している場合に便利です。起動構成の restart 属性を true に設定すると、Node.js が終了した後に、Node デバッガーが自動的に 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"
}

ヒント: Stop ボタンを押すとデバッグセッションが停止し、Node.js から切断されますが、nodemon(および Node.js)は実行を継続します。nodemon を停止するには、コマンドラインから強制終了する必要があります(上記のように integratedTerminal を使用している場合は簡単です)。

ヒント: 構文エラーがある場合、nodemon はエラーが修正されるまで Node.js を正常に開始できません。この場合、VS Code は Node.js へのアタッチを試み続けますが、最終的に(10秒後に)あきらめます。これを回避するには、timeout 属性に大きな値(ミリ秒単位)を設定することでタイムアウトを延長できます。

フレームの再起動

Node デバッガーは、スタックフレームでの実行の再起動をサポートしています。これは、ソースコードの問題を見つけ、変更した入力値でコードの一部を再実行したい場合に便利です。デバッグセッション全体を停止して再起動すると時間がかかる場合があります。フレームの再起動 (Restart Frame) アクションを使用すると、値の設定アクションで変数を変更した後、現在の関数に再突入できます。

Restart frame

フレームの再起動は、関数の外部の状態に対するミューテーション(変更)をロールバックしないため、期待通りに動作しない場合があります。

ブレークポイント

条件付きブレークポイント

条件付きブレークポイントは、式が truthy な値を返すときのみ一時停止するブレークポイントです。行番号の横の余白を右クリックし、「条件付きブレークポイント」を選択することで作成できます。

Conditional breakpoint

ログポイント

コードが特定の場所に到達したときに一時停止するのではなく、単にメッセージや値をログに記録したい場合があります。これはログポイントを使用して実行できます。ログポイントは一時停止せず、ヒット時にデバッグコンソールにメッセージを記録します。JavaScript デバッガーでは、中括弧を使用して式をメッセージ内に挿入できます。例えば current value is: {myVariable.property} のようにします。

行番号の横の余白を右クリックし、「ログポイント」を選択して作成できます。例えば、これは location is /usr/local のようなものを記録する可能性があります。

Logpoint

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

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

Hit count breakpoint

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

いくつかの例

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

トリガーブレークポイント

トリガーブレークポイントとは、別のブレークポイントがヒットしたときに自動的に有効になるブレークポイントのことです。特定の前提条件を満たした場合にのみ発生するコードの障害ケースを診断する際に非常に役立ちます。

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

ブレークポイントの検証

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

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

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

そうした場合、いくつかのブレークポイントが要求された行に「固着」せず、既に解析済みのコード内の次の可能な行に「ジャンプ」することに気付くでしょう。混乱を避けるため、VS Code は Node.js がブレークポイントがあると見なす場所に常にブレークポイントを表示します。ブレークポイント (BREAKPOINTS) セクションでは、これらのブレークポイントは要求された行番号と実際の行番号の間に矢印で示されます。

Breakpoints View

このブレークポイント検証は、セッションが開始されブレークポイントが Node.js に登録されたとき、またはセッションが実行中に新しいブレークポイントが設定されたときに発生します。この場合、ブレークポイントは別の場所に「ジャンプ」する可能性があります。Node.js が(実行するなどして)すべてのコードを解析した後、ブレークポイントセクションヘッダーにある 再適用 (Reapply) ボタンを使用して、要求された場所にブレークポイントを簡単に再適用できます。これにより、ブレークポイントが要求された位置に「ジャンプして戻る」はずです。

Breakpoint Actions

不要なコードのスキップ

VS Code の Node.js デバッグには、ステップ実行したくないソースコードを回避する機能(「Just My Code」とも呼ばれます)があります。この機能は、起動構成の skipFiles 属性を使用して有効にできます。skipFiles は、スキップするスクリプトパスの glob パターンの配列です。

例えば、以下を使用すると

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

プロジェクト内の node_modules および lib フォルダー内のすべてのコードがスキップされます。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 プロトコルデバッガーは、V8 Debugger Protocol がネイティブにサポートしていないため、skipFiles 機能をエミュレートする必要があります。これにより、ステップ実行のパフォーマンスが低下する可能性があります。

WebAssembly のデバッグ

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

  • Emscripten を使用した C/C++: -g フラグを指定してコンパイルし、デバッグ情報を出力します。
  • Zig: "Debug" ビルドモードでは、DWARF 情報が自動的に出力されます。
  • 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 のコアを「合理化」し続けるために別個の拡張機能として提供されています。インストール後、アクティブなデバッグセッションをすべて再起動すると、ネイティブコードがデバッガーにマッピングされるはずです!読み込まれたソース (Loaded Sources) ビューにソースコードが表示され、ブレークポイントが機能するようになるはずです。

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

Debugger stopped on a breakpoint in C++ source code

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

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

VS Code の WebAssembly デバッグは、Chromium 開発者による C/C++ デバッグ拡張機能に基づいています。

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

現在の VS Code JavaScript デバッガーは、Node バージョン 8.x 以上、最近の Chrome バージョン、および(msedge 起動タイプを介した)最近の Edge バージョンをサポートしています。

次のステップ

Node.js セクションをまだ読んでいない場合は、以下をご覧ください。

  • Node.js - サンプルアプリケーションを使用したエンドツーエンドの Node シナリオ

VS Code でのデバッグの基本に関するチュートリアルビデオは、以下をご覧ください。

VS Code のタスク実行サポートについては、以下に移動してください。

  • タスク (Tasks) - 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 を使用しているか、ECMAScript モジュールを使用するために Node.js に --experimental-modules を渡している場合は、launch.jsonruntimeArgs 属性を介してこれらのオプションを渡すことができます。

NODE_OPTIONS はどのように設定できますか?

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

export NODE_OPTIONS="$NODE_OPTIONS --some-other-option=here"
© . This site is unofficial and not affiliated with Microsoft.