ts-node(typescript)デバッグ設定(VSCode)

* 変更履歴

1. 2021/06/19: エディタで開いている(アクティブな).tsファイルをデバッグするように変更(デバッグ設定ファイルを書き換える必要がなくなりました)

## できること

1. ts-nodeを使い、開いている.tsファイルを *コンパイルすことなく* デバッグする
1. もしくは、ts-nodeで実行中のスクリプトにアタッチしてデバッグする

## 経緯

* ts-nodeを利用した場合のデバッグ方法がよくわからなかったため、調べた結果をまとめました。
  * ※typescriptをtscでトランスパイルしてからデバッグする場合tsconfig.jsonでmapファイルの設定が必要です(.ts, .jsで互いの行位置を認識しないとブレークポイントを張ったり、行ステップ実行ができない。)
  
    一方、ts-nodeはtsconfig.jsonでmapファイルの指定をしない(デフォルトのまま)でもデバッグできるようです(公式ページに「TypeScript execution and REPL for node.js, with source map support.」と書いてあるので、気にしなくてもsource mapがサポートされているようです）

* VSCodeデバッグの概要
  * 「./.vscode/launch.json」にデバッグ用の設定を記載する
  * 設定でデバッガから起動(launch)するか、起動中のプログラムにアタッチ(attach)するか記載する。
  * 起動する設定の場合は、開始ソースファイル名を指定する。
  * アタッチする場合は、アタッチ対象を選択するための(プロセス)ピッカーを表示する設定を行う

## launch.jsonについて <a id="anchor2"></a>

* VSCodeでデバッグを行う場合に必要(作成される)な設定ファイルです。
* 「./.vscode/launch.json」に下記をコピーすればデバッグできます。
  * ファイルがない場合は、デバッグボタンをクリックして作成してから内容を上書きしてください。
![create_launch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276579/cf4e41cb-2d28-b10f-114b-13e110f8c258.png)

下記ソースを張り付ければts-nodeでデバッグできるようになります。

```json
{
  "version": "0.2.0",
  "configurations": [    
    {
      "name": "エディタで開いている(アクティブな).tsファイルをデバッグ",
      "type":  "pwa-node", // 利用するデバッガの種類をVSCodeに伝える。"node"でも良いが、"pwa-node"の方が新しいデバッガのためこちらを利用(progressive web apps とは関係ない)
      "request": "launch", // デバッガ起動時に、対象プログラム("program")を起動する
      "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], // ts-nodeを読み込みます(nolazyは無くても動きます。V8エンジンにスクリプト解析を延滞させないためのオプション(指定しないとブレークポイントスキップする可能性があるため))
      "args": ["${file}", "--transpile-only"], // デバッグを開始するファイルを指定する。「${file}」はアクティブなファイルのフルパス(開いているファイルをデバッグする)
      "skipFiles": ["<node_internals>/**", "node_modules/**"],
      "env": {
        "TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json"
      }
    },
    {
      "type": "pwa-node",
      "request": "attach",
      "name": "実行中のnodeプログラムにアタッチしてデバッグ",
      "processId": "${command:PickProcess}",      
    },   
    {
      "type": "node",
      "name": "Debug Jest script",      
      "request": "launch",
      "runtimeArgs": [
        "--inspect-brk",
        "${workspaceRoot}/node_modules/jest/bin/jest.js",
        "--runInBand"
      ],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "port": 9229
    }
  ]
}
```

## テスト対象のプログラムについて <a id="anchor3"></a>

githubにあるこのサンプルで試すことができます
[Expressをディレクトリ構成変えずに最小限の手間でTypescriptにする手順](https://github.com/murasuke/express-generator-tsnode)

* 任意のフォルダにcloneしてから、必要なモジュールをインストール(npm install)します。

```bash
git clone https://github.com/murasuke/express-generator-tsnode
cd express-generator-tsnode/
npm install
```

* **実行とデバッグ**ボタンを押して「launch.json」ファイルを作成し、上記ソースを貼り付けます。

## 対象プログラムを起動してデバッグ <a id="anchor4"></a>

* 実行を開始するファイル「express-generator-tsnodeであれば./bin/www.ts」を開いてからデバッグを開始します。

```json
    {
      "name": "エディタで開いている(アクティブな).tsファイルをデバッグ",
      "type":  "pwa-node", // 利用するデバッガの種類をVSCodeに伝える。"node"でも良いが、"pwa-node"の方が新しいデバッガのためこちらを利用(progressive web apps とは関係ない)
      "request": "launch", // デバッガ起動時に、対象プログラム("program")を起動する
      "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], // ts-nodeを読み込みます(nolazyは無くても動きます。V8エンジンにスクリプト解析を延滞させないためのオプション(指定しないとブレークポイントスキップする可能性があるため))
      "args": ["${file}", "--transpile-only"], // デバッグを開始するファイルを指定する。「${file}」はアクティブなファイルのフルパス(開いているファイルをデバッグする)
      "skipFiles": ["<node_internals>/**", "node_modules/**"],
      "env": {
        "TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json"
      }
    },
```

## 起動中のnodeにアタッチしてデバッグ <a id="anchor5"></a>

```json
{
  "type": "pwa-node", // 利用するデバッガの種類をVSCodeに伝える。
  "request": "attach",  // 起動中のプログラム(node)にアタッチしてデバッグする
  "name": "実行中のnodeプログラムにアタッチしてデバッグ",
  "processId": "${command:PickProcess}",  // デバッグ開始時、プロセスのピッカーを表示(デバッグ対象のnodeプロセスを選択する)
},   
```

* デバッグを開始すると「プロセス選択リスト」が表示されます。適切なプロセス(ここでは`node ./bin/www`)を選択します。

![process_picker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276579/7d6160ce-f9cc-ccaf-c14a-f278a3e34bef.png)

## おまけ：jestでテスト対象のプログラムをデバッグ <a id="anchor6"></a>

* これで.test.tsファイルのデバッグできました

```json
    {
      "type": "node",
      "name": "Jestのテストコードをデバッグ",      
      "request": "launch",
      "runtimeArgs": [
        "--inspect-brk",
        "${workspaceRoot}/node_modules/jest/bin/jest.js",
        "--runInBand"
      ],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "port": 9229
    }
```