microbundle
microbundle copied to clipboard
Support Node conditional exports
In node 13, there is a new option available: exports
.
As this will be the new standard for defining packages available for node/browsers/etc, it could be nice to use it instead/addition of the module
, unpkg
etc. fields in the current package.json. Webpack also plans to support it in the v5: https://github.com/webpack/webpack/issues/9509
Current API:
{
"source": "src/foo.js", // Your source file (same as 1st arg to microbundle)
"main": "dist/foo.js", // output path for CommonJS/Node
"module": "dist/foo.module.js", // output path for JS Modules
"unpkg": "dist/foo.umd.js", // optional, for unpkg.com
"scripts": {
"build": "microbundle", // uses "source" and "main" as input and output paths by default
"dev": "microbundle watch"
}
}
New API:
{
"source": "src/foo.js", // Your source file (same as 1st arg to microbundle)
"main": "dist/foo.js", // output path for CommonJS/Node
"exports": {
"import": "dist/foo.module.js", // output path for JS Modules
"browser": "dist/foo.umd.js", // optional, for unpkg.com
},
"scripts": {
"build": "microbundle", // uses "source" and "main" as input and output paths by default
"dev": "microbundle watch"
}
}
Hiya @Ayc0 - thanks for opening an issue for this, it's been on my mind a lot. I have an implementation that should be able to be airlifted into Microbundle, hopefully I'll get some time this week or next.
any update on this? I think solving this will also be an alternative solution for https://github.com/developit/microbundle/issues/50, since exports
is a way to specify multiple entries with multiple exported formats.
I think this is now supported:
The example provided is subpath exports, I think the desired functionality would be conditional exports to handle the same conditions main
, module
, ect handle but on a per entry level. To be fair, I haven't tested this format to see if microbundle
properly handles it.
I do not think microbundle
currently (v0.15.0) properly handles this. Here is a replication case, using arcgis-rest-fetch, which specifically uses conditional exports (see the note in the README). Here is demo case:
Replication Case
- Set up a project:
mkdir demo-case
cd demo-case
- Create package.json:
{
"name": "foo",
"type": "module",
"source": "src/foo.js",
"exports": {
"require": "./dist/foo.cjs",
"default": "./dist/foo.modern.js"
},
"main": "./dist/foo.cjs",
"module": "./dist/foo.module.js",
"unpkg": "./dist/foo.umd.js",
"scripts": {
"build": "microbundle --compress=false",
"dev": "microbundle watch"
}
}
(per Installation)
- Install microbundle and arcgis-rest-fetch:
npm i -D microbundle
npm i -D @esri/arcgis-rest-fetch
- Create file
src/foo.js
:
import { getFetch } from "@esri/arcgis-rest-fetch";
export const gf = () => {
return getFetch();
}
-
Run:
npm run build
- Expected: contents of
dist/foo.cjs
should contain thegetFetch()
from the https://github.com/Esri/arcgis-rest-js/blob/main/packages/arcgis-rest-fetch/node-ponyfill.js since it's defined inexports.require
. - Actual: contents of
dist/foo.cjs
contains thegetFetch()
from https://github.com/Esri/arcgis-rest-js/blob/main/packages/arcgis-rest-fetch/browser-ponyfill.js
- Expected: contents of
More Info
Some links to other implementations: https://github.com/parcel-bundler/parcel/issues/4155#issuecomment-756457121
@gavinr I think there's a bit of confusion here between Microbundle consuming "exports"
and outputting bundles that line up with user-defined "exports"
. I believe this issue is for the latter.
Regardless, unless you're inlining the dependency (which you haven't indicated), Microbundle shouldn't alter the behavior there at all.
If you are inlining the dependency, then Microbundle chooses the bundle that fits your current environment (your build process): as you're authoring in ESM (using import
) you inline the "module"
entry from that package's "exports"
, which is correct behavior.
If your users need to consume a package differently based on their current environment (Node vs Browser, for example), then that package should be a dependency, not inlined. That way your users will still consume that package as it intended.
Thank you for the quick reply. I think you’re saying that my replication case is off topic from the original issue here? If so, my apologies and I can move it to a separate issue.
Message ID: @.***>
Yes, it's different to the original topic (we weren't instructing users to use "exports"
in their packages at the time of this issue), though hopefully I've answered your issue in the above comment.
Sorry, circled back and did some late edits.
If you need to consume a package differently based on the current environment of your own build output, that package should be a dependency, not inlined
That seems to be the correct solution. I'll mark my responses as off-topic so others won't be confused in the future. Thanks.