fix: patch ESM resolve.js during asset build to restore ENOENT catch
Node 22.22+ / 24 removed the try/catch around realpathSync in finalizeResolution. realpathSync calls binding.lstat which throws ENOENT for VFS paths (they don't exist on real FS). In Node 24 resolve.js is loaded eagerly during bootstrap before user code runs, so runtime patches to fs.realpathSync arrive too late. Patch the Node source directly during asset builds so the ENOENT guard is compiled into the binary. This silently no-ops on older Node versions where the pattern doesn't match (they already catch ENOENT internally).
This commit is contained in:
@@ -95,6 +95,14 @@ export default async function main(
|
||||
"assert(!CJSLoader.hasLoadedAnyUserCJSModule)",
|
||||
"/*assert(!CJSLoader.hasLoadedAnyUserCJSModule)*/"
|
||||
);
|
||||
// Node 22.22+ / 24 removed the ENOENT catch from finalizeResolution in the
|
||||
// ESM resolver. realpathSync calls binding.lstat which throws ENOENT for VFS
|
||||
// paths (they don't exist on real FS). Restore the catch so VFS imports work.
|
||||
await compiler.replaceInFileAsync(
|
||||
"lib/internal/modules/esm/resolve.js",
|
||||
/const real = realpathSync\(path, \{ encoding: ['"]utf8['"] \}\);/,
|
||||
"let real; try { real = realpathSync(path, { encoding: 'utf8' }); } catch (e) { if (e.code !== 'ENOENT') throw e; real = path; }"
|
||||
);
|
||||
const { contents: nodeccContents } = await compiler.readFileAsync(
|
||||
"src/node.cc"
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user