JavaScript, TypeScript, Next.jsのデバッグ方法
モチベーション
今までJavaScriptやTypeScriptでコードを書いていてデバッグしたくなったとき,デバッグの仕組みがあることを知りながらも,すぐconsole.log()
を書いたりして非効率なデバッグをやってしまっていました(反省).
そこで,自分がよく使う以下の構成について,デバッグの方法を調べてまとめました.
- Node.js(JavaScript)
- Node.js(TypeScript)
- ブラウザ実行(JavaScript)
- ブラウザ実行(TypeScript)
- Next.js
環境
- Node.js: 18.13
- TypeScript: 5.1
- Next.js: 13.4
Node.js(JavaScript)
Node.jsはデバッグの仕組みが備わっていて,--inspect
もしくは--inspect-brk
を付けることで,デバッグ用のポートが開きます.
cf. Debugging - Getting Started | Node.js
$ node --inspect index.js
# 最初の行で自動でストップさせたい場合
$ node --inspect-brk index.js
こうして起動した後に,chromeでchrome://inspect
を開き,“Devices”メニューの”Remote Target”からNode.jsのデバッグポートにアクセスしてアタッチします.
cf. Chrome Debugging Protocol Viewer - v8-inspector (node)
Node.js(TypeScript)
TypeScriptの場合は,トランスパイルされたJavaScriptと元のTypeScriptを紐つけるsourcemapを出力すれば,後はJavaScriptと同じです.
$ tsc --sourcemap index.ts
$ ls
index.js index.js.map index.ts
$ node --inspect index.js
# 最初の行でストップしたい場合
$ node --inspect-brk index.js
sourcemapは自動で読み込まれ,TypeScriptのコードでデバッグできます.
ブラウザ実行(JavaScript)
ブラウザで実行されるJavaScriptは,特に何も準備は要らず,ChromeのDevToolsでデバッグ可能です.
ブラウザ実行(TypeScript)
Node.js(TypeScript)の場合と同様に,sourcemapを出力すれば,後はJavaScriptと同じです.
$ tsc --sourcemap public/main.ts
$ ls public
index.html main.js main.js.map main.ts
Next.js
Next.jsはTypeScriptのトランスパイルやwebpackによるバンドル化などが行われる上,SSRを使うとクライアントとサーバそれぞれでコードが動くため,動作は複雑です. しかし,ちゃんとデバッグのサポートがされているので,お作法通りにやれば簡単にデバッグ可能です.
クライアントサイド
npm run dev
で起動すれば,sourcemapが作られデバッグ可能な状態になってくれます.
もし,Chrome DevToolsの”Filesystem”タブではなく”Page”タブでファイルで指定する場合は,“_N_E”の下にファイルがあるので注意が必要です.(ブレークポイントはこの中のファイルに付ける.)
サーバサイド
Node.jsの場合と同様に,NODE_OPTIONS=--inspect
でデバッグ用のポートを起動します.
ただし,Next.jsの公式ドキュメントによると,npm
コマンドで起動して利用したい場合は,package.jsonのscripts
に"debug": "NODE_OPTIONS='--inspect' next dev"
といった行を追加し,npm run debug
などと実行する必要があるようです.
(私の環境では,なぜかpackage.jsonを編集せずにNODE_OPTIONS=--inspect npm run dev
としてもデバッグできましたが.)
cf. Configuring: Debugging | Next.js
また,私の環境ではなぜかnpm run debug
で起動したときに9229-9232のポートで4つもプロセスが起動し,そのうち正しい1つ(たしか3つ目の9231)にアタッチしないとうまくデバッグできませんでした.
公式ドキュメントにはそういったことは書いていないので,私の環境がなにか悪いのかもしれません.
$ npm run debug
> node-debug-learning@0.1.0 debug
> NODE_OPTIONS='--inspect' next dev
Debugger listening on ws://127.0.0.1:9229/9169643c-bda0-4d01-a451-8a5d24ae01cf
For help, see: https://nodejs.org/en/docs/inspector
- info the --inspect option was detected, the Next.js proxy server should be inspected at port 9229.
- ready started server on 0.0.0.0:3000, url: http://localhost:3000
- info the --inspect option was detected, the Next.js routing server should be inspected at port 9230.
Debugger listening on ws://127.0.0.1:9230/4462212f-bdd9-4f98-8332-fc8b1c06b1ff
For help, see: https://nodejs.org/en/docs/inspector
- event compiled client and server successfully in 192 ms (20 modules)
- wait compiling...
- info the --inspect option was detected, the Next.js server for app should be inspected at port 9232.
- info the --inspect option was detected, the Next.js server for pages should be inspected at port 9231.
- event compiled client and server successfully in 118 ms (20 modules)
Debugger listening on ws://127.0.0.1:9232/10dda6c4-3c9e-490f-a79b-601dfe85896a
For help, see: https://nodejs.org/en/docs/inspector
Debugger listening on ws://127.0.0.1:9231/bafcfa3f-35b9-4165-b1de-ea4976cc5461
For help, see: https://nodejs.org/en/docs/inspector
また,今回はPages Routerで試しましたが,Next.js13から導入されたApp Routerの場合は,少しやり方が異なる可能性があります. (Server ComponentとClient Componentを理解して,正しくデバッグする必要があると思います.)