console.logを大量に埋め込んでデバッグしていませんか。Node.jsには強力な組み込みデバッガがあり、Chrome DevToolsやVS Codeと連携することで、ブレークポイントの設定、変数の監視、コールスタックの確認など、高度なデバッグが可能です。

本記事では、--inspectフラグの使い方からChrome DevToolsでの操作、VS Codeのlaunch.json設定まで、効率的なデバッグ環境の構築方法を解説します。

実行環境

項目 バージョン
Node.js 20.x LTS以上
npm 10.x以上
OS Windows/macOS/Linux
VS Code 最新版推奨
Chrome 最新版推奨

前提条件

  • JavaScriptの基礎知識(関数、オブジェクト、Promise/async-await)
  • Node.jsの基本API理解
  • VS Codeの基本操作

console.logデバッグの限界

多くの開発者が最初に行うデバッグ手法はconsole.logによる値の出力です。しかし、この方法には明確な限界があります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// console.logデバッグの例
function calculateTotal(items) {
  console.log('items:', items); // デバッグ用
  let total = 0;
  for (const item of items) {
    console.log('processing item:', item); // デバッグ用
    total += item.price * item.quantity;
    console.log('current total:', total); // デバッグ用
  }
  console.log('final total:', total); // デバッグ用
  return total;
}

console.logの問題点

問題点 説明
コード汚染 デバッグ用のコードが本番コードに混入する
手動削除が必要 デバッグ後に手動で削除し忘れるリスク
実行を止められない 特定の状態で処理を停止して確認できない
スコープ外の変数確認が困難 確認したい変数を都度追加する必要がある
非効率 確認箇所を変えるたびにコード修正と再実行が必要

組み込みデバッガを使用することで、これらの問題を解決し、効率的なデバッグが可能になります。

Node.jsの組み込みデバッガ

Node.jsにはnode inspectコマンドによるコマンドラインデバッガが組み込まれています。

debuggerステートメント

コード内にdebuggerステートメントを記述すると、デバッガ接続時にその行で実行が停止します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// app.js
function processData(data) {
  const result = [];
  for (const item of data) {
    debugger; // この行でデバッガが停止
    result.push(item * 2);
  }
  return result;
}

const numbers = [1, 2, 3, 4, 5];
const doubled = processData(numbers);
console.log(doubled);

node inspectコマンド

node inspectコマンドでデバッガを起動します。

1
node inspect app.js

実行結果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
< Debugger listening on ws://127.0.0.1:9229/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
< For help, see: https://nodejs.org/en/docs/inspector
<
connecting to 127.0.0.1:9229 ... ok
< Debugger attached.
<
Break on start in app.js:2
  1 // app.js
> 2 function processData(data) {
  3   const result = [];
debug>

デバッガコマンド一覧

コマンドラインデバッガで使用できる主なコマンドです。

コマンド 短縮形 説明
cont c 実行を継続
next n 次の行へステップ(関数内に入らない)
step s ステップイン(関数内に入る)
out o ステップアウト(関数から抜ける)
pause - 実行を一時停止
setBreakpoint(line) sb(line) 指定行にブレークポイント設定
clearBreakpoint(file, line) cb(file, line) ブレークポイント解除
backtrace bt コールスタック表示
list(n) - 現在位置周辺のn行を表示
watch(expr) - 式を監視リストに追加
unwatch(expr) - 式を監視リストから削除
repl - REPLモードに入る
exec expr p expr 式を評価して結果を表示
restart - スクリプトを再起動
kill - スクリプトを終了

デバッガ操作の実践例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
debug> n
break in app.js:10
  8 }
  9
>10 const numbers = [1, 2, 3, 4, 5];
 11 const doubled = processData(numbers);
 12 console.log(doubled);
debug> n
break in app.js:11
  9
 10 const numbers = [1, 2, 3, 4, 5];
>11 const doubled = processData(numbers);
 12 console.log(doubled);
debug> s
break in app.js:3
  1 // app.js
  2 function processData(data) {
> 3   const result = [];
  4   for (const item of data) {
  5     debugger;
debug> exec data
[ 1, 2, 3, 4, 5 ]
debug> watch('result.length')
debug> c
break in app.js:5
Watchers:
  0: result.length = 0

  3   const result = [];
  4   for (const item of data) {
> 5     debugger;
  6     result.push(item * 2);
  7   }

–inspectフラグによるデバッガ起動

Chrome DevToolsやVS Codeなどの外部デバッガと連携するには、--inspectフラグを使用します。

–inspectオプションの種類

flowchart TD
    A[デバッグを開始したい] --> B{いつから<br>デバッグする?}
    B -->|すぐに実行開始| C["--inspect"]
    B -->|デバッガ接続を待つ| D["--inspect-wait"]
    B -->|最初の行で停止| E["--inspect-brk"]
    C --> F[コード実行中に<br>デバッガを接続]
    D --> G[デバッガ接続後に<br>実行開始]
    E --> H[最初の行で停止し<br>ステップ実行可能]
オプション 説明 用途
--inspect デバッガを有効化し、即座に実行開始 実行中のプロセスにアタッチしたい場合
--inspect-wait デバッガ接続を待ってから実行開始 初期化処理からデバッグしたい場合
--inspect-brk 最初の行で停止 最初からステップ実行したい場合

–inspectの基本的な使い方

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# デフォルトポート(9229)でデバッガを起動
node --inspect app.js

# カスタムポートを指定
node --inspect=9230 app.js

# 最初の行で停止
node --inspect-brk app.js

# デバッガ接続を待ってから実行
node --inspect-wait app.js

実行結果:

1
2
Debugger listening on ws://127.0.0.1:9229/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
For help, see: https://nodejs.org/en/docs/inspector

リモートデバッグ

外部からの接続を許可する場合は、ホストアドレスを指定します。

1
2
# 全てのインターフェースで接続を受け付ける
node --inspect=0.0.0.0:9229 app.js

セキュリティ上の注意: 0.0.0.0を指定すると、ネットワーク上の任意のホストからデバッガに接続可能になります。本番環境では絶対に使用せず、開発環境でも信頼できるネットワーク内でのみ使用してください。

Chrome DevToolsでのデバッグ

Chrome DevToolsはNode.jsのデバッグに対応しており、GUIでブレークポイント設定や変数監視が可能です。

Chrome DevToolsへの接続手順

  1. Node.jsを--inspectフラグ付きで起動
1
node --inspect-brk app.js
  1. Chromeブラウザで以下のURLにアクセス
1
chrome://inspect
  1. 「Remote Target」セクションに表示されるNode.jsプロセスの「inspect」をクリック

DevToolsの主要機能

DevToolsが開いたら、以下の機能を活用できます。

ブレークポイントの設定

Sourcesパネルでソースコードを開き、行番号をクリックするとブレークポイントを設定できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// server.js
const http = require('node:http');

const server = http.createServer((req, res) => {
  const url = req.url;        // ここにブレークポイント設定
  const method = req.method;  // 変数の値を確認可能
  
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello World');
});

server.listen(3000, () => {
  console.log('Server running on port 3000');
});

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

特定の条件を満たす場合のみ停止するブレークポイントを設定できます。行番号を右クリックして「Add conditional breakpoint」を選択します。

1
2
3
4
5
// 条件付きブレークポイントの例
for (let i = 0; i < 100; i++) {
  // i === 50 の場合のみ停止する条件を設定
  processItem(i);
}

ログポイント

コードを変更せずに、特定の行で値をコンソールに出力できます。行番号を右クリックして「Add logpoint」を選択します。

1
2
// ログポイントの書式
"Processing item: {item.name}, price: {item.price}"

Watchパネル

特定の式や変数を常に監視できます。「+」ボタンをクリックして監視したい式を追加します。

Call Stackパネル

現在の実行位置に至るまでの関数呼び出し履歴を確認できます。スタック内の任意のフレームをクリックすると、その時点のスコープと変数を確認できます。

Scopeパネル

現在のスコープ内の変数とその値を確認できます。Local、Closure、Globalなどのスコープ別に整理されています。

VS Codeでのデバッグ

VS Codeには強力なNode.jsデバッガが組み込まれており、エディタ上でシームレスにデバッグできます。

Auto Attach機能

VS Codeの統合ターミナルで実行したNode.jsプロセスに自動的にデバッガをアタッチする機能です。

コマンドパレット(Ctrl+Shift+P)から「Toggle Auto Attach」を実行し、モードを選択します。

モード 説明
smart node_modules以外のコードを実行した場合にアタッチ
always 全てのNode.jsプロセスにアタッチ
onlyWithFlag --inspectフラグ付きの場合のみアタッチ

Auto Attachを有効にした後、ターミナルを再起動(ターミナル右上の警告アイコンをクリック)すると、自動アタッチが機能します。

JavaScript Debug Terminal

デバッグ専用のターミナルを作成できます。コマンドパレットから「Debug: Create JavaScript Debug Terminal」を実行するか、ターミナルのドロップダウンから「JavaScript Debug Terminal」を選択します。

このターミナルで実行したNode.jsプロセスには、自動的にデバッガがアタッチされます。

launch.jsonによるデバッグ設定

より細かい制御が必要な場合は、launch.jsonでデバッグ設定を定義します。

launch.jsonの作成

  1. サイドバーの「実行とデバッグ」(Ctrl+Shift+D)を開く
  2. 「launch.jsonファイルを作成します」をクリック
  3. 「Node.js」を選択

基本的なlaunch.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      "skipFiles": ["<node_internals>/**"],
      "program": "${workspaceFolder}/app.js"
    }
  ]
}

主要な設定プロパティ

プロパティ 説明
type デバッガの種類(nodeを指定)
request launch(起動)またはattach(アタッチ)
name デバッグ設定の表示名
program 実行するファイルのパス
args プログラムに渡す引数の配列
cwd 作業ディレクトリ
env 環境変数
envFile 環境変数ファイルのパス
runtimeExecutable Node.js実行ファイルのパス
runtimeArgs Node.jsに渡す引数
skipFiles ステップ実行時にスキップするファイル
console コンソールの種類
outFiles ソースマップの検索パス
stopOnEntry 最初の行で停止するか

実践的なlaunch.json設定例

環境変数ファイルを使用する設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch with .env",
      "skipFiles": ["<node_internals>/**"],
      "program": "${workspaceFolder}/src/index.js",
      "envFile": "${workspaceFolder}/.env",
      "env": {
        "NODE_ENV": "development"
      }
    }
  ]
}

npmスクリプトを使用する設定

package.jsonのスクリプトを経由してデバッグする場合:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch via npm",
      "runtimeExecutable": "npm",
      "runtimeArgs": ["run-script", "debug"],
      "cwd": "${workspaceFolder}",
      "console": "integratedTerminal"
    }
  ]
}

対応するpackage.json:

1
2
3
4
5
{
  "scripts": {
    "debug": "node src/index.js"
  }
}

実行中のプロセスにアタッチする設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "attach",
      "name": "Attach to Process",
      "port": 9229,
      "restart": true,
      "skipFiles": ["<node_internals>/**"]
    }
  ]
}

プロセスピッカーを使用する設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "attach",
      "name": "Attach by Process ID",
      "processId": "${command:PickProcess}"
    }
  ]
}

nodemonと連携する設定

ファイル変更時に自動再起動するnodemonと連携する設定です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "nodemon",
      "runtimeExecutable": "nodemon",
      "program": "${workspaceFolder}/src/index.js",
      "restart": true,
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen"
    }
  ]
}

TypeScriptプロジェクトの設定

ソースマップを使用してTypeScriptをデバッグする設定です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch TypeScript",
      "program": "${workspaceFolder}/src/index.ts",
      "preLaunchTask": "tsc: build",
      "outFiles": ["${workspaceFolder}/dist/**/*.js"],
      "skipFiles": ["<node_internals>/**"],
      "sourceMaps": true
    }
  ]
}

複数の設定を切り替える

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Debug: Development",
      "program": "${workspaceFolder}/src/index.js",
      "env": { "NODE_ENV": "development" }
    },
    {
      "type": "node",
      "request": "launch",
      "name": "Debug: Test",
      "program": "${workspaceFolder}/node_modules/jest/bin/jest.js",
      "args": ["--runInBand"]
    },
    {
      "type": "node",
      "request": "attach",
      "name": "Attach to Docker",
      "port": 9229,
      "localRoot": "${workspaceFolder}",
      "remoteRoot": "/app"
    }
  ]
}

デバッグビューのドロップダウンから設定を選択し、F5キーでデバッグを開始できます。

VS Codeのデバッグ操作

ブレークポイントの設定

エディタの行番号の左側をクリックするか、行にカーソルを置いてF9キーを押すとブレークポイントを設定できます。

ブレークポイントの種類

種類 説明 設定方法
通常のブレークポイント その行で常に停止 行番号クリック
条件付きブレークポイント 条件がtrueの場合のみ停止 右クリック→条件付きブレークポイント
ヒットカウント 指定回数ヒット後に停止 右クリック→ヒットカウント
ログポイント 停止せずにログを出力 右クリック→ログポイント

デバッグツールバー

デバッグ中に表示されるツールバーの各ボタンの機能です。

ボタン ショートカット 説明
続行 F5 次のブレークポイントまで実行
ステップオーバー F10 現在の行を実行し、次の行へ移動
ステップイン F11 関数内に入る
ステップアウト Shift+F11 現在の関数から抜ける
再起動 Ctrl+Shift+F5 デバッグセッションを再起動
停止 Shift+F5 デバッグを停止

デバッグコンソール

デバッグコンソール(Ctrl+Shift+Y)では、現在のコンテキストで式を評価できます。

1
2
3
4
5
6
7
// デバッグコンソールでの操作例
> items.length
5
> items.filter(i => i.price > 100)
[{ name: "Product A", price: 150 }, { name: "Product B", price: 200 }]
> JSON.stringify(config, null, 2)
"{\n  \"host\": \"localhost\",\n  \"port\": 3000\n}"

変数の値を変更

デバッグ中に変数パネルで変数を右クリックし、「値の設定」を選択すると、変数の値を変更できます。これにより、異なる値での動作を確認できます。

高度なデバッグテクニック

skipFilesでnode_modulesをスキップ

ステップ実行時にnode_modules内のコードや内部モジュールをスキップすることで、自分のコードに集中できます。

1
2
3
4
5
6
{
  "skipFiles": [
    "<node_internals>/**",
    "${workspaceFolder}/node_modules/**/*.js"
  ]
}

VS Codeの設定でグローバルに指定することも可能です。

1
2
3
4
5
{
  "debug.javascript.terminalOptions": {
    "skipFiles": ["<node_internals>/**"]
  }
}

ソースマップの活用

TypeScriptやBabelでトランスパイルされたコードをデバッグする場合、ソースマップが必要です。

TypeScriptの場合(tsconfig.json):

1
2
3
4
5
6
{
  "compilerOptions": {
    "sourceMap": true,
    "outDir": "./dist"
  }
}

launch.jsonでソースマップの場所を指定:

1
2
3
4
5
6
7
8
{
  "type": "node",
  "request": "launch",
  "name": "Debug TypeScript",
  "program": "${workspaceFolder}/src/index.ts",
  "outFiles": ["${workspaceFolder}/dist/**/*.js"],
  "sourceMaps": true
}

例外発生時に自動停止

「ブレークポイント」パネルで以下のオプションを有効にできます。

オプション 説明
キャッチされない例外 catchされていない例外で停止
キャッチされた例外 catchされた例外でも停止

複合起動設定

フロントエンドとバックエンドを同時にデバッグするなど、複数のデバッグセッションを同時に起動できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Server",
      "program": "${workspaceFolder}/server/index.js"
    },
    {
      "type": "node",
      "request": "launch",
      "name": "Worker",
      "program": "${workspaceFolder}/worker/index.js"
    }
  ],
  "compounds": [
    {
      "name": "Server + Worker",
      "configurations": ["Server", "Worker"]
    }
  ]
}

デバッグのベストプラクティス

効率的なデバッグのワークフロー

flowchart TD
    A[問題を発見] --> B[仮説を立てる]
    B --> C[適切な場所に<br>ブレークポイント設定]
    C --> D[デバッグ実行]
    D --> E{期待通りの<br>動作?}
    E -->|Yes| F[ブレークポイントを<br>次の箇所へ移動]
    E -->|No| G[変数・状態を確認]
    G --> H[問題箇所を特定]
    H --> I[コードを修正]
    I --> D
    F --> E

デバッグ時の注意点

ポイント 説明
小さく始める 最小限のブレークポイントから始め、必要に応じて追加
条件付きブレークポイント活用 ループ内では条件を設定して不要な停止を避ける
ログポイントを活用 停止せずに値を確認したい場合に有効
Watch式を活用 頻繁に確認する値はWatchに登録
コールスタックを確認 問題の原因が呼び出し元にある場合も多い
skipFilesを設定 自分のコードに集中できる

本番環境でのデバッグ

本番環境でのデバッグには特別な注意が必要です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 本番環境で--inspectを使う場合の注意
// 1. ポートを外部に公開しない
// 2. 必要な時のみ有効化
// 3. ファイアウォールで保護

// シグナルで動的にデバッガを有効化する例
process.on('SIGUSR1', () => {
  const inspector = require('node:inspector');
  inspector.open(9229, 'localhost', true);
  console.log('Debugger enabled');
});

まとめ

Node.jsのデバッグ機能を活用することで、console.logに頼らない効率的な問題解決が可能になります。

手法 用途 推奨シーン
node inspect コマンドラインデバッグ SSHでのリモートサーバーデバッグ
Chrome DevTools GUIデバッグ 詳細なプロファイリング、メモリ分析
VS Code 統合開発環境でのデバッグ 日常的な開発作業

最初はVS CodeのAuto Attach機能から始め、必要に応じてlaunch.jsonでカスタマイズしていくことをおすすめします。ブレークポイント、Watch、コールスタックの確認を習慣化することで、デバッグ効率が大幅に向上します。

次回は「Node.jsパフォーマンス分析 - プロファイリングとメモリリーク検出」で、より高度な問題解析手法について解説します。

参考リンク