`"type": "module"` causes `SyntaxError: Cannot use import statement outside a module` in node >= 20.6.0
adriencaccia opened this issue · 2 comments
Hey,
With node>=20.6.0, using "type": "module"
, running node --loader esbuild-register/loader -r esbuild-register foo.ts
where foo.ts
is
import { bar } from "./bar";
console.log("works");
console.log(bar);
Results in the following error:
/home/runner/work/esbuild-register-node20/esbuild-register-node20/foo.ts:1
import { bar } from "./bar";
^^^^^^
SyntaxError: Cannot use import statement outside a module
at internalCompileFunction (node:internal/vm:73:18)
at loadCJSModule (node:internal/modules/esm/translators:154:23)
at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:233:7)
at ModuleJob.run (node:internal/modules/esm/module_job:217:25)
at async ModuleLoader.import (node:internal/modules/esm/loader:308:24)
at async loadESM (node:internal/process/esm_loader:42:7)
at async handleMainPromise (node:internal/modules/run_main:66:[12](https://github.com/adriencaccia/esbuild-register-node20/actions/runs/6177908642/job/16770040562#step:6:13))
Node.js v[20](https://github.com/adriencaccia/esbuild-register-node20/actions/runs/6177908642/job/16770040562#step:6:21).6.0
I made a minimal reproduction at https://github.com/adriencaccia/esbuild-register-node20.
You can see in this job that it works up to node@20.5.1, but fails for 20.6.0 and 20.6.1.
If you have any idea how to navigate from here, with the changelog of node 20.6.0, I would be happy to help fix the issue!
Hi, after facing with this problem I ended up creating an alternative implementation that seems to work with Node.js >= 20.6.0.
https://github.com/uhyo/nitrogql/tree/v1.3.1/packages/esbuild-register
I don't intend to advise you to migrate to this one, but this may help understanding and fixing the issue in esbuild-register. I should have rather contributed to esbuild-register but it was too tough for me to not break everything while fixing the issue. Sorry 🙏
Anyways, my analysis is that returning source
along with format: 'commonjs'
wasn't supported until Node.js 20.6.0, meaning that it was just ignored. When the load
hook returned format: 'commonjs'
, Node.js invoked the CommonJS loader for that file.
Node.js 20.6.0 added support for returning CommonJS source
, in which case a new, different CJS loader is used. This means that the hooks registered to the old (or "monkey-patchable") loader don't take effect. esbuild-register
unintendedly opted in to the new feature, which is the cause of the problem.
Although I haven't tested one, a possible fix is to just remove source: source
from the load
hook. However, that won't be a long-time fix because the docs says that ”This behavior for nullish source
is temporary — in the future, nullish source
will not be supported.”