TypeScriptをVSCodeのデバッグ機能で動かす環境構築 + ESLint, Prettier

先人達の記事を参考にしながら､TypeScriptを手軽にVSCodeで動かすための個人的な最適解ができたので紹介する｡
ESLint, Prettierも入れて実用的な環境構築となっている｡

｢TypescriptとかESLintとかのセットアップは別にいいから､**VSCodeの設定**が知りたい!｣
という人は [👇🏽VSCodeのデバッグ設定](#vscodeのデバッグ設定) にジャンプ!

## 構築する環境

- VSCodeの **デバッグ機能**(F5押下) で **TypeScript** を動かせる｡
  - 内部的にTSCコマンドでビルドされる｡
- **ESLint** と **Prettier** を入れる｡

下記は対象外とする｡

- ESBuildなどは入れない｡シンプルなTSCコマンドビルド環境｡
- Vue.jsなどブラウザ環境ではない｡TSからビルドされたJSを **Node.js** 上で動かす｡

:::note info
執筆時点(2024/08/08)のバージョンで説明する｡
- @eslint/js: `^9.8.0`
- @typescript-eslint/eslint-plugin: `^8.0.1`
- @typescript-eslint/parser: `^8.0.1`
- eslint: `^8.57.0`
- eslint-config-prettier: `^9.1.0`
- eslint-plugin-prettier: `^5.2.1`
- prettier: `^3.3.3`
- typescript: `^5.5.4`
- typescript-eslint: `^8.0.1`
:::

## 前提

下記をインストールしておく｡

- Node.js (npmコマンドが使える状態) 
- VSCode､拡張機能
  - [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
  - [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)

## 各種パッケージのインストール

#### npmプロジェクトの作成(`package.json`の生成) 

```bash
npm init -y
```

#### TypeScriptのインストール

```bash
npm install -D typescript
```

#### ESLint･Prettierのインストール

```bash
npm install -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin prettier eslint-config-prettier eslint-plugin-prettier
```
- ESLint関連:
  - eslint
  - @typescript-eslint/parser
  - @typescript-eslint/eslint-plugin
- Prettier関連:
  - prettier
  - eslint-config-prettier
  - eslint-plugin-prettier

## 各種初期設定


#### TypeScriptプロジェクトの作成(`tsconfig.json`の生成) 

```bash
npx tsc --init
```

:::note info
TypeScriptをローカルにインストールした場合は`tsc`コマンドのパスが通っていないため､`tsc`コマンド単体で実行できない｡
`npx`+`tsc`を組み合わせて実行する｡
:::

#### ESLintの初期設定
対話型で進んでいく｡
選択内容はVue.jsを始めとするフロントか､**それ以外のNode.js**か等々で異なってくる｡今回はそれ以外｡

```bash
npx eslint --init
```

```
You can also run this command directly using 'npm init @eslint/config'.
? How would you like to use ESLint? ...
  To check syntax only
> To check syntax and find problems
  To check syntax, find problems, and enforce code style

? What type of modules does your project use? ...
> JavaScript modules (import/export)
  CommonJS (require/exports)
  None of these

? Which framework does your project use? ...
  React
  Vue.js
> None of these

? Does your project use TypeScript? » No / <Yes>

? Where does your code run? ...  (Press <space> to select, <a> to toggle all, <i> to invert selection)
  Browser
> Node

? What format do you want your config file to be in? ...
  JavaScript
  YAML
> JSON

@typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest
? Would you like to install them now? » No / <Yes>

? Which package manager do you want to use? ...
> npm
  yarn
  pnpm
```

:::note warn
稀に､それぞれ最新バージョンのTypescript､ESLintだと相互対応していないケースがある｡

```
npm warn node_modules/eslint
npm warn   peer eslint@"^8.56.0" from typescript-eslint@7.18.0

･･･

Successfully created E:\ ファイルパス \eslint.config.mjs file.
Note that some plugins currently do not support ESLint v9 yet.
You may need to use '--force' when installing, or add the following to your package.json:
"overrides": { "eslint": "^9.8.0" }
```

上記の例だと､TypeScript側がESLint`9.8.0`に未だ対応していない(だろう)ということが分かる｡
→ ESLintの再インストールと､ESLintの初期設定をやり直す｡

#### ESLintをバージョン指定し再インストール

バージョンはエラーログに記載されているバージョンでまずは試すと良い｡
<sub>(確実なのはnpmのサイト or GitHubのReleaseを見ること)</sub>

```bash
npm install -D eslint@8.56.0
```

#### ESLintの再初期設定

```bash
npx eslint --init
```
:::

#### ESLintの設定

prettierを使用していることを書いてあげる｡

```diff_json:eslintrc.json
 {
   "env": {
     "browser": false,
     "es2021": true
   },
   "extends": [
     "eslint:recommended",
     "plugin:@typescript-eslint/recommended",
+    "prettier"
   ],
   "parser": "@typescript-eslint/parser",
   "parserOptions": {
     "ecmaVersion": "latest",
     "sourceType": "module"
   },
   "plugins": [
       "@typescript-eslint",
+      "prettier"
     ],
   "rules": {
+    "prettier/prettier": "error"
   }
 }

```

#### Prettierの設定(任意)

プロジェクトルート直下に`.prettierrc.json`を作成する｡
お好みで自動整形ルールを書いていく｡

```.prettierrc.json
{
  "semi": false,
  "tabWidth": 2,
  "singleQuote": true,
  "printWidth": 100,
  "trailingComma": "es5"
}
```

> 最新のESLint v9.xではデフォルトの設定ファイルが**mjs形式**に変わるらしい?

#### Prettierの除外設定(任意)
プロジェクトルート直下に`.prettierignore`を作成する｡
`tsconfig.json`はコメントがズレるので整形させない方が良い｡

```.prettierignore
tsconfig.json
```

#### TypeScriptのビルド設定`tsconfig.json`(必須)

すでに設定はコメントアウトで記載されているため､解除して値を変えてあげる｡

```json-doc:tsconfig.json
{
  "compilerOptions": {
    ･･･
    "rootDir": "./src", // ソースファイルのルートフォルダ
    "sourceMap": true,  // ソースマップ(デバッグツールが､ビルド後のファイルとソースコードファイルの対応を見るために使う中間ファイルを生成する)
    "outDir": "./dist", // ビルド後の出力先フォルダ
```

:::note warn
`"sourceMap": true`を入れないと､VSCodeのデバックが動かないため注意｡
:::

:::note info
`src`ディレクトリ配下にまだファイルがないため､1文字目で下記エラーが出る場合がある｡無視して良い｡
```
構成ファイル 'xxxxx/tsconfig.json' で入力が見つかりませんでした。
指定された 'include' パスは '["**/*"]' で、'exclude' パスは '["xxxxx/dist"]' でした。ts
```
:::

- `target`､`module`､`lib`等はデプロイ先環境が対応しているESバージョンに依って変わる｡
    - 今回は説明できないが､tsconfig.jsonの書き方で検索すると色々出てくる｡
- その他は一旦デフォルト設定で良い｡

#### ESLintとPrettierの起動スクリプトを定義(任意)

```package.json
  "scripts": {
    "lint": "eslint . --ext .ts",
    "format": "prettier --write ."
  }
```

これで下記コマンドを実行してESLintを起動できる｡ (今はソースコードが無いため､動かしてもあまり意味がない｡)

```bash
npm run lint
npm run format
```

#### ここまでのディレクトリ構造

**src** と **dist** ディレクトリを作っておく｡

```bash
mkdir src
mkdir dist
```

プロジェクトルート直下に各設定ファイルが並んでいれば正解｡

```diff
 .
+├── dist
 ├── node_modules
 │   ├── ･･･
+├── src
 ├── .prettierignore
 ├── .prettierrc.json
 ├── eslint.config.mjs
 ├── package-lock.json
 ├── package.json
 └── tsconfig.json
```

任意設定も書いていたら長くなってしまったが､パッケージ類の初期設定は一旦ここまで✅

## VSCodeのデバッグ設定

### launch.json を作成する

VSCodeで **🪲実行とデバッグ** を開き､ **launch.json ファイルを作成します** を押下する｡
![launch.jsonファイルを作成します.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1545436/d2c060d9-c406-8e7d-b957-d702ddd26e26.png)

デバッガーの選択で､ **Node.js** を選択する｡
![デバッガーの選択 Node.js.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1545436/f13cfddf-bb6d-6241-7215-9b57cba13ec0.png)

ルート直下の`.vscode`ディレクトリ内に､`launch.json`ファイルが作成される｡

### launch.json を修正する

```diff_jsondoc:launch.json
 {
   // IntelliSense を使用して利用可能な属性を学べます。
   // 既存の属性の説明をホバーして表示します。
   // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
   "version": "0.2.0",
   "configurations": [
-    {
-      "type": "node",
-      "request": "launch",
-      "name": "プログラムの起動",
-      "skipFiles": ["<node_internals>/**"],
-      "program": "${workspaceFolder}\\src\\main.ts",
-      "outFiles": ["${workspaceFolder}/**/*.js"]
-    }
+    {
+      "type": "node",
+      "request": "launch",
+      "name": "TypeScriptの起動",
+      "preLaunchTask": "TSC Compile",
+      "cwd": "${workspaceFolder}",
+      "program": "${file}",
+      "console": "internalConsole"
+    }
   ]
 }
```
:::note info
`preLaunchTask`は次の項で定義する｡
デバッグ起動前に実行するタスクのことで､ここに **tscコマンド** でコンパイルするタスクを入れる｡
:::

その他`name`や`console`などはお好みで調整して欲しい｡


### tasks.json を作成する

`.vscode`ディレクトリに`tasks.json`というファイルを手動で作成する｡

```tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "shell",
      "label": "TSC Compile",
      "command": "npx",
      "args": ["tsc", "-p", "."],
      "options": {
        "cwd": "${workspaceFolder}"
      },
      "problemMatcher": ["$tsc"],
      "group": "build",
      "detail": "TSC: build - tsconfig.json using npx",
      "presentation": {
        "reveal": "always",
        "panel": "new"
      },
      "runOptions": {
        "runOn": "default"
      }
    }
  ]
}
```

ここまででこんな感じのディレクトリ構造になっていれば正解｡

```diff
 .
 ├── .vscode
+│   ├── launch.json
+│   └── tasks.json
 │
 ├── .eslintrc.json
 ├── ･･･
```

## デバッグを実行する

ここまでの設定が済めば､実行とデバッグに`launch.json`で記載した項目が表示されている｡
![実行とデバッグメニューに項目が追加される.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1545436/a9fc0415-a269-fa62-132a-e933ee8c9274.png)

適当なソースコードを書いて､ブレークポイントを打って､▶️デバッグを実行する｡
![ブレークポイントを打ってデバッグ実行する.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1545436/fb1bd010-d638-a005-7e6e-0cffb0084b2f.png)
無事にブレークポイントで止まって､デバッグが動作した!!🍻
また､ **distディレクトリ** にコンパイルされたJSファイルが出力されているはずだ｡

## 参考文献

https://zenn.dev/byebyeworld/articles/vscode-typescript-debug

https://zenn.dev/big_tanukiudon/articles/c1ab3dba7ba111?utm_source=pocket_saves