Repository navigation
repl / eval: CommonJS globals leak into ESM modules #30842
Description
Activity
- addedcliIssues and PRs related to the Node.js command-line interface.Issues and PRs related to the Node.js command-line interface.esmIssues and PRs related to the ECMAScript Modules implementation.Issues and PRs related to the ECMAScript Modules implementation.experimentalIssues and PRs related to experimental features.Issues and PRs related to experimental features.replIssues and PRs related to the REPL subsystem.Issues and PRs related to the REPL subsystem.
on Dec 7, 2019 I think the only way to fix this would be some trickery with virtual
withcontexts (like thecontext_extensionsoption ofCompileFunctionInContext). @hashseed does adding such an option to normal script compilation seem reasonable?Why is this an issue? Imo repl does not have to be spec compliant. Also there is no spec for
require.@hashseed note that according to the OP it happens for
node --evalas well, so it's not just the repl.Imo repl does not have to be spec compliant. Also there is no spec for require.
i mean ideally we want to avoid cjs locals leaking into modules (and other places). if v8 is not willing to accept such a change we can call this "won't fix" (and i won't be that broken up about it) but imo it would be nice to fix.
Reacted by antsmartiannote that according to the OP it happens for node --eval as well, so it's not just the repl.
I think you misread the first paragraph: It sounds like in the
--evalcase, the module logsundefinedas expected. This only happens in the repl.@devsnek Would it be possible to use the
RuntimeAgent.evaluatefor the repl withrequirefrom the console API instead from global? That should prevent it from leaking into the global scope and it wouldn't appear in "normal" code while still working in the repl expressions. That would also move it closer to the way the repl in devtools/debug clients works.@jkrems that's not quite true.
--evalwith--input-type=moduledoes the right thing but the commonjs variables are leaked whennode --evalis used without--input-type=module.Reacted by Jordan Harband, Jan Olaf Martin and ExE BossOh, we set them as globals there, too? That’s definitely weird. Don’t see why we need for —eval.
For
--evaland--printrun without--input-type=modulethey're set here:
https://github.com/nodejs/node/blob/master/lib/internal/process/execution.js#L75-L79Inside
scriptthe commonjs variables are function arguments created byvm.compileFunctionso I assume they're being copied toglobalto become available insidevm.runInThisContext.I wish there was a comment in that file explaining why we're not using the typical function wrapper. Is it "because it would be a breaking change" at this point..? First level of blame doesn't show anything obvious.
Reacted by Corey Farrell@jkrems --print 1 needs to print 1, so wrapping it in a function wouldn't work.
Reacted by Jan Olaf MartinGotcha, thanks for the explanation! But v8-inspector and console API may be a possible path for
--print/--evalI assume?@jkrems inspector doesn't introduce new magic scope. in fact, that would also be an issue with the virtual
withscope, so i guess that won't work either...with repl we can transform the code arbitrarily and no one will really care, so we can fix it with enough effort, but for
--evalwe need to keep everything exact, and i can't think of a way to make it work.inspector doesn't introduce new magic scope.
Ah, the console API is also available for all other code running, not just the evaluated expression? That's too bad. :( The upside is that it gets automatically removed once the initial evaluation stops (doesn't survive to future ticks) but I'm not sure if that's enough for this..? As long as ESM doesn't run in the same tick, it wouldn't see the
requireanymore.Since there is no viable route forward here, and the design decisions in V8 encapsulation and the Node.js REPL have been made, closing this as a "wontfix".
This is still on my list of things to fix if ever possible
github-actions commented
on Jun 27, 2026 on Jun 27, 2026 – with GitHub ActionsContributorMore actionsThis issue has been marked as stale due to 210 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.github-actions commented
on Jul 28, 2026 on Jul 28, 2026 – with GitHub ActionsContributorMore actionsThis issue has been automatically closed after 30 days of inactivity following its stale status (no activity for a total of 120 days).
If this is still relevant, feel free to reopen it or leave a comment with additional details so we can continue the discussion.
Linux lt2.cfware.com 5.3.11-200.fc30.x86_64 #1 SMP Tue Nov 12 19:25:25 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux--evaland--printwithout--input-type=moduleCreate
script.mjs:Running
node ./script.mjsornode --input-type=module --eval "import('./script.mjs')"both produce the correct outputscript.mjs undefined.Now run
import('./script.mjs')in repl, this produces outputscript.mjs function. Same fornode --eval "import('./script.mjs')".Using
--printin place of--evaldoes not changetypeof require.CC @nodejs/modules-active-members