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

Choosing a marker to customize default exports returned by require(esm) #1622

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

github-actions[bot]
Copy link
Contributor

@github-actions github-actions bot commented Sep 20, 2024

When a user have an existing CommonJS package like this:

// 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:

// 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:

export default function foo () { };
export const __cjsUnwrapDefault = true;

or

export default function foo () { };
export { foo as "module.exports" };

Further to this vote, there is a follow-on proposal 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:

  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.

Vote instructions:

To close the vote, at least 3 secret holder(s)1 must run the following command: git node vote https://github.com/nodejs/TSC/pull/1622 --decrypt-key-part --post-comment

/cc @nodejs/tsc

Current estimated participation: 15.79%

Footnotes

  1. secret holders are folks who have access to the private key associated with a public key on hkps://keys.openpgp.org that references an email address listed on the TSC voting member list at the time of the opening of the vote.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants