-
Notifications
You must be signed in to change notification settings - Fork 30k
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
Providing a custom representation for an ES module under require(esm) #54085
Comments
Thanks for opening the issue, I like the idea of having a marker for Currently with what mentioned in the OP export const __cjsDefaultMarker = true;
export default 'cjs module'; It gets transpiled to something like this: module.exports.default = 'cjs module';
module.exports.__esModule = true;
module.exports.__cjsDefaultMarker = 'cjs module'; And imported by real ESM import d from 'deps'; // d is module.exports, which is { default: 'cjs module', __esModule: true, __cjsDefaultMarker: true } This differs from the user expectation of "importing ESM from (transpiled) ESM" (as end users typically aren't fully aware of the transpilation going on): import d from 'deps'; // Users expect d to behave as if being imported from authored ESM, so d should be 'cjs module'. This was a oversight that has been bothering users ESM-to-CJS transpiled library users (e.g. see evanw/esbuild#1719 or search for This also addresses the question in #53848 (comment) when it comes to importing |
I don't think this is a thing we should advertise, upgrading from CJS to ESM have other breaking implications e.g. making the returned result immutable i.e. not mockable. I previously already received questions about why the result of |
What is the problem this feature will solve?
With the newly supported
require(esm)
we have the ability to require ES modules into CommonJS contexts.One thing that might be useful is that since
require()
can return any JS type, whilerequire(esm)
will only ever return an ES module namespace, is to support customizations of the return value ofrequire(esm)
such that custom types can also be supported to retain the full expressivity of CommonJS modules in this interop.Solving this problem can even allow CJS modules to upgrade to ESM as a non-breaking change, since any CJS module can then be represented by an ESM module under under such a rule.
Furthermore, such a pattern can also form the start of a new primitive for transpiling CJS into ESM, which may be the future of transpilers over an npm ecosystem increasingly migrating to ES modules.
When transpiling CJS into ESM it is critical that any CJS module can be properly represented in ESM when required by a real CJS module, which this would solve.
What is the feature you are proposing to solve the problem?
The feature is for an indication on the ES module itself to indicate to the CommonJS ESM import layer that the ES module has a custom representation to CommonJS.
For example:
Where
require(esm)
of the above ES module would return the direct string'cjs module'
.Further, I would like to suggest that we make this marker the same marker that is used to mark ESM CJS wrappers when importing CJS into ESM, per #53848. The reason being that we then can ensure transitive interop.
That is, this marker supports both being created and being consumed in interop workflows. This is a requirement if this marker is to behave in a well-defined way in a CJS to ESM transpilation workflow as it is a requirement of interop patterns in that they can arbitrarily compose and "collapse" as they transitively lift and lower through the module system interpretations in various tooling workflows. A CJS module imported in ESM passed back into the CJS module system can then automatically be wrapped and unwrapped as required.
What alternatives have you considered?
No response
The text was updated successfully, but these errors were encountered: