-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
The export name "__esModule" is reserved and cannot be used #1591
Comments
On the JSPM side, the issue here is that JSPM will convert CJS into ESM, and in doing so follow the Node.js semantics for what exports to expose. Per the Node.js ESM CJS wrapper semantics, |
Ah, I think I understand now. So e.g. react-calendly's dist/index.js does But esbuild complains because if it now were to take that ESM with the__esModule export, and convert it to CJS, the export will clash with the __esModule magic marker which is added per esnext/es6-module-transpiler#85. 'Cause esbuild can't know that the __esModule export already is the magic marker from the original CJS module. (It's like a game of telephone, CJS => ESM => CJS 😄) But in my case, I'm esbuilding with format=esm, so it doesn't need to convert anything to CJS, so maybe it doesn't need to complain about the reserved export? |
It seems a bug in jspm.dev, it chooses the cjs version over the esm one, and wrongly exports |
This all sounds correct to me.
You can still get into a situation where this is needed because esbuild supports requiring ESM (which is not something that node supports). For example, consider your example file // MRE.js
const exports = {}
Object.defineProperty(exports, "__esModule", { value:true })
export default exports
const __esModule = exports.__esModule
export { __esModule } If I import that with
This is why the Trying to only do this check in the conditions when it actually matters is pretty complicated since it happens in a completely different part of the compile pipeline after linking and tree shaking, and by that point it may be pretty non-obvious why it happened so reporting a reasonable error that explains what happened and why isn't straightforward. And I don't want to have a very obscure error appear only sometimes seemingly at random with no explanation. I think if it's not possible to explain exactly why it happened, it should either always appear or never appear so it at least doesn't feel like a bug. I suppose I could just remove the error and allow this code to be bundled but to potentially fail at run-time. But that doesn't feel great either since it still seems like "a very obscure error that appears only sometimes seemingly at random with no explanation." See also: #1338 |
@evanw I was not aware ES build was adding If ES build is adding Instead I would suggest using the spec marker - More generally, this issue is an example of a valid ES module per the ES specification not bundling in esbuild. |
This also seems to come down to a misunderstanding of what |
It makes sense that a |
@sokra thanks for sharing your perspective on this - can you clarify though for a normal ES module case like |
webpack adds |
|
RollupJS as an ESM-first bundler will at least ensure you do not have to consider The concern is that ESM-first code without any CJS is now getting interference from |
This really is a hill I'd die on if I had the power to in this situation -
There are three require cases - Anything else is harming the future ecosystem. |
That's illegal anyway. In Node.js you can't require(esm) and the browser doesn't know about require(). And it will only break if consumed by a transpiled ESM require(), that doesn't sound like a huge restriction. Technically we could place a faux ESM adapter in between.
Technically there is no spec for CJS-ESM-interop, so we would have to define "correct" first. An additional It increases the bundle size by Considering the amount of babel-transpiled CommonJS in npm, I would say it might be more harmful to not provide a Yes, it would probably better if |
@evanw perhaps you could clarify with this error:
what exactly is the bug that is trying to be avoided here? I think building ES modules that export For what it is worth, the CommonJS -> ESM converter that is effectively unsupported here is this: https://github.com/jspm/babel-plugin-transform-cjs-dew where retaining the |
I added (Note the first 4 test cases are normal cases and the others are edge cases)
|
Ah, I see: (I replaced __esModule with _esModule for testing, so that MRE.js bundles successfully)
So in __export , __markAsModule will define the __esModule marker, and then the __esModule export will clash with that in the for loop. Would it be at all feasible to make __export + __markAsModule a bit smarter => if there's already a correct __esModule marker in I guess doing that "smart" check at compile time would be harder or impossible, because esbuild only parses the script and doesn't evaluate it, so it doesn't actually know what's the value of the __esModule export? |
I just wanted to see if there's any new perspectives to this issue now that it's been dormant for a while? To give some practical context on why we (Framer) care a lot about this: Framer has introduced a feature called "Handshake" which lets users build a visual component which gets turned into React under the hood. They can then import its ESM module via a URL, which is now supported in Webpack 5 (and by extension, Next.js). Now Framer is building two more features:
These two features together (bundling with There must be a way for us to allow the legitimate use cases above while handling most edge cases (i.e. sacrifice handling some edge cases in favor of allowing legitimate use cases). I thought Piotr's PR was a good step in that direction – @evanw is there any reason we can't merge it? |
Does anyone in this thread have ideas for how to work around this issue with an |
I finally started looking into this. One reason why I haven't tackled it yet is that it's a huge interop mess with several entangled issues. I'd like to get them all fixed together so I have a holistic picture of the changes instead of addressing issues individually. I have started putting together a set of test cases for what I think should be fixed in this cluster of issues: https://github.com/evanw/bundler-esm-cjs-tests. I'll also start working on getting esbuild to pass these test cases. I think this will unfortunately bloat the injected shim code even more, but that's likely unavoidable. |
Recently, I've been attempting to bundle modules from jspm.io (via a custom esbuild plugin which implements imports from URLs and import maps), and I've been running into this error a lot:
Here's an example module where I've run into this for the first time: https://jspm.dev/npm:react-calendly@2.2.1!cjs
It all boils down to something like this:
It's that named __esModule export that upsets esbuild -- if I comment it out, it builds fine.
The way I understood it from reading esnext/es6-module-transpiler#85, the magic __esModule export was introduced so that when you transpile an ESM module to CJS, and do
const foo = require("esm-foo-transpiled-to-cjs")
, it'll know that you really meanconst foo = require("esm-foo-transpiled-to-cjs").default
. However, I belive JSPM's doing things the other way, i.e., it transpiles CJS modules to ESM. So I'm not sure if their usage of the __esModule export is correct.We've had a brief conversation about this with @guybedford on the JSPM Discord, but we decided to move it here. I'm curious, what's the story behind this "__esModule is reserved" check/error in esbuild?
The text was updated successfully, but these errors were encountered: