はじめに

アプリケーション開発部の田村です。自社で運営するサービス開発を担当しています。
今、担当しているサービスはReactで開発し運用しています。
今回はVisual Studio Codeを使ったReactアプリケーションのデバッグについて私が便利だと感じた機能を紹介します。

本記事を実施する上での要件

  • Visual Studio Code ver 1.50以降
  • Node.js
  • Docker
  • Docker Compose
  • Google Chrome

デバッグについて

デバッグの重要性

我々開発者にとって生産性の向上は重要なテーマです。その生産性の向上に関して、重要であると考えるのがTry & Errorの高速化です。
ここで言うTry & Errorとは以下の作業を指します。

  • コードを書く
  • 動かしてみる
  • エラーの原因を特定して修正する

この繰り返しをどれだけ高速に回せるかが生産性向上にとって重要になります。
今回、フォーカスするのは3つ目の「エラーの原因を特定して修正する」です。
この原因を見つけ出すデバッグを効率よく行うことができれば生産性が向上します。またエラー時だけでなくコード解析でも役に立ちます。

デバッグの方法

コーディングにおけるデバッグといえば、次の2つが一般的です。

  • ログを表示する
  • ブレークポイントで処理を止めて、ステップ実行をする

開発時にはこの2つのうちどちらか、もしくは併用してデバッグを行う方がほとんどです。
ブレークポイントを設定して、ステップ実行するだけの方も多いですが、 Visual Studio Codeではさらに便利に行う機能が備わっているのでそれを紹介します。

アプリケーションの準備

今回はReactアプリケーションを題材にして、Visual Studio Codeでできる便利なデバッグ方法を紹介していきます。
Visual Studio Codeでは言語ごとにデバッグで使える機能に違いあるため、全ての言語で今回紹介するデバッグ機能が使えるわけではありませんが参考にすることは出来ます。

アプリケーションの取得と実行準備

具体的なアプリケーションを使って解説していきます。SPA + REST API構成のサービス開発リファレンスのハンズオンで使用するexampleを利用します。

任意のディレクトリで下記コマンドを実行します。

git clone -b 1.2 https://gitlab.com/ti-spa-restapi/spa-restapi-handson.git

# exampleで使うRest Apiモックサーバを起動します
cd spa-restapi-handson/example/todo-app/frontend/docker/
docker-compose -f docker-compose.api-mock.yml up -d

# npm install
cd ..
npm i

基本的なデバッグを行う

デバッグを行う準備

Visual Studio Codeでアプリケーションを開く

Visual Studio Codeを起動し、メニュー「File」-「 Open Folder…」からspa-restapi-handson/example/todo-app/frontendを開いてください。

これからデバッグを行う際に必要となる「tasks.json」と「launch.json」を作成していきます。
「tasks.json」でReactアプリケーションを起動、「launch.json」でデバッガ起動、といったイメージです。
作成すると下記のような状態になります。

tasks.jsonの作成

アプリケーションの起動はターミナルでnpm startコマンドを実行してもよいのですが、今回はVisual Studio CodeのTask機能を利用します。理由は後ほど説明します。

「.vscode」フォルダを作成し、そこに下記の内容で「tasks.json」を作成してください。

.vscode/tasks.json

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "react-start",
      "detail": "react-scripts start for debug",
      "type": "npm",
      "script": "start",
      "isBackground": true,
      "problemMatcher": [
        {
          "pattern": [
            {
              "regexp": ".",
              "file": 1,
              "line": 1,
              "message": 1
            }
          ],
          "background": {
            "activeOnStart": true,
            "beginsPattern": "^Starting.*$",
            "endsPattern": "^Compiled.*$"
          },
        }
      ],
      "options": {
        "env": {
          "BROWSER": "none"
        }
      }
    },
    {
      "label": "terminate-react-start",
      "command": "${input:terminate}",
      "type": "shell",
      "problemMatcher": []
    }
  ],
  "inputs": [
    {
      "id": "terminate",
      "type": "command",
      "command": "workbench.action.tasks.terminate",
      "args": "react-start"
    }
  ]
}

npm startを起動するタスク「react-start」が作成されました。

このタスクを実行してみましょう。
コマンドパレット(Ctrl + Shift + p)から「Tasks: Run Task」-「react-start」を選択します。すると、Visual Studio Codeのターミナルが起動し、npm startが実行されます。
※ブラウザが自動起動しない設定を入れているので、自動的にブラウザは起動しません。

ブラウザでhttp://localhost:3000にアクセスするとアプリケーションの画面が表示されます。

Visual Studio Codeのターミナルにあるゴミ箱ボタンでタスクを停止します。

launch.jsonの作成

次にGoogle Chromeのデバッグポートを有効にして起動するデバッグ構成を作成します。
下記のファイルを作成します。

.vscode/launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "pwa-chrome",
      "request": "launch",
      "name": "debug react",
      "url": "http://localhost:3000",
      "webRoot": "${workspaceFolder}",
      "preLaunchTask": "react-start",
      "postDebugTask": "terminate-react-start",
    }
  ]
}

「debug react」という名前でデバッグ構成が作成されました。
このデバッグ構成を起動すると下記のように動きます。

  1. preLaunchTaskで指定したreact-startが実行される。このreact-startは「tasks.json」で作成したもの。
  2. デバッグポートを有効にしてGoogle Chromeが起動し、ReactアプリケーションのURLを開く。
  3. Google ChromeのデバッグポートにVisual Studio Codeのデバッグが接続する。

「tasks.json」でReactアプリケーションを起動するようにしたのは、このようにデバッガの起動と連携させることが目的でした。このデバッグ構成を起動するだけでReactアプリケーションも起動してくれるので便利です。

また、少し古い記事ではこのデバッガとして、Visual Studio Codeの拡張である「Debugger for Chrome」が紹介されていました。しかし今ではVisual Studio Code本体に同様の機能(vscode-js-debug)が取り込まれたため、現在ではこの拡張は非推奨とされています。

基本操作

デバッグ構成の起動

作成したデバッグ構成を起動するにはVisual Studio Code上でF5を押下します。

基本的なデバッグ

デバッグの基本操作を確認しておきます。

Visual Studio Codeでsrc/components/Login.tsxを開き、28行目にブレークポイントを設定します。 そしてブラウザ画面の右上の「ログイン」を押下してください。 ユーザ名とパスワードは適当で構いません。
入力してログインボタンを押下します。

すると、先程のブレークポイントで実行行が止まります。

下記のショートカットキー、もしくは上に表示されるツールバーでステップ実行を行います。

キー 操作 動き
F10 ステップオーバー 行単位で実行
F11 ステップイン その行にある関数内に侵入
Shift + F11 ステップイン 現在の関数内から抜けて呼び出し元に戻る
F5 続行 次のブレークポイントが見つかるまで一気に実行する

F10キーで実行行を進める・変数をマウスオーバーして値を確認する、が基本操作になります。
これでも十分便利ですが、更に便利な機能を紹介していきます。

便利なデバッグ方法

Variables

再度、ログイン画面で適当なユーザ名とパスワードを入力してブレークポイントで止めます。 実行ビューの「Variables」を開くとそのフレームで見える変数が一覧で表示されます。
見るだけではなく、変数をダブルクリックもしくはF2キーで値を変更出来ます。
これは下記の用途で使えます。

  • IF文の評価式の変数を操作してIFブロックに入る・入らない、を制御する
  • 変数に不正な値をセットすることで手軽に例外発生時などの挙動を確認できる

Watch

実行ビューの「Watch」を使うと評価式をリアルタイムに確認することが出来ます。
例えば、変数の値ではなく変数の値の文字数などを表示したいといった用途で使えます。

password.length + ": " + password

デバッグコンソール

実行行が止まったフレーム内で式を実行することが出来ます。
メソッドや変数の補完も有効なので、ここで組み上げた式をWatch式に貼り付けると効率が上がります。

Run to cursor

行きたい行にカーソルを移動し、そこで右クリック-「Run to cursor」を選択するとその行まで実行してくれます。
F10キーを連打して実行行を進めるより効率的です。

Restart Frame

F10のステップオーバーを連打しすぎて「あっ、行き過ぎた」という時、もう一度最初からやり直したい時に使える機能です。
名前の通りCal StackのFrameをもう一度最初からやり直すことで、実行行が最初のFrameに戻るので、ステップ実行をやり直すことが出来ます。

ログポイント

ログポイントを使用すると、コードを修正することなくコンソールに変数の値を出力することが出来ます。

変数の中身は確認したいがブレークポイントは煩わしい、そんな時はconsole.logコードを埋め込むことになります。
ただこの方法は、デバッグが難航してくると終わった後のconsole.logコードの消し忘れ・リコンパイルにより画面が再描画されてしまうことで開発リズムが悪くなる、などのデメリットがあります。
ログポイントを利用すればこれらを解消できます。

Visual Studio Codeでsrc/components/TodoList.tsxを開き、21行目にブレークポイントを設定します。
そのブレークポイントで右クリック-「Edit Breakpoint…」を選択します。
次に「Log Message」を選び、下記の式を入力します。

todo id = {todo.id}, todo title = {todo.text}

「Log Message」内に書く式は、テンプレートリテラルの形式です。

確認の邪魔になるので前述のsrc/components/Login.tsxに設定したブレークポイントは削除します。

適当なユーザ名とパスワードでログインして、Todo一覧画面を表示します。
ブレークポイントが設定されていますが、ログポイントの場合は実行行が止まらず、DEBUG CONSOLEに先程のログが出力されます。

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

特定の条件でのみブレークポイントを有効にすることが出来ます。

例えば、前述のsrc/components/TodoList.tsxの21行目のブレークポイントで、「やること2」の時に実行行を止めたい場合に便利です。
21行目のコードはループ処理の中にあるため、通常のブレークポイントでは「やること1」のデータをF5キーでやり過ごす必要がありますが、条件付きブレークポイントを使えばそんな煩わしさがありません。

20      {todos.map(todo =>
21        <TodoItem key={todo.id} id={todo.id} text={todo.text} completed={todo.completed} toggleTodoCompletion={toggleTodoCompletion} deleteTodo={deleteTodo}/>
22      )}

21行目に設定したブレークポイントを右クリック-「Edit Breakpoint…」を選択します。
条件式に下記のコードを入力します。

todo.text === 'やること2'

今回は2件しかデータがないので嬉しさを感じづらいですが、多くのデータがある場合には便利です。

※画像内で、「やること2」が2回呼ばれていますが、これはReactのReact.StrictModeコンポーネントの影響です。開発時はこの機能によりRenderフェーズが複数回呼ばれます(参照)。

まとめ

Visual Studio Codeを使うことで、デバッグ作業の効率を向上させることが出来、生産性向上に繋がります。
普段はブレークポイントを設定してステップ実行をするだけの方も、今回紹介した方法を試してみてください。


本コンテンツはクリエイティブコモンズ(Creative Commons) 4.0 の「表示—継承」に準拠しています。