microbundle
microbundle copied to clipboard
Export maps and node support
Hello there 👋,
I recently switched to microbundle for a bunch of my libs and I love it so far, however, I ran into an issue where the modern bundle (via exports) doesn't seem to run inside node.js.
My (simplified) package.json looks like this:
{
"name": "color2k",
"sideEffects": false,
"exports": "./dist/index.modern.js",
"main": "./dist/index.js",
"unpkg": "./dist/index.umd.js",
"module": "./dist/index.module.js",
"source": "./src/index.ts",
"types": "./dist/index.d.ts",
"scripts": {
"build": "microbundle"
}
}
And after I run microbundle, my dist folder looks like this
index.d.ts
index.js
index.js.map
index.modern.js
index.modern.js.map
index.module.js
index.module.js.map
index.umd.js
index.umd.js.map
And after I publish with this config and run the following code with Node.js, I get the following error:
// my-file.js
const color2k = require('color2k');
// ...
SyntaxError: Unexpected token 'export'
at wrapSafe (internal/modules/cjs/loader.js:979:16)
at Module._compile (internal/modules/cjs/loader.js:1027:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
I suspect this is due to Node.js not knowing what to do with exports. For more context, I'm not using the mjs extension when running this code in node LTS v14.15.3.
Maybe this is more of a question rather than a bug but in general: How do I use exports with microbundle? How can I author a package that is both for Node.js and browsers?
- Do I need to write a conditional exports map?
- Do I need to post-fix the modern bundle with the
.mjsextension? If so how do I do that with microbundle?
Thanks for any support!
For now, I'll just remove the exports field.
For some more things I've tried:
I've tried using a conditional exports map where I pointed the import field to the .modern.js bundle, however, this doesn't seem to work correctly when using Node.js's native es module support (.mjs).
I believe node.js requires the .mjs extension in order to use import and export natively.
For that setup, it's:
{
"exports": {
"require": "./dist/index.js",
"import": "./dist/index.modern.js" // <-- does not work
}
}
However, if I rename the modern file to index.modern.mjs, it works
{
"exports": {
"require": "./dist/index.js",
"import": "./dist/index.modern.mjs" // <-- works ✅
}
}
I'm not really sure what's the right way to handle this but I feel like the docs need to be updated to cover Node.js cases.
Hope this helps, thanks for the great lib!
Hiya @ricokahler! In order to support native ESM in Node, .mjs is required:
{
"name": "color2k",
"sideEffects": false,
// CJS:
"main": "./dist/index.js",
"exports": {
// Node CJS:
"require": "./dist/index.js",
// Node ESM:
"default": "./dist/index.modern.mjs"
},
// Bundler ESM:
"module": "./dist/index.module.js",
// unpkg/cdn UMD:
"unpkg": "./dist/index.umd.js",
// only used by microbundle:
"source": "./src/index.ts",
"types": "./dist/index.d.ts",
"scripts": {
"build": "microbundle"
}
}
Agreed regarding the docs - if the readme examples aren't using .mjs to force Node's ESM behavior they should be fixed to do that for sure.
@developit is there is a way to get microbundle to output a file with the .mjs extension? Right now when I run microbundle with that config, it outputs dist/index.modern.js.
Should index.modern.js be index.modern.mjs by default?
@developit is there is a way to get microbundle to output a file with the
.mjsextension? Right now when I run microbundle with that config, it outputsdist/index.modern.js.Should
index.modern.jsbeindex.modern.mjsby default?
I think this depends on the type of the package "type": "module" as I found out with my problem #801
Microbundle should just use the extension you specify in your package.json. It doesn't right now, which is a bug.