deno
00ea8f1f - fix(resolver): don't treat `deno eval` modules as npm package files (#36304)

Commit
14 days ago
fix(resolver): don't treat `deno eval` modules as npm package files (#36304) `deno eval` and `deno run -` fail whenever the cwd is inside `node_modules`: ``` $ cd node_modules/some-pkg && deno eval "console.log(1)" error: Unable to load .../node_modules/some-pkg/$deno$eval.mts Caused by: No such file or directory (os error 2) ``` Both resolve their in-memory source to a synthetic `$deno$eval.mts` / `$deno$stdin.mts` specifier in the cwd, so a cwd under `node_modules` (or the npm cache) classifies it as an npm package file. `CliModuleLoader::prepare_load` then skips graph preparation for it, and the load falls through to the npm module loader, which reads from disk and gets `ENOENT` — the source only ever existed in memory. The practical fallout is that **no `node-gyp` based native package can be installed**, because gyp evaluates `binding.gyp` with `node -p` while cwd'd into the package being built: ``` gyp: Call to 'node -p "process.env.USE_GLOBAL || (process.platform === 'linux' ...)"' returned exit status 1 while in binding.gyp gyp ERR! configure error error: script 'postinstall' in 'node-liblzma@2.2.0' failed with exit code 1 ``` ## Fix - Exclude the synthetic `$deno$` modules from the in-npm-package check, so they get normal graph preparation and load from the in-memory source. - Short-circuit main module resolution for them, so node resolution doesn't existence-check a file that will never be on disk. Without this the *referrer* (still the cwd) drags resolution back down the node path and it fails with `ERR_MODULE_NOT_FOUND` instead. The synthetic specifier deliberately stays in the cwd. Moving it to the closest ancestor outside `node_modules` also fixes the load, but breaks the idiom that `binding.gyp` files depend on — bare requires have to resolve from the package being built: ``` $ deno eval -p "require('node-addon-api').include_dir" error: Cannot find module 'node-addon-api' ``` There is a spec test covering that specifically, so this doesn't regress later. ## Testing New spec test `tests/specs/eval/cwd_in_node_modules` (ESM, `-p`, CJS, nested `node_modules/.deno/...` layout, and the `require`-resolves-from-cwd guard). Verified each case fails without this change. End to end, `deno install --allow-scripts` on a `node-liblzma` + `node-gyp` project now builds the native addon to completion **with no `node` on `PATH`** — Deno drives the whole node-gyp build — and the resulting `node_lzma.node` loads. Checked for regressions by diffing failing-test sets with and without the change across the `npm`, `run`, `node`, `install`, `task`, `workspaces` and `cache` spec suites: identical in every case. ## Note on #36291 This is filed as lifecycle scripts lacking `--allow-sys`, but that premise doesn't hold on `main`. Lifecycle scripts do run with `-A` (`cli/task_runner.rs`), and the `process.execPath` subprocess that `node-gyp-build` spawns is re-translated through the node shim in `ext/node/polyfills/internal/child_process.ts`, which re-adds `-A` — the child does get `sys` access. The reported `NotCapable` error does not reproduce. What does reproduce, from that exact repro case, is the `deno eval` failure above. So this is `Ref` rather than `Closes` — worth confirming with the reporter whether they still see a permission error once this lands.
Author
Parents
Loading