- Fedora 31 on WSL1
- NodeJS 14.4.0
- VSCode 1.48.2
Remote WSL で VSCode を WSL 上で簡単に実行できるので、次のような Launch Configuration だけでリモートデバッグ出来ます。また、runtimeExecutable
やら runtimeArgs
やらで ts-node
を使えば ts が直接実行できます。
{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "restart": true, "name": "Launch Program", "skipFiles": [ "<node_internals>/**" ], "program": "${workspaceFolder}/src/app.ts", "runtimeExecutable": "ts-node", "runtimeArgs": ["-T"], } ] }
ホスト機が Windows であることなどまったく気にする必要ありません。完。
シンボリックリンク内のワークスペースの問題
と思っていたのですが、実際にやってみたらダメでした。ワークスペースのパスにシンボリックリンクが含まれていてその中で VSCode を開いていると、ブレークポイントを設定しても Unbound breakpoint とか言われて止められません。
例えば、次のようなシンボリックリンクがあり、
ln -sfn /c/Users/oreore/devel /home/oreore/devel
ワークスペースのパスが /home/oreore/devel/path/to/project
だとすると、それをそのまま開いてもダメでした。/c/Users/oreore/devel/path/to/project
を開く必要があります。
諸事情で普段いつもパスにシンボリックリンクが含まれている場所で作業しているので、これだとかなり都合が悪いです。
下記の Issue によると runtimeArgs
で --preserve-symlinks
と --preserve-symlinks-main
を指定すれば良い、とのことですが、ダメでした。
VSCode の設定で debug.javascript.usePreview: false
を指定すれば大丈夫でした。
{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "restart": true, "name": "Launch Program", "skipFiles": [ "<node_internals>/**" ], "program": "${workspaceFolder}/dist/app.js", "runtimeArgs": [ "--preserve-symlinks", "--preserve-symlinks-main" ] } ] }
ただ node
コマンドのオプションを指定する必要があるため ts-node
は使えません。runtimeArgs
で -r ts-node/register/transpile-only
を付けるようにしてもダメでした。
outFiles
でビルドされた js ファイルを指定すれば実行できました。
{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "restart": true, "name": "Launch Program", "skipFiles": [ "<node_internals>/**" ], "program": "${workspaceFolder}/src/app.ts", "outFiles": ["${workspaceFolder}/dist/**/*.js"], "runtimeArgs": [ "--preserve-symlinks", "--preserve-symlinks-main" ] } ] }
ただこれだとあくまでもビルドされた js が実行されるだけであって ts ファイルが直接実行されているわけではありません。
次のようにコマンドを叩けば node
コマンドからでも直接 ts ファイルが実行できているんですけど・・なんででしょうね?
node --preserve-symlinks --preserve-symlinks-main -r ts-node/register/transpile-only src/app.ts
VSCode の NodeJS デバッガー拡張
複数あるもよう。
ms-vscode.js-debug
が最も新しいデバッガーで debug.javascript.usePreview: true
のときに使用されます(デフォルト true
なので明示的に無効にしない限りこれが使用される)。
ms-vscode.node-debug
と ms-vscode.node-debug2
は debug.javascript.usePreview: false
のときに使用されます。どちらが使用されるかは NodeJS のバージョンで自動的に決定されます。Launch Configuration で指定することもできます。
また、Launch Configuration の type
で pwa-node
を指定すると debug.javascript.usePreview
には依らず ms-vscode.js-debug
使用されるようです。
なお、この pwa は プログレッシブウェブアプリケーション のことではないようです。
node のコマンドの開始方法も異なります。ms-vscode.js-debug
の場合は環境変数 NODE_OPTIONS
にデバッガに必要なオプションが指定されます。なので ts-node
などを runtimeExecutable
に指定することができます。一方で ms-vscode.node-debug
や ms-vscode.node-debug2
ではコマンドラインオプションに --debug-brk
や --inspect-brk
が直接追加されます。
前述のシンボリックリンク問題が --preserve-symlinks
と --preserve-symlinks-main
で解決するというのは、リンクされている PR が ms-vscode.node-debug2
のものなので、ms-vscode.js-debug
だと効果ないようです。
また、ms-vscode.node-debug2
だと program
で指定されたファイルが js かどうかを判定して、js ではない場合はソースマップから js ファイルを特定してそちらを実行するようになっています。
拡張子が .js .es6 .jsx .mjs のいずれかだと js だと判定されるようです。
Launch Configuration で __debuggablePatterns
で *.ts
を指定すれば ts ファイルを直接実行させられる?
と思ったんですがダメでした。
remoteRoot で実際のパスを指定
debug.javascript.usePreview: true
のままでも、remoteRoot
でシンボリックリンクを解決した実際のパスを指定すれば大丈夫でした。
{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "restart": true, "name": "Launch Program", "skipFiles": [ "<node_internals>/**" ], "program": "${workspaceFolder}/src/app.ts", "runtimeExecutable": "ts-node", "runtimeArgs": ["-T"], "localRoot": "${workspaceRoot}", "remoteRoot": "/c/Users/oreore/devel/path/to/project", } ] }
remoteRoot
にパスをベタ書きする必要があるのがちょっとイケていないですね。
VSCode を Windows で実行して WSL の node プロセスにアタッチ
VSCode は Windows 上で実行しつつ、WSL 内で node --inspect dist/app.js
のように実行し、下記のような Launch Configuration でインスペクタのポートにアタッチしても良さそうです。
{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "attach", "restart": true, "name": "Attach to Remote", "skipFiles": [ "<node_internals>/**" ], "address": "127.0.0.1", "port": 9229, "localRoot": "${workspaceFolder}", "remoteRoot": "/c/Users/oreore/devel/path/to/project", }, ] }
ただこの場合は node
コマンドを使う必要があるので ts ファイルではなく js ファイルを実行する必要があります。
あるいは次のように -r ts-node/register/transpile-only
を指定すれば node
コマンドを使いつつ ts ファイルが直接実行できます。ただ、この場合はプロジェクトの node_modules
に ts-node
と typescript
が必要です。
node --inspect -r ts-node/register/transpile-only src/app.ts
あるいは NODE_OPTIONS
環境変数で --inspect
オプションを指定しても OK です。この方法なら ts-node
や typescript
はグローバルにあれば十分です。
env NODE_OPTIONS=--inspect ts-node -T src/app.ts
さいごに
シンボリックリンクを含むパスの中で作業するという変なことをやっていなければハマることもなくもっと簡単だったのかも。。。