こんにちは。
Node.js でCLIアプリケーションを作ってます。shebang で node に --experimental-loader フラグを渡したところ、ERR_MODULE_NOT_FOUND というエラーメッセージが表示されました。なぜこのエラーが発生するのかメモ書きです。
なお推測の域を出ません。ご了承ください
経緯
Node.js 19 で --experimental-specifier-resolution フラグ が削除されました。
代わりに --experimental-loader フラグが有用との噂を聞いて試してました。
エラーに遭遇した状況
package.json は次のとおりです。
{ "name": "nycmd", "type": "module", // ESModuleで実装 "bin": { "mycmd": "./bin/mycmd.js" // エントリーポイント }, ... }
bin に mycmd
を定義してます。ターミナルで mycmd
コマンドを実行すると ./bin/mycmd.js
が呼ばれます。
./bin/mycmd.js は次のとおりです。
#!/usr/bin/env node --experimental-loader @esbuild-kit/esm-loader import '../dist/cli'
先頭行は shebang です。node に --experimental-loader フラグを渡してます。
@esbuild-kit/esm-loader は Loader です。ESModule を import するとき、拡張子(.js)を付与してもらいます。3行目の import '../dist/cli'
を import '../dist/cli.js'
へ書き換えてもらう、ということです。
ERR_MODULE_NOT_FOUND というエラー
mycmd
を実行すると、次のようなエラーメッセージが表示されました。
$ mycmd node:internal/errors:490 ErrorCaptureStackTrace(err); ^ Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@esbuild-kit/esm-loader' imported from /xxx/myworkdir/ at new NodeError (node:internal/errors:399:5) at packageResolve (node:internal/modules/esm/resolve:889:9) at moduleResolve (node:internal/modules/esm/resolve:938:20) at defaultResolve (node:internal/modules/esm/resolve:1153:11) at nextResolve (node:internal/modules/esm/loader:163:28) at ESMLoader.resolve (node:internal/modules/esm/loader:838:30) at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18) at ESMLoader.import (node:internal/modules/esm/loader:525:22) at initializeLoader (node:internal/process/esm_loader:75:58) at loadESM (node:internal/process/esm_loader:90:11) { code: 'ERR_MODULE_NOT_FOUND' }
@esbuild-kit/esm-loader を見つけられないようです。
【推測】 なぜ見つけられないのか
見つけられない module は、shebang に書いてあります。
そこで shebang の意味合いを考えます。調べたところ今回の場合、おおよそ次のコマンドを実行するのと同義らしいです。
/usr/bin/env node --experimental-loader <module>
このコマンドでエラーを出さないには module を探し出せねばなりません。例えば full path を書けば module を探し出せそうです。
実際に試してみると上手くいきました。
#!/usr/bin/env node --experimental-loader /xxx/@esbuild-kit/esm-loader/dist/index.js import '../dist/cli'
まとめると、今回のエラーは Node.js のモジュール解決方法に依存しそうです。モジュール解決について詳しく知りたい方は ドキュメント をご覧ください。
あくまで experimental なフラグ
--experimental-specifier-resolution フラグや --experimental-loader フラグは、あくまで experimental なフラグです。私はパッケージングの手間を省くために触っていたのですが、横着せず真面目に向き合ってみようかと思います。