1) We patched JavaScriptCore to load ES Modules synchronously when they don't use top-level await. The main tradeoff here is that requiring an ES Module which uses top-level await is unsupported (Bun throws an exception when you try to do this)
2) To support require() inside ES Modules, we add `import.meta.require` and have a transpiler integration to convert calls to module.require() or require() into import.meta.require(). This either loads the file as an ES Module or as a CommonJS module, depending on what the transpiler says it is
3) We rely on certain heuristics to decide whether a script is an ES Module or a CommonJS module. If they use certain sloppy mode or CommonJS-only features, it becomes CommonJS. If they use ESM features or it's somewhat ambiguous, it becomes an ES Module.
Is there an option to require each file to use either CJS or ESM features, but not both? If not, may I suggest adding that option?
Mixed require and import (the latter in both its static and dynamic variants) is already possible with Webpack and Vite.
I hate it and would complain about any code introducing this in any kind of review.
It's great for integration, full stop.
This is an inconvenience where tradeoffs really show and demand to study the behavioral/semantic differences.
Funnily enough, I still find Bun interesting.
Regarding import.meta., I already love Vite's dynamic import transpilation features. They aim to work almost transparently and often do (I am not even talking about the glob feature here).
That being said, I'm unsure if Bun's way of bridging the module ecosystem gap using import.meta will be as useful.
If you ask me, frontend code should ban Node/CJS/require entirely or transpile it into static or dynamic ESM imports; respectively.
Any case where this is not possible unambiguously is a case for human intervention and code rewrite/conversion.
>Any case where this is not possible unambiguously is a case for human intervention and code rewrite/conversion.
Good god, yes
All three patches mentioned will lead to modules that work only in bun and not work in node/deno/browsers, further fragmentating the ecosystem.
https://twitter.com/threepointone/status/1698271991927648643
I imagine that's quite rare, because such a package would only be imported or required for its side effects; and because that package cannot import or require any others, could you safely just assume that if it was `require()`ed use CJS, and if it was `import`ed, use ESM?
The risk for Bun's adoption is that they're wrong, of course.
The risk for Node's usage is that they're right, and library authors begin urging users to use Bun because it's 100x easier than making a useful library with Node. (This will happen very slowly, but things that happen very slowly can start happening all at once very quickly.)
Such as? If you could provide 5-10 of your many examples and why you think that Bun's approach doesn't solve them it would be very helpful.
Possibly the most devious nuance is whether the spec's appendix B applies, which affects whether html comment syntax is valid (yes, this is a thing). The html comment token can therefore be parsed either as a comment or as a series of operators depending on the grammar being used.
Effectively, this means it's possible to craft a program that does different things in CJS vs ESM mode.
If I want, I can literally run a TS file directly with mixed import/require (not that you would ever) directly, without a package.json, tsconfig, dependencies, etc.
In my experience, it's basically Node, minus all the setup/config/build headaches.