developit / microbundle

📦 Zero-configuration bundler for tiny modules.
https://npm.im/microbundle
MIT License
8.04k stars 362 forks source link

exports config renaming modern? #921

Closed freeman-lab closed 2 years ago

freeman-lab commented 2 years ago

Hi! Thanks for the great tool here, we use it for all our package building, e.g. @carbonplan/components, @carbonplan/maps, and more.

I was recently trying to setup a package with multiple entry points via export, which I'll confess is something I haven't done! I was following goober as an example. I found, however, that their setup doesn't seem to work after v0.12. Specifically, this configuration

"exports": {
    ".": {
      "require": "./dist/goober.js",
      "browser": "./dist/goober.modern.js",
      "import": "./dist/goober.esm.js",
      "umd": "./dist/goober.umd.js"
    },
    ...

results in the modern build getting renamed to ./dist/goober.esm.js and thus ./dist/goober.modern.js does not exist. Indeed, if you pull their repo and update microbundle to v0.13 or v0.14 the build fails. I've confirmed a similar behavior in the package I'm trying to setup (happy to share that too, but it seemed more useful to have theirs as a fully worked reproduction).

Is this intended behavior? It looks like maybe it was introduced here? Is there a suggested workaround if trying to achieve the same pattern as above?

Forgive any ignorance, as I'm still learning a lot of the nuances here! If a fix is needed, happy to try and submit a PR.

rschristian commented 2 years ago

This is intentional, yes.

Anything that supports consuming "exports" can handle the modern output. Node has supported it since v12.7, which can consume ES2019. Microbundle's modern output is ES2017. Prior to that linked PR, the modern format was always output as <pkg>.modern.js (assuming you weren't using the "esmodules" field).

Edit: For what it's worth, Goober's setup is invalid in Node w/ native ESM, so I wouldn't use it as a model. The readme in this project has an example that should supported in all environments.

freeman-lab commented 2 years ago

Thanks! Really appreciate the careful explanation, that all makes sense to me.

And I confirmed in my setup (components to be consumed in a next.js app) that what you recommended is working great.

"exports": {
    ".": {
      "require": "./dst/<pkg>.js",
      "default": "./dst/<pkg>.modern.js"
    },
    ...

Thanks again!

rschristian commented 2 years ago

Glad to hear it.

Though you're going to want to make sure you're either using .cjs with "require" or .mjs with "default", depending on your package type; they cannot both be .js (following the Node spec at least, bundlers can do as they please). Assuming you don't have "type": "module" set, that will error out when something tries to consume "default" at the moment, as CJS is the assumed type.

developit commented 2 years ago

Sounds like this was resolved (yay!). Just to sum up:

{
  "name": "@carbonplan/components",
  "main": "./dst/index.js",
  "module": "./dst/index.mjs",
  "exports": {
    "require": "./dst/index.js",
    "default": "./dst/index.modern.mjs"
  }
}