npxコマンドの-p -cオプション指定時のNode.jsスクリプトのデバッグ

# はじめに

npxコマンドで -p -cオプションを使った場合にNode.jsスクリプトのinspectを使ったデバッグ実行ができなかったので、これの回避策を書きたいと思います。

ここでは、アスキーアートを生成するcowsayコマンドを例に使います。

# 通常の実行

npxコマンドにオプションを指定しない場合の通常の実行例です。

```
$ npx cowsay ほげほげ
npx: 10個のパッケージを1.831秒でインストールしました。
 __________
< ほげほげ >
 ----------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
```

npxコマンドに ```-n inspect``` あるいは ```--node-arg=inspect```を渡すと、nodeのインスペクタが起動し、デバッグを行うことができます。

```
$ npx -n inspect cowsay ほげほげ
npx: 10個のパッケージを1.376秒でインストールしました。
< Debugger listening on ws://127.0.0.1:9229/0edce88f-2821-4ecf-bf09-6c0e1caba8ce
< For help, see: https://nodejs.org/en/docs/inspector
< Debugger attached.
Break on start in /Users/mh-mobile/.npm/_npx/29719/lib/node_modules/cowsay/cli.js:2
  1 #!/usr/bin/env node
> 2 var argv = require("optimist")
  3 .usage("Usage: $0 [-e eye_string] [-f cowfile] [-h] [-l] [-n] [-T tongue_string] [-W column] [-bdgpstwy] text\n\n" +
  4 	"If any command-line arguments are left over after all switches have been processed, they become the cow's message.\n\n" +
debug>
```

# -p -cオプションを指定した実行

次は、-p -cオプションを指定して実行した例です。
通常の実行同様にcowsayコマンドが動作します。

```
$ npx -p cowsay -c "cowsay ふがふが"
npx: 10個のパッケージを1.448秒でインストールしました。
 __________
< ふがふが >
 ----------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
```

ここで、通常の実行同様に、```-n inspect```を指定すると、```ERROR: --node-arg/-n can only be used on packages with node scripts.```のエラーが表示され、nodeのインスペクタを使用できません。

```
$ npx -n inspect -p cowsay -c "cowsay ふがふが"
npx: 10個のパッケージを1.244秒でインストールしました。
ERROR: --node-arg/-n can only be used on packages with node scripts.
```

# 回避策

nodeコマンドにinspectの引数を渡して、cowsayコマンドを実行することができれば、デバッグができそうです。ただし、npxコマンドのcオプションに```node inspect cowsay```と指定してもインスペクタが動作しません。これは、cowsayコマンドのパスをカレントディレクトリから探していることが原因のようです。

```
$ npx -p cowsay -c "node inspect cowsay ふがふが"
npx: 10個のパッケージを1.626秒でインストールしました。
< Debugger listening on ws://127.0.0.1:9229/0d44c33e-5152-48fa-823f-d7b9ec8739ee
< For help, see: https://nodejs.org/en/docs/inspector
< Debugger attached.
< Waiting for the debugger to disconnect...
```

```
$ npx -p cowsay -c "node cowsay ふがふが"
npx: 10個のパッケージを1.236秒でインストールしました。
internal/modules/cjs/loader.js:960
  throw err;
  ^

Error: Cannot find module '/Users/mh-mobile/work/node.js/cowsay'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:957:15)
    at Function.Module._load (internal/modules/cjs/loader.js:840:27)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)
    at internal/main/run_main_module.js:18:47 {
  code: 'MODULE_NOT_FOUND',
  requireStack: []
}
```

試行錯誤の上、whichコマンドを使うと、cowsayコマンドの実行パスを取得できることが分かりました。この実行パスを```node inspect```に渡せば、インスペクタを実行できそうです。

```
$ npx -p cowsay -c "which cowsay"
npx: 10個のパッケージを1.266秒でインストールしました。
/Users/mh-mobile/.npm/_npx/29834/bin/cowsay
```

nodeコマンドにcowsayコマンドの実行パスを渡すために、xargsコマンドを使用します。xargsコマンドの-Iオプションを指定することで、実行パスをnodeコマンドの直後に渡すことができます。

これで、通常の実行同様にcowsayコマンドが動作します。

```
$ npx -p cowsay -c "which cowsay | xargs -I{} env node {} ふがふが"
npx: 10個のパッケージを1.64秒でインストールしました。
 __________
< ふがふが >
 ----------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
```

次に、nodeコマンドにinspectを渡して、実行します。

```
$ npx -p cowsay -c "which cowsay | xargs -I{} env node inspect {} ふがふが"
npx: 10個のパッケージを1.497秒でインストールしました。
< Debugger listening on ws://127.0.0.1:9229/4461f637-f92d-4b4a-9458-f65c9ff53e83
< For help, see: https://nodejs.org/en/docs/inspector
< Debugger attached.
Break on start in /Users/mh-mobile/.npm/_npx/29918/lib/node_modules/cowsay/cli.js:2
  1 #!/usr/bin/env node
> 2 var argv = require("optimist")
  3 .usage("Usage: $0 [-e eye_string] [-f cowfile] [-h] [-l] [-n] [-T tongue_string] [-W column] [-bdgpstwy] text\n\n" +
  4 	"If any command-line arguments are left over after all switches have been processed, they become the cow's message.\n\n" +
debug>
```

これで、コンソールでデバッグ停止するようになりましたが、私の環境ではステップ実行などの操作がコンソール上で動作しませんでした（笑）。

ただし、Chromeのインスペクタをchrome://inspectで起動することでデバッグ実行ができるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110575/ec9f4f0b-e4a5-836d-56b1-f73e804497d9.png)