Install esbuild and run it with any ESM loader. In this example, I use 'bin' script directly to avoid package manager related things. Loader is empty (which is valid according to specs - just no resolve / load hooks will be added to the chain):
node --loader 'data:text/javascript,//' ./node_modules/esbuild/bin/esbuild
(node:1874) ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
node:internal/errors:484
ErrorCaptureStackTrace(err);
^
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension "" for <some my machine path>/node_modules/esbuild/bin/esbuild
at new NodeError (node:internal/errors:393:5)
at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:75:9)
at defaultGetFormat (node:internal/modules/esm/get_format:114:38)
at defaultLoad (node:internal/modules/esm/load:81:20)
at nextLoad (node:internal/modules/esm/loader:161:28)
at ESMLoader.load (node:internal/modules/esm/loader:594:26)
at ESMLoader.moduleProvider (node:internal/modules/esm/loader:446:22)
at new ModuleJob (node:internal/modules/esm/module_job:64:26)
at #createModuleJob (node:internal/modules/esm/loader:469:17)
at ESMLoader.getModuleJob (node:internal/modules/esm/loader:423:34) {
code: 'ERR_UNKNOWN_FILE_EXTENSION'
}
Node.js v19.2.0
From my understanding, the issue is related to the script extension (== no extension). It's OK for pure commonjs setup, but when we ask node to use loaders flow by --loader flag, node will execute defaultResolve / defaultLoad hooks for every incoming file. Next, defaultResolve can't handle files without extension, and return 'format: undefined' - which leads to fail inside defaultLoad.
'format: commonjs' at resolve stage (in my PoC I just test incoming url with '*/bin/esbuild' inside the hook) solves the issue - as per docs, it will activate some kind of CJS fallback. But it looks like a dirty hack )
So, proposed solution - to add .js (or even .cjs) extension to the 'bin' script (and change package.json too).
My use case (== 'why do you use loader here?') is simple - loader (simple ts transpiler) added for every 'yarn xxx' via NODE_OPTIONS yarn configuration, which is very useful for TS monorepo (no need to compile eslint / jest configs, etc.).
ps checked with node 18 too.
Install esbuild and run it with any ESM loader. In this example, I use 'bin' script directly to avoid package manager related things. Loader is empty (which is valid according to specs - just no resolve / load hooks will be added to the chain):
From my understanding, the issue is related to the script extension (== no extension). It's OK for pure commonjs setup, but when we ask node to use loaders flow by --loader flag, node will execute defaultResolve / defaultLoad hooks for every incoming file. Next, defaultResolve can't handle files without extension, and return 'format: undefined' - which leads to fail inside defaultLoad.
'format: commonjs' at resolve stage (in my PoC I just test incoming url with '*/bin/esbuild' inside the hook) solves the issue - as per docs, it will activate some kind of CJS fallback. But it looks like a dirty hack )
So, proposed solution - to add .js (or even .cjs) extension to the 'bin' script (and change package.json too).
My use case (== 'why do you use loader here?') is simple - loader (simple ts transpiler) added for every 'yarn xxx' via NODE_OPTIONS yarn configuration, which is very useful for TS monorepo (no need to compile eslint / jest configs, etc.).
ps checked with node 18 too.