Visual Studio Codeはlaunch.jsonファイルで構成を行うことで、デバッグをさまざまに構成可能だ。Node.jsを対象に構成ファイルの取り扱いの基本を説明する。
前回は、Visual Studio Code(以下、VS Code)でデバッグを行うために基本事項を取り上げた。その中で最後に説明したlaunch.jsonファイル(デバッグの構成ファイル)について見てみよう。
前回も述べた通り、launch.jsonファイルは[デバッグ]ビューにある['launch.json' を構成または編集してください]ボタン(歯車のボタン)をクリックすることで、作成できる。このときに、VS Codeがどの環境でのデバッグ構成を行おうとしているのかを自動的に判断してくれるが、うまく判断できなかった場合には、問い合わせを行うメッセージが表示されるので、そこでデバッグ環境を指定してやる。以下はExpressベースのアプリをexpress-generatorを使用して作成し、launch.jsonファイルを作成しようとしたところだ。
ここではNode.js+Expressな環境でデバッグを行うので、[Node.js]を選択した。すると、次のようなlaunch.jsonファイルが作成される。ファイルが作成されるのは、VS Codeで開いている最上位のディレクトリにある.vscodeディレクトリだ。
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceRoot}\\bin\\www"
}
]
}
なお、launch.jsonファイルの生成時には、VS Codeがpackage.jsonファイルの内容などを見て、自動的に構成を行ってくれる部分もある(上のprogram属性など)。では、このファイルの内容について見ていこう。
launch.jsonファイルは、さまざまな環境に応じて、さまざまな構成で作成されるが、それら全てで必須となる属性としては以下のものがある。
属性 | 説明 |
---|---|
type | デバッガーの種別 |
request | デバッグ時にプログラムを起動するか(launch)、既に起動しているプログラムにデバッガーをアタッチするか(attach) |
name | デバッグ構成として表示する名前 |
必須の属性 |
上に示したlaunch.jsonファイルを見ると、type属性の値はもちろん"node"となっている。request属性の値は新規にプログラムを起動することを意味する"launch"に、name属性の値は"Launch Program"となっていて、これがデバッグに使用する構成の名前としてVS Codeに表示される。
最後のprogram属性はデバッグ実行時に起動するプログラムのパスを指定するもので、多くのデバッグ環境がサポートしている。前述した通り、ここではExpressベースのプロジェクトをexpress-generatorを使用して作成したので、そのエントリポイントとなる「bin\www」ファイルが指定されている。
request属性には"launch"か"attach"を指定可能であり、前者を指定すればデバッグ開始時にプログラムが新規に起動され、後者を指定すれば既に起動中のプログラムにアタッチする。アタッチ用の構成を加えると、launch.jsonファイルは次のようになる。
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceRoot}\\bin\\www"
},
{
"type": "node",
"request": "attach",
"name": "Attach Program"
}
]
}
アタッチ用の構成では、起動するプログラムのパスは不要なので記述しない(記述できない)。このような構成にすると、[デバッグの開始]ボタンの右にあるドロップダウンに2つの構成が表示されるようになる。このような設定にすれば、コンソールや統合ターミナルなどからプログラムをデバッグモードで起動している状態で、[Attach Program]を選択してデバッグを実行すれば、起動中のプログラムにアタッチできる。これについては後で実際に見てみよう。
Node.js用のlaunch.jsonファイルには、この他にも多くの属性を記述可能だ。そのうちの幾つかを抜粋して以下に示す。まずはrequest属性が"launch"でも"attach"でも使用できるものから。
属性 | 説明 |
---|---|
protocol | デバッグに使用するプロトコル |
port/address | デバッグで使用するポート/IPアドレス |
stopOnEntry | プログラム起動直後にデバッグ実行を中断するか |
sourceMaps | ソースマップを有効にするかどうか |
outFiles | トランスパイル後のJavaScriptファイルの位置を指定。ソースマップ有効時に指定する |
smartStep | ソースマップの対象外のコードのステップ実行を省略するかどうか |
skipFiles | ステップ実行の対象外とするファイルを指定 |
trace | 診断出力の設定 |
request属性が"launch"でも"attach"でも記述可能な属性 |
request属性が"launch"の場合には、以下の属性もサポートされる。
属性 | 説明 |
---|---|
program | 起動するプログラムのパス |
args | デバッグ実行時にプログラムに渡す引数 |
cwd | デバッグ実行を行うディレクトリ |
runtimeExecutable | 使用するランタイム環境 |
runtimeArgs | ランタイム環境に渡す引数 |
env | 環境変数の指定 |
envFile | 環境関数を定義したファイル |
console | プログラムを起動するコンソールの種類を指定 |
request属性が"launch"の場合にサポートされる属性 |
request属性が"attach"の場合には以下がサポートされる。
属性 | 説明 |
---|---|
processId | アタッチするプロセスのプロセスID |
request属性が"attach"の場合にサポートされる属性 |
この他にも、デバッグを開始する前に実行するタスクを指定するpreLaunchTask属性、デバッグコンソールの表示を制御するinternalConsoleOptions属性などを利用可能だ。次にExpressベースのプログラムを実際にデバッグ実行しながら、幾つかの属性を見てみよう。
本稿ではexpress-generatorを使用して、Expressアプリを作成して、ほんの少しだけ手を加えている。Express自体の詳しい説明はしないので、興味のある方は公式サイトや「Node.jsのMVCフレームワーク「Express」の基礎知識とインストール」などを参照されたい。
見ての通り、スケルトンコードで表示されるウエルカムメッセージの下にテキストボックスとボタンを配置しただけのもので、すぐに想像できるように、テキストボックスに何かを入力して[hello]ボタンをクリックすると、その下に「Hello XXX」のようなメッセージが表示されるようになっている。
生成されたコードのうち、手を加えたのはindex.jsファイルとindex.jadeファイルだ。index.jsファイルでは入力を受け取ったら、それを加工して、index.pugファイルで定義されているビューを表示している。
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.post('/', function(req, res) {
let name = req.body.name;
console.log(name);
res.render('index', { title: 'Express', msg: `Hello ${name}` });
});
module.exports = router;
index.pugファイルでは、上で見たUI要素を定義している。
extends layout
block content
h1= title
p Welcome to #{title}
form(action='/', method='POST')
input(type='text', name='name', size=40)
input(type='submit', value='hello')
p #{msg}
launch.jsonファイルでは上でも見た通り、プログラムの起動とアタッチの両方の設定を行ってある。
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceRoot}\\bin\\www"
},
{
"type": "node",
"request": "attach",
"name": "Attach Program"
}
]
}
以下では、launch.jsonファイルの構成を変えながら、デバッグ実行を行っていくことにする。
まずは上に示した基本構成で、デバッグ時にプログラムを新規に起動するパターンを見てみよう。これには単に[デバッグ]ビューで[Launch Program]を選択して、[デバッグの開始]ボタンをクリックするだけだ。ここでは10行目にブレークポイントを設定した。
デバッグ実行を開始すると、デバッグツールバー(ウィンドウ上部)やパネル(ウィンドウ右下)が表示され、パネルでは[デバッグ コンソール]タブが選択される(パネルが表示されない場合はメニューバーから[表示]−[デバッグ コンソール]を選択するか、[Ctrl]+[Shift]+[Y]キーを押す)。
ここでテキストボックスに何かを入力して、[hello]ボタンを押すと、実行が中断される。これはいつものデバッグの様子だ。ここでデバッグ実行の開始時に、一度、実行を中断して、いろいろと確認したいとする。その場合には、stopOnEntry属性だ。デバッグ実行を中断して、これを追加してみよう。
{
"version": "0.2.0",
"configurations": [
{
…… 省略 ……
"stopOnEntry": true
},
{
…… 省略 ……
}
]
}
この構成でデバッグ実行を開始すると、Expressアプリのエントリポイントである「bin\www」ファイルの先頭で実行が中断されるようになる。
このように、launch.jsonファイルに構成を追加していくことで、細やかな構成でデバッグを行えるようになる。もう1つの例として、Node.jsのコアモジュールのステップ実行をスキップする構成を以下に示す。
{
"version": "0.2.0",
"configurations": [
{
…… 省略 ……
"skipFiles": [
"<node_internals>/**/*.js"
]
},
{
…… 省略 ……
}
]
}
skipFiles属性にはglob形式でステップインを飛ばしたいファイル群を指定していく。上で使っている「<node_internals>」はNode.jsの組み込みコアモジュールを参照する「マジックネーム」となっている。よって、この記述を追加すれば、Node.jsの内部モジュールの実行がスキップされるようになる(またno_modulesディレクトリ以下の全ての.jsファイルをスキップするには「"${workspaceRoot}/node_modules/**/*.js」を追加すればよいようにも思えるが、筆者が試したところでは期待した通りにはスキップされなかった。筆者の期待が間違っている可能性がある)。
ステップ実行がスキップされたファイルについては、[デバッグ]ビューの[コール スタック]ペーンで薄いグレーで表示されるようになる。ファイルをスキップするルールなどについては「Skipping uninteresting code」ページを参照されたい。
次にアタッチをしてみよう。
まずはコンソールや統合ターミナルから「node debug bin\www」「node --debug bin\www」などのコマンドを入力して、デバッグモードでアプリを実行する。あるいはpackage.jsonファイルにデバッグ用のスクリプトを記述して、「npm run-script debug」などとしてもよい。
例えば、以下は統合ターミナルからコマンドラインでプログラムをデバッグモードで実行しているところだ。
そして、[デバッグ]ビューで[Attach Program]構成を選択して、[デバッグの開始]ボタンを実行する。アタッチができれば後は通常通りにデバッグを行える。
デバッグ用のツールバーの右端には、アタッチを解除するボタンがあるので、デバッグが終了したらこれをクリックしよう(ただし、起動したプログラムは依然として実行を続けた状態となるので注意)。
VS Codeではnpmをランタイム環境としてデバッグを行うことも可能だ。これには、runtimeExecutable属性を指定する。例えば、package.jsonファイルに以下のようなデバッグ用スクリプトを追加し、その設定を利用してデバッガーを起動できる。ここではInspectorプロトコルを使うように指定している(デフォルトのポート番号は9229)。
{
"name": "expressapp",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www",
"debug": "node --inspect ./bin/www"
},
"dependencies": {
…… 省略 ……
}
}
このとき、対応するlaunch.jsonファイルのエントリは次のようになる。
{
"version": "0.2.0",
"configurations": [
{
…… 省略 ……
},
{
…… 省略 ……
},
{
"type": "node",
"request": "launch",
"name": "Launch from npm script",
"runtimeExecutable": "C:\\Program Files\\nodejs\\npm.cmd",
"runtimeArgs": [
"run-script", "debug"
],
"protocol": "inspector",
"port": 9229
}
]
}
ここではruntimeExecutable属性にはnpmへのフルパスを指定している(筆者が試したところでは単に「npm」とするだけではうまくいかなかったため)。runtimeArgs属性にはnpmに与える引数を指定する。「npm run-script debug」コマンドを実行するので、ここでは"run-script"と"debug"を指定している。protocol属性にはpackage.jsonで指定した「"node --inspect ./bin/www"」に合わせて"inspector"を指定し、port属性にはInspectorプロトコルで使用するデフォルトポート番号の9229を指定している。
この状態で、[Launch from npm script]を選択して[デバッグの開始]ボタンをクリックすれば、[デバッグ コンソール]パネルからプログラムが起動されて、デバッグ実行が開始される。
この辺りの設定は結構面倒くさいところがあり(特にVS Codeの側でいろいろと気を使ってくれるのが、逆に分かりにくくなっているような気がする)、試行錯誤が必要になるかもしれない。うまくいかないときには、ポートとプロトコルを適切に設定できているかに注意しよう。
今回はNode.jsプログラムのデバッグを行う際に、そのデバッグ構成を行う方法を見た。本稿では取り上げなかった属性もたくさんあるので、興味のある方は「Node.js Debugging in VS Code」ページや「Node.js Tutorial in VS Code」ページなどを参照されたい。
次回はVS Codeで.NET Coreコードをデバッグするための構成などについて見ていく予定だ。
Copyright© Digital Advantage Corp. All Rights Reserved.