diff --git a/votes/initiateNewVote/_EDIT_ME.yml b/votes/initiateNewVote/_EDIT_ME.yml index c9fac556..184cd8de 100644 --- a/votes/initiateNewVote/_EDIT_ME.yml +++ b/votes/initiateNewVote/_EDIT_ME.yml @@ -3,7 +3,7 @@ # 1. Select a subject for the vote. This can be a question addressed to the TSC # voting members. -subject: REPLACEME +subject: Choosing a marker to customize default exports returned by `require(esm)` # 2. You can leave the header instructions as is, or modify them if you see fit. headerInstructions: | @@ -24,8 +24,8 @@ headerInstructions: | # voters express their preference for each candidates, no matter how many # there are. candidates: - - TODO - - TODO + - '`export { foo as "module.exports" };`' + - '`export const __cjsUnwrapDefault = true;`' # 4. Pass the following to false if it's important to keep the candidates in the # order you define above. Presenting candidates in a fixed order tends to @@ -35,10 +35,64 @@ canShuffleCandidates: true # 5. Insert here a short description of the vote objectives and link to the # issue it was discussed on to give the full context. footerInstructions: | - TBD + This is a follow-up to the naming bikeshed in https://github.com/nodejs/loaders/issues/221 + which is for the implementation in https://github.com/nodejs/node/pull/54563 + and the follow-on issue in https://github.com/nodejs/node/pull/53848 + A short summary can be found in https://github.com/nodejs/node/pull/54563#pullrequestreview-2288424604 # 6. Optionally, insert a brief introduction for the vote PR, in the markdown format. prBody: | + When a user have an existing CommonJS package like this: + + ```js + // foo package: + module.exports = function foo () { }; + + // ESM users get... + import foo from 'foo'; + // CommmonJS users get.. + const foo = require('foo'); + ``` + + Now that `require(esm)` is possible and they can ship ESM to their CommonJS users without breaking them, they would try something like this: + + ```js + // foo package + export default function foo () { }; + + // ESM users get... + import foo from 'foo'; + // CommmonJS users get.. + const foo = require('foo').default; // <--- This is now different! + ``` + + As you can see, for CommonJS consumers this will not be exactly equivalent. Since in ESM the default exports is a property of the name space, they need to access `.default` from the result returned by + `require(esm)`. So the idea is that Node.js can take a marker from package authors to directly customize what `require(esm)` returns in this case. + To keep `const foo = require('foo')` working, the two proposed markers are: + + ```js + export default function foo () { }; + export const __cjsUnwrapDefault = true; + ``` + + or + + ```js + export default function foo () { }; + export { foo as "module.exports" }; + ``` + + Further to this vote, there is [a follow-on proposal](https://github.com/nodejs/node/pull/53848) to reuse this marker on namespaces representing CJS modules imported into ESM, where attaching this marker would effectively define a scheme for converting CJS into ESM that would retain full transitive interop semantics allowing arbitrary CJS to be converted into ESM as a non-breaking change. + + Under this follow-on marking, when importing some CJS module `bar` into ESM: + + ```js + module.exports = 'bar'; + ``` + + Users importing with `console.log(await import('bar'))` would obtain a namespace object either of the form `ModuleNamespace { __cjsUnwrapDefault: true, default: 'bar' }` or `ModuleNamespace { default: 'bar', 'module.exports': 'bar' }` depending on which option is chosen for this first PR. + + The vote should stay open for 7 days, or until all TSC voting members have cast a ballot. # 7. Optionally, choose an id that will be used for the branch name as well as # the vote folder name. If not supplied, a UUID will be used.