しくみを理解！VS CodeによるNode.js・TypeScriptのデバッグ設定方法

## はじめに
[以前の記事](https://qiita.com/course_k/items/eecf57aa1f5d7e9a55a4)で、ReactとTypeScriptのVS Codeでのデバッグ設定をまとめました。

今回はNode.jsとTypeScriptで開発する際のデバッグ方法をまとめます。

## 設定ファイルの生成
VS Codeの「実行とデバッグ」メニューから「launch.jsonファイルを作成します。」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/d7b36845-96f8-b1be-aea0-ced94fdcb967.png)

デバッガーの選択に移るので、「Node.js」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/17de710f-29ee-fc02-53ff-5a7f559a2d86.png)

「.vscode」というディレクトリがルートディレクトリに生成され、「launch.json」というファイルが生成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/c95ec195-f371-71e5-9181-06e0d41c1c43.png)

中身は以下の通りです。
```json:デフォルトのlaunch.json
{
  // IntelliSense を使用して利用可能な属性を学べます。
  // 既存の属性の説明をホバーして表示します。
  // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "プログラムの起動",
      "skipFiles": ["<node_internals>/**"],
      "program": "${file}",
      "preLaunchTask": "tsc: build - tsconfig.json",
      "outFiles": ["${workspaceFolder}/dist/**/*.js"]
    }
  ]
}
```

### 設定ファイルの構成
#### version
特に設定したり変更したりする必要はありません。
基本的に`0.2.0`が設定されています。

#### configurations
デバッグの設定オブジェクトを配列の形式で指定します。
配列で情報を保持しているので、複数のデバッグ設定を定義することもできます。

##### type
デバッガーのタイプを指定します。今回はNode.jsのデバッグを行うので`node`が指定されています。
そのほか`chrome`、`msedge`など様々なタイプを指定することができます。
何が指定できるかは、以下のようにインテリセンス（contol + スペース）を使って確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/44df4d3e-6cc8-b230-3c06-3fda04721cfd.png)

##### request
デバッグの起動設定です。
`launch`と`attach`を指定できます。
`launch`はVS Codeでデバッグのプロセスを起動するもので、一般的にはこちらを設定すれば問題ないです。
`attach`は既に起動しているプロセスに対して接続してデバッグを実行します。
Docker環境でデバッグする場合等はこちらを使います。

##### name
デバッグの設定を識別するための名前です。
「デバッグと実行」メニューのプルダウンに表示されます。

##### skipFiles
デバッグ対象の絞り込みができます。
指定されたパターンに一致するファイルやフォルダをデバッガのステップ実行から除外します。
`<node_internals>`はNode.jsの組み込みモジュールを参照するための「マジックネーム」です。
環境変数とはまた別物ですが、これを指定することで、「node_modules」を除外対象にすることができます。

##### program
デバッガーが実行を開始する**JavaScriptファイル**を指定します。
「.ts」ファイルではなく、「.js」ファイルを指定するのがポイントです。

デフォルトの設定では動かないので、後ほどカスタマイズします。

:::note warn
ts-nodeなどを使用してTypeScriptファイルを直接実行する場合は、この限りではありません。
:::


##### preLaunchTask
デバッグセッションを開始する前に実行するタスクを指定します。
ここではTypeScriptコンパイラを使用して、プロジェクトをビルドするタスクを定義しています。
なお、これは実行するタスクの名前を指定しているだけなので、後ほどタスク自体は別途作成します。

##### outFiles
デバッガーがソースマップを探すべき出力ファイルのパターンを指定します。
TypeScriptはJavaScriptに変換されてから実行されるため、TypeScriptの実装が、変換後のJavaScriptのどの部分と対応しているか、という情報を持っておく必要があります。

それがソースマップです。

${workspaceFolder}はVS Codeでの定義済変数で、ワークスペースフォルダのパスを表します。
dist/**/*.js は、dist ディレクトリとそのサブディレクトリにある全ての .js ファイルを指します。

この設定により、デバッガーはTypeScriptソースコードと生成されたJavaScriptコードを正確にマッピングできます。

### 設定ファイルのカスタマイズ
以下のように編集しました
```json:カスタマイズ後のlaunch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Debug TypeScript",
      "skipFiles": ["<node_internals>/**"],
      "program": "${workspaceFolder}/dist/index.js",
      "preLaunchTask": "tsc: build - tsconfig.json",
      "outFiles": ["${workspaceFolder}/dist/**/*.js"]
    }
  ]
}
```

`program`に`${workspaceFolder}/dist/index.js`を設定しました。
これで生成後のJavaScriptファイルをデバッガーが実行できるようになります。

他には`name`をわかりやすいように変更し、コメントを削除しています。

launch.jsonの設定は以上です。

## タスクファイルの生成
launch.jsonの`preLaunchTask`に指定したタスクの設定を行います。

VS Code上で「⌘ + Shift + P」を実行します。

「Tasks:Configure Task」を入力し、「タスクの構成」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/3642295c-9a5d-b07f-7df1-837a10452574.png)

構成するタスクの選択に移るので、「tsc: ビルド - tsconfig.json」を入力し、表示されたものを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/e6c77c2b-9bb2-926d-e524-d6aac682f43c.png)

launch.jsonと同じフォルダ階層（.vscode内）に「tasks.json」というファイルが生成されます。

```json:デフォルトのtasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "typescript",
      "tsconfig": "tsconfig.json",
      "problemMatcher": ["$tsc"],
      "group": "build",
      "label": "tsc: ビルド - tsconfig.json"
    }
  ]
}
```

### タスクファイルのカスタマイズ
基本的にデフォルトのままで問題ありませんが、ポイントが一つだけあります。

それは`label`に指定されている値と、launch.jsonの`preLaunchTask`が一致しているかどうかを確認するということです。

ここでは、「tsc: ビルド」となっているので、先ほど設定した`preLaunchTask`に合わせて、「tsc: build」としておきます。

```json:カスタマイズしたtasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "typescript",
      "tsconfig": "tsconfig.json",
      "problemMatcher": ["$tsc"],
      "group": "build",
      "label": "tsc: build - tsconfig.json"
    }
  ]
}

```

## tsconfig.jsonの設定を見直す
デバッグを正しく動かすためには、tsconfig.jsonの設定も必要です。
`compilerOptions`内に以下の定義が設定されているかを確認します。

```json:tsconfig.jsonの抜粋
{
  "compilerOptions": {
    // ... 他の設定 ...
    "outDir": "./dist",
    "rootDir": "./src",
    "sourceMap": true
  }
}
```
特に、`outDir`と`sourceMap`が正しく設定できていないと、デバッグ時のソースマップがうまくされないので、しっかり設定を確認しておく必要があります。

## まとめ
Reactに続いて、TypeScriptでのデバッグ設定方法も確認しました。

こういった設定周りはしょっちゅうやるものではないので、なかなか覚えるのが難しく、またそもそも設定する機会もあまりありません。

今回は紹介していませんがDockerで動いているプログラムに対してデバッグをする際はさらに込み入った設定が必要になるので、自分の備忘も兼ねて、いつかまとめられればと思います。

これらの設定について、いつでも対応できるよう、覚えておきたいですね。