devlog

【Node.js】shebang で node に --experimental-loader フラグを渡すと ERR_MODULE_NOT_FOUND というエラー

2023-05-17

こんにちは。

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-loaderLoader です。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 なフラグです。私はパッケージングの手間を省くために触っていたのですが、横着せず真面目に向き合ってみようかと思います。

Links

  • 作成日
    2023-05-17
  • 更新日
    2023-09-04