Open make-github-pseudonymous-again opened 2 years ago
Mayne check my previus question
Thanks @multivoltage. I understand that microbundle
's goal is to produce bundles that are as small as possible. I am interested in small bundles, but I am even more interested in compatibility with the most popular execution environments for ESM: reasonably popular web browsers versions and maintained node versions. I see two approaches to solve this problem:
package.json
conditional exports are then trivial to implement (.module.js
output for module
key, .cjs
for main
and exports.require
, and .modern.js
for exports.default
).--target web
(default) and one with --target node
. But then it is not clear how to map the different keys.I am trying to do 1, but I hit some sort of babel misconfiguration. I have no idea on how to do 2 so that it works reliably. Sure modern node
and webpack
(and also rollup
?) support require
and import
. But the condition node
does not seem to have a way to distinguish between CommonJS and ESM. It looks like for it to work we would need conditions node:require
, node:import
, browser:require
, and browser:import
. Maybe someone knows better?
PS: Do I understand correctly from the webpack
docs that to compose conditionals one can cascade them?
It seems the solution is to give up on custom configurations and let microbundle
decide. microbundle
bears the responsibility of setting the correct configuration to obtain correct builds for contemporary targets. If you want a build compatible with both contemporary Node and Web, use --target web
(the default). If you really want an unmangled build for Node, build twice, once with --target web
, and once with --target node
. Then use the following configuration in package.json
:
...
"type": "module",
"source": "src/foo.js", // your source code
"exports": {
"node": {
"require": "./dist/node/foo.cjs",
"default": "./dist/node/foo.modern.js",
},
"default": "./dist/web/foo.modern.js"
},
"main": "./dist/node/foo.cjs", // where to generate the CommonJS bundle
"module": "./dist/web/foo.js", // where to generate the ESM bundle
...
The reason my example usage crashes is that microbundle
esm
and cjs
formats force the transpilation of generator functions and for ... of
syntax but when combined with the @babel/preset-env
configuration above, somehow only the generator functions are transpiled, but not the for ... of
syntax. Related issues:
Ideally, I think there should be a tool similar to microbundle
but that forces explicit babel
configuration without creating these conflicts. It would not be that much more of a hassle to setup if microbundle
defined their default babel
configuration for the combinations of builds and targets as independent babel
presets. Would microbundle
still add value compared to direct use of rollup
in this case? I think so: handles TypeScript by default, produces tiny code, automatic build/target detection (via main
, module
, and exports
). Arguably these need less custom configuration.
Another solution seems to be to explicitly rely on @babel/plugin-transform-for-of
, for instance:
...
"presets": [
[
"@babel/preset-env",
{
"targets": [
"defaults",
"maintained node versions"
]
}
]
],
"plugins": [
"@babel/plugin-transform-for-of"
]
...
PS: And if you use destructuring, @babel/plugin-transform-destructuring
.
For a while I have been using the following
babel
preset for production bundles:This configuration seems to be incompatible with
microbundle
as it generates errors such asunknown Statement of type "ForOfStatement"
when the source containsfor (... of ...)
statements. Using"presets": ["@babel/preset-env"]
without specifying targets works. However, I am concerned about the compatibility achieved by such "default" builds.What is the proper way to use
microbundle
to build for both the browser and for node? What's the correct babel configuration to use? I am fine with having one build for the browser and another for Node, but how should one definepackage.json
exports in that case?I do realize
microbundle
probably does the correct thing by default, but I am a bit skeptical given the existence of the--target
CLI flag, for which little documentation exists.