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

Discussion: Name of the flag for the “ESM by default” mode #49541

Open
GeoffreyBooth opened this issue Sep 7, 2023 · 42 comments
Open

Discussion: Name of the flag for the “ESM by default” mode #49541

GeoffreyBooth opened this issue Sep 7, 2023 · 42 comments
Labels
cli Issues and PRs related to the Node.js command line interface. esm Issues and PRs related to the ECMAScript Modules implementation. module Issues and PRs related to the module subsystem.

Comments

@GeoffreyBooth
Copy link
Member

GeoffreyBooth commented Sep 7, 2023

Building off of #49432, what should the flag be named for this proposed new mode? Yes, this is the bikeshed thread.

I think we have a few constraints:

  • Whatever we choose needs to begin with --experimental (for now, until it goes stable).
  • It needs to either be a flag that takes a value, like our existing --input-type=module / --input-type=commonjs; or have an obvious opposite, so that if/when this new mode becomes the new Node default there’s some way to opt back into the previous CommonJS-first behavior.
  • If it takes a value, those values should be module and commonjs for consistency with the existing --input-type and the package.json "type" field.
  • We shouldn’t pick --experimental-module because there was a prior flag named --experimental-modules which still exists as a noop, and it would be confusing to users if nothing happens when they try to use the flag but made a typo.

Please vote using emoji:

  • 🚀 --experimental-type=module / --experimental-type=commonjs
  • 🎉 --experimental-default-type=module / --experimental-default-type=commonjs
  • ❤️ --experimental-implicit-type=module / --experimental-implicit-type=commonjs
  • 👀 --experimental-esm-by-default / --no-experimental-esm-by-default
@GeoffreyBooth GeoffreyBooth added module Issues and PRs related to the module subsystem. cli Issues and PRs related to the Node.js command line interface. esm Issues and PRs related to the ECMAScript Modules implementation. labels Sep 7, 2023
@GeoffreyBooth
Copy link
Member Author

I’ll start: --experimental-type=module / --experimental-type=commonjs.

@targos
Copy link
Member

targos commented Sep 11, 2023

--experimental-type (--type when stable) SGTM. It's close to <script type="module">.

@Qard
Copy link
Member

Qard commented Sep 11, 2023

Maybe I missed some context somewhere, but why do we need another flag separate from --input-type? Can we not just aim to switch the default of that one?

@GeoffreyBooth
Copy link
Member Author

Maybe I missed some context somewhere, but why do we need another flag separate from --input-type? Can we not just aim to switch the default of that one?

Because that one only affects --eval, --print and STDIN, and I'm proposing having it affect many more things. It would be a breaking change if we expanded the behaviors of --input-type.

@Qard
Copy link
Member

Qard commented Sep 11, 2023

Not clear why that would be considered a breaking change. If the flag was not supported in anything but those cases previously then this would just be a case of adding additional support, which sounds to me like a minor. 🤔

In any case, it sounds rather unfriendly from a usability perspective to have two different flags that sound like they do the same thing (Because they do! Just in slightly different contexts.) rather than sticking to the one flag we already have that does this. ESM is already confusing enough with all the extra configs and inconsistencies with CJS-derived expectations, we don't need proliferating flags adding to the complications. 😬

@GeoffreyBooth
Copy link
Member Author

GeoffreyBooth commented Sep 11, 2023

Not clear why that would be considered a breaking change.

Well, maybe it wouldn’t be. Currently if you run node --input-type=module test.mjs it throws Error [ERR_INPUT_TYPE_NOT_ALLOWED]: --input-type can only be used with string input via --eval, --print, or STDIN. So it would no longer throw in this case, which maybe isn’t breaking?

Perhaps the better question is whether we would still need --input-type in the new mode. Like say we ship --experimental-type; would there be a reason to ever run node --experimental-type=module --input-type=commonjs ...? I guess maybe if you want an --eval string that’s CommonJS, but also want any files on disk that it may reference to be treated via the ESM-first semantics. Not sure when you would want this, but it’s at least a potential use case.

A simpler way to put it: if --experimental-type=module becomes the new Node-wide default, would there be any reasons to run node --input-type=commonjs rather than node --type=commonjs?

@Qard
Copy link
Member

Qard commented Sep 12, 2023

I think that's a case of "Just because you can doesn't mean you should." Yes, theoretically that may be a case a user may try to do, but is that something we want to actually support? Or should we just have a switch on all cases? Seems to me a lot less confusing to just have a process wide switch of everything from CJS mode to ESM mode.

@GeoffreyBooth
Copy link
Member Author

is that something we want to actually support?

No, unless there’s a plausible, reasonable use case. Which there may very well be! That’s my question, can you think of one?

@Qard
Copy link
Member

Qard commented Sep 12, 2023

I would rather not support it until someone asks for it than try to invent some scenario that a user may never actually do. It's a lot easier to add support for something than it is to remove it. We should be very intentional and feedback-driven by things like that.

@GeoffreyBooth
Copy link
Member Author

GeoffreyBooth commented Sep 12, 2023

Well except that in this case it’s hard to add support for it if we’ve already redefined --input-type.

I think if we want to potentially use --input-type and enlarge the scope of what it covers, the way forward would be to create a temporary new flag --experimental-input-type that has the broader set of behaviors; and when we’re ready to call it stable, we move those behaviors down into --input-type. What do you think?

Alternatively we create --experimental-type and eventually --type, and deprecate (maybe just docs deprecate) --input-type.

@Qard
Copy link
Member

Qard commented Sep 12, 2023

I think it's a bit confusing having a stable and an experimental flag with the same name, other than the experimental prefix. Perhaps a new flag with an additional prefix like --experimental-file-input-type with it documented explicitly as being planned to merge with --input-type when it reaches stable too?

@ljharb
Copy link
Member

ljharb commented Sep 12, 2023

"input" implies stdin, which is why the name was chosen.

why not something like --default-module-type?

@GeoffreyBooth
Copy link
Member Author

Perhaps a new flag with an additional prefix like --experimental-file-input-type with it documented explicitly as being planned to merge with --input-type when it reaches stable too?

I guess? Would it be a semver-major change to expand the responsibilities of --input-type? Because if so, that’s a good reason to choose a new flag name, so that this new flag can get backported once stable. Like we could have --experimental-type, make it stable as --type, and then backport --type back to 18; whereas we can’t backport the changes to --input-type.

@Qard
Copy link
Member

Qard commented Sep 12, 2023

Like I said, I don't feel like expanding support should be considered a major there. It's up to the TSC though. 🤷🏻‍♂️

@GeoffreyBooth
Copy link
Member Author

Like I said, I don’t feel like expanding support should be considered a major there. It’s up to the TSC though. 🤷🏻‍♂️

I asked at today’s TSC meeting and several people thought that expanding the scope of --input-type would likely be a breaking change. I suppose you could do node --input-type=module --eval 'import("./file.js")' and in current Node, with no package.json file nearby then that file.js would be interpreted as CommonJS; but suddenly --input-type gets superpowers and now file.js is interpreted as ESM. This seems like it would be a breaking change.

Personally I want to backport this flag as far back as possible, especially to 20.x, so I’d rather pick a new name than overload --input-type but be prevented to backport. So I guess we can rule out --input-type, but great idea!

@GeoffreyBooth
Copy link
Member Author

@guybedford #49869 (comment):

This seems to be the better naming IMO. Using the term “default” to describe this mode switch I think may be much more clarifying since this doesn’t override existing configurations.

I considered this name, but I’m not sure users will interpret the name “default” the way we do. Especially since we want to change Node’s default module system in the future. The “default” is the value, commonjs or module, and that’s going to change; and it’s weird to say that “the default value of --default-type is now module.”

@guybedford
Copy link
Contributor

the default value of --default-type is now module

Semantically this is entirely correct in it being a default of a default, but you would usually just say the "default type" is now module.

My concern specifically was about users wondering why node --experimental-type=commonjs x.js doesn't work when you have a package.json of "type": "module". Thinking of it as setting the type is definitely wrong and confusing, as it is very much setting a default.

@GeoffreyBooth
Copy link
Member Author

Thinking of it as setting the type is definitely wrong and confusing, as it is very much setting a default.

I don’t think of this as any different than the type field itself. That field only controls the interpretation of ambiguous files—.js—and not the explicit .mjs and .cjs ones.

Likewise, --type controls the interpretation of ambiguous package scopes (no type field, or no package.json, etc.). Just as the type field doesn’t override the interpretation of .mjs files, --type wouldn’t override the interpretation of defined type fields.

@aduh95
Copy link
Contributor

aduh95 commented Sep 26, 2023

Just as the type field doesn’t override the interpretation of .mjs files, --type wouldn’t override the interpretation of defined type fields.

I think this is a bit counter intuitive, as usually CLI flags have the higher priority – ecosystem packages that offer configuration from package.json will often let users overrides the package.json config with a CLI flag.

@guybedford
Copy link
Contributor

I don’t think of this as any different than the type field itself.

I understand the reasoning you're making, but it's still not a strong argument to me. We should evaluate the clarity of the name on its own merits not relatively.

--experimental-default-type remains my preference for clarity.

@GeoffreyBooth
Copy link
Member Author

GeoffreyBooth commented Sep 26, 2023

I think it’s a subjective call and we should see what the majority of people think. Personally I like the brevity of --type once this goes stable.

@GeoffreyBooth
Copy link
Member Author

If we want something that’s more specific that avoids the confusion around “default,” we could use --implicit-type to get across that it’s only affecting ambiguous cases. But also keep in mind that this flag has other effects that aren’t so easily categorized: it bypasses the CommonJS loader and its monkey patches, and it (as currently proposed) interprets the CLI entry point as a URL. It’s more like “change a bunch of things in Node to be ESM-first.” Calling it simply “type” provides less of a clue as to what this flag does, but since it does several things at once that’s maybe more appropriate?

@JakobJingleheimer
Copy link
Contributor

Seems to me expanding the scope of input-type is breaking. But also, as Jordan mentioned, "input" suggests STDIN, so not appropriate. --type seems the best choice as it mirrors many existing conventions.

@aduh95
Copy link
Contributor

aduh95 commented Sep 26, 2023

@JakobJingleheimer the recent discussion is about --type vs --default-type vs --implicit-type for the new flag. I think we've established that --input-type is a separate discussion.

@guybedford
Copy link
Contributor

--implicit-type would also work for me here in being a qualifying name. If we want short flags, we could add a short flag alias for the module value or similar.

@targos
Copy link
Member

targos commented Sep 27, 2023

I like the idea of a short flag. What about -m for --type=module ?

@GeoffreyBooth
Copy link
Member Author

I like the idea of a short flag. What about -m for --type=module ?

I think that's fine, but first we need to decide what the name of the long flag should be. Are you saying you prefer --type to the other options?

@targos
Copy link
Member

targos commented Sep 27, 2023

I don't really have a preference. If there is a short version, it wouldn't matter to me.

@GeoffreyBooth
Copy link
Member Author

I don’t really have a preference. If there is a short version, it wouldn’t matter to me.

Once the module value becomes the default, it won’t make sense to have a short version that means --type=module (or whatever the name becomes); then we would need a short version that means --type=commonjs, and -c is already taken. We could have -t=commonjs but I’m not sure it makes much sense to have a short flag that takes a value.

I also value the shortness, which is why I was leaning toward --type in the first place. If it helps people, in my mind I think of it as meaning “tell Node to operate in type: module mode.” As in, it’s not specific to any particular package scope, it’s a global Node setting.

@guybedford
Copy link
Contributor

To reiterate my concern about the name here - having a flag that does not do what it sounds like it does is a recipe for user confusion. If I see a flag called --experimental-type=module and run node --experimental-type=module x.js where depending on various complex rules I don't understand it may or may not actually execute the module under that type, creates a very bad user experience by setting up the possibility for a confusion leading to a mismatch between expectations and the actual model.

Therefore my request is that we use any name other than --experimental-type or --type. Both --default-type and --implicit-type are fine by me.

Since this is now blocking #49869, and @GeoffreyBooth is unable to change the PR without consensus, I would like to ask those participating here to urgently help in finding consensus on a suitable name.

Those who have already voted for --type (@JakobJingleheimer ?) can you clarify if you would be able to change your opinion?

And if anyone has strong opinions for or against here please do share, since not knowing which alternatives are viable is hindering progress currently.

@GeoffreyBooth
Copy link
Member Author

I added an emoji vote to the top post: #49541 (comment). Please vote so that it’s clear what option(s) you support. I’m happy to go with whatever gets the majority, and I would ask that everyone respect the will of the majority and not block if your preference isn’t chosen.

@joyeecheung
Copy link
Member

Can this be just a boolean? --experimental-esm-by-default/--esm-by-default/--no-esm-by-default? That probably reduces the ambiguity to the minimum.

@aduh95
Copy link
Contributor

aduh95 commented Sep 28, 2023

I would ask that everyone respect the will of the majority and not block if your preference isn’t chosen.

FWIW I would encourage anyone who feels strongly against a proposal to speak their mind, no matter if it's the choice of the majority, and block the PR accordingly if necessary. As long as you provide reasonable arguments against a proposition, the project should not move forward with it until the objection is resolved.

Can this be just a boolean? --experimental-esm-by-default/--esm-by-default/--no-esm-by-default? That probably reduces the ambiguity to the minimum.

If we are serious about flipping the default in the future, we should probably use --no-commonjs-by-default. We might technically need to create such a flag in order to create a short alias, so we'll probably come back to this proposal when we try to create the alias.

@JakobJingleheimer
Copy link
Contributor

@JakobJingleheimer the recent discussion is about --type vs --default-type vs --implicit-type for the new flag. I think we've established that --input-type is a separate discussion.

I got that, thanks ;) I was merely omitting the experimental prefix because it was already established to be in all cases.

default and implicit seem a tad verbose: all the existing machinations assume CLI flags to be the value unless something more specific overrides it. So the extra words seem like noise to me.

If a collaborator really feels like extra verbiage is needed to re-assert established behaviour, sure. For probably a majority of usage, it'll be a set-and-forget in some config file, so no need to lose sleep over it—I think all the proposed options convey what they'd do. If there needs to be a tie-breaker (it looks close), my ranked vote is:

  1. 🚀 --experimental-type=module
  2. 👀 --experimental-esm-by-default
  3. everything else

@GeoffreyBooth
Copy link
Member Author

Now that --default-type has landed, I think it would be good to land a short flag. Besides the UX, it would help in marketing efforts. A few people have mentioned that -m seems like the obvious choice, as a shorthand for --default-type=module.

The inverse would be -c, which is already taken as a shorthand for --check. How about:

  • In 21.0.0 we ship -m as a shorthand for --default-type=module.
  • In 21.0.0 we deprecate -c; the message would say to use --check instead.
  • In 22.0.0 we reassign -c as a shorthand for --default-type=commonjs.

We could also just forgo having a short flag for the “back to CommonJS default” option.

@aduh95
Copy link
Contributor

aduh95 commented Sep 29, 2023

Shipping a short flag for an experimental flag sounds like a mistake, the whole purpose of putting experimental- in the flag is so it discourage users from using it. Adding a short version should not happen until the flag is stable IMO.

@GeoffreyBooth
Copy link
Member Author

Shipping a short flag for an experimental flag sounds like a mistake, the whole purpose of putting experimental- in the flag is so it discourage users from using it. Adding a short version should not happen until the flag is stable IMO.

Well if we think we want short flags in 22, and if we want -c to be one of them, then we should start the deprecation cycle now for -c.

@joyeecheung
Copy link
Member

joyeecheung commented Sep 30, 2023

Can't we just switch to another shorthand instead of deprecating -c for --check unnecessarily? I am pretty sure it's common for tools to just pick a different shorthand flag when there's a conflict of existing flag. We can't just keep shifting flags randomly around, there are always too many words and too few latin letters.

@targos
Copy link
Member

targos commented Sep 30, 2023

We also don't necessarily need to come up with a short flag for commonjs

@ljharb
Copy link
Member

ljharb commented Sep 30, 2023

I’d dispute that; I’ll forever want to keep my default type as it is, commonjs.

@GeoffreyBooth
Copy link
Member Author

Shipping a short flag for an experimental flag sounds like a mistake, the whole purpose of putting experimental- in the flag is so it discourage users from using it.

I don’t think we’re trying to discourage users from using this flag, in fact the opposite. We’re just trying to emphasize to users that it’s subject to changes.

The appeal of -m is that since we ended up with a mouthful of a flag, --experimental-default-type, we could use -m in the announcement as a more concise and memorable way of explaining the new feature. But there’s no point to using -m once the default is flipped. The time when -m is useful is during the lifetime of 21 when this flag exists and the default is still commonjs.

But if we don’t ship -m before the default flips, it would follow that we wouldn’t have a short flag for the commonjs value. It might be confusing or feel like a mistake to have a short flag for one value and not the other. -c seems like the obvious choice for a short flag for commonjs, and I think --check is so rarely used that very few people would notice if we repurposed its short flag; especially if we used all of 21 as a deprecation cycle.

So anyway I think either we deprecate -c and ship -m for module now in 21, and then point -c at commonjs in 22, or ship no short flags. I’m not sure any other plan makes much sense?

@mcollina
Copy link
Member

mcollina commented Oct 1, 2023

I think changing an existing flag is pretty annoying for people. I’d prefer if we do not want to do that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cli Issues and PRs related to the Node.js command line interface. esm Issues and PRs related to the ECMAScript Modules implementation. module Issues and PRs related to the module subsystem.
Projects
None yet
Development

No branches or pull requests

9 participants