Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

esm: add limited support for --print #52105

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

aduh95
Copy link
Contributor

@aduh95 aduh95 commented Mar 15, 2024

The idea is to enable the following use-case:

$ ./node --input-type=module -p 'await fetch("https://nodejs.org/docs/latest/api/index.json").then(r=>r.json())'   
{ type: 'module', source: 'doc/api/index.md' }

Obviously it only work for a tiny portion of modules (only modules that have a single expression that is not import or export), but since there was no support at all before this PR, it's not going to break anyone.

@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/loaders

@nodejs-github-bot nodejs-github-bot added errors Issues and PRs related to JavaScript errors originated in Node.js core. needs-ci PRs that need a full CI run. process Issues and PRs related to the process subsystem. labels Mar 15, 2024
@ghiscoding
Copy link

this seems similar to the updated bun --print as shown in their latest v1.0.31#new-bun-print blog post. The only exception might be that Bun doesn't require the await, it will await even without it when a Promise is detected. Note that I'm not using this Node command, I just thought of adding this note for comparison sake. Cheers

@GeoffreyBooth
Copy link
Member

Does the following work?

node --input-type=module --print "import { version } from 'process'; version"

The CJS equivalent node --print 'const { version } = require("process"); version' does.

@aduh95
Copy link
Contributor Author

aduh95 commented Mar 16, 2024

Does the following work?

node --input-type=module --print "import { version } from 'process'; version"

The CJS equivalent node --print 'const { version } = require("process"); version' does.

No, as said in the description and can be seen in the tests, this PR adds support for single expression modules only. import { version } from 'process'; version didn't work before, and still doesn't work with this PR. The alternative would be

$ node --input-type=module --print 'await import("node:process").then(({ version }) => version)'
22.0.0
$ node --input-type=module --eval "import { version } from 'process'; console.log(version)"
22.0.0
$ node --input-type=module --print 'process.version'
22.0.0
$ node --version
22.0.0

@@ -61,7 +60,7 @@ function getEvalModuleUrl() {
*/
function evalModuleEntryPoint(source, print) {
if (print) {
throw new ERR_EVAL_ESM_CANNOT_PRINT();
source = `console.log((${source}))`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
source = `console.log((${source}))`;
source = `console.log(await (async(() => {${source}})()))`;

will wrapping source with an async iife make multiple expressions and missing await work?

Copy link
Contributor Author

@aduh95 aduh95 Mar 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would force the user to write return, which would be weird (let’s not forget that using return at the top-level of a module is not valid syntax)

Copy link
Member

@GeoffreyBooth GeoffreyBooth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like if --print supports multiple expression CommonJS input, if we can’t get it to work likewise for ESM input we should at least error informatively so that the user knows how to fix their input so that it works.

@aduh95
Copy link
Contributor Author

aduh95 commented Mar 20, 2024

I feel like if --print supports multiple expression CommonJS input, if we can’t get it to work likewise for ESM input we should at least error informatively so that the user knows how to fix their input so that it works.

Do you have something in mind regarding what that would look like?

@GeoffreyBooth
Copy link
Member

GeoffreyBooth commented Apr 4, 2024

Do you have something in mind regarding what that would look like?

Could multiple expressions be turned into one by wrapping them in an IIFE? So like “It looks like you wanted to run multiple lines of code; however, --print for ES module code can only accept a single expression. Wrap your code in an immediately executing function, like (async () => { … })(), to convert your multiple lines into a single expression.”

@aduh95
Copy link
Contributor Author

aduh95 commented Apr 4, 2024

It's unclear how we could detect if the user is trying to run multiple lines without parsing their code – which maybe is what we should actually do. Note that the async IIFE won't help with import/export expressions.

@GeoffreyBooth
Copy link
Member

which maybe is what we should actually do.

I think there’s some precedent for this, like maybe in --eval (?) on error we use Acorn to check for import/export to prompt the user to add --input-type=module.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
errors Issues and PRs related to JavaScript errors originated in Node.js core. needs-ci PRs that need a full CI run. process Issues and PRs related to the process subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants