@rollup/[email protected] added support for pkg.exports entrypoints through https://github.com/rollup/plugins/pull/540.
However it seems like the node keyword is currently not respected which causes trouble when bundling for Node.js environments.
The specific pkg.exports definition that doesn't work as expected is https://github.com/uuidjs/uuid/blob/334ef62c330d92f8ca376d09087e8ee9abc5cc12/package.json#L21-L31:
{
"exports": {
".": {
"node": {
"module": "./dist/esm-node/index.js",
"require": "./dist/index.js",
"import": "./wrapper.mjs"
},
"default": "./dist/esm-browser/index.js"
},
"./package.json": "./package.json"
}
}
Since apparently the node keyword is ignored, rollup picks up the default key, which in this case is a browser build.
Node.js supports the node keyword and this is supported in webpack@5 as well
It has been reported as a bug to https://github.com/uuidjs/uuid/issues/544
When browser: false, respect the node keyword, just like Node.js and webpack do.
/cc @guybedford @LarsDenBakker @TrySound @lukastaegert since you were involved in earlier discussions around pkg.exports and uuid as a widely used canary, see https://github.com/rollup/rollup/issues/3514 & https://github.com/webpack/webpack/issues/11014 😉
Edit: Here's the reference where @guybedford proposed the pattern used in uuid's pkg.exports field: https://github.com/uuidjs/uuid/pull/468#discussion_r442999540
Have you seen #693?
In the examples mentioned, I do not see the node condition specified explicitly. If you read the plugin documentation, you will see that the only conditions set by default are ['default', 'module', 'import']. I am not sure whether the absence of browser should automatically imply node, especially since browser is to my knowledge not yet integrated into package.exports resolution anyway (you would still need to specify the browser condition explicitly). That being said, there is definitely room for improvement, at the very least on documentation level but also to make things clearer for the user with less screws to turn.
@shellscape thanks for the pointer. I must have missed that issue when searching before raising this report. After reading through it I'm still unsure if it really solves this issue out of the box.
@lukastaegert I was referring to
a) The node.js documentation at https://nodejs.org/api/packages.html#packages_conditional_exports which states:
Node.js supports the following conditions out of the box:
- "import" - matches when the package is loaded via import or import(), or via any top-level import or resolve operation by the ECMAScript module loader. Applies regardless of the module format of the target file. Always mutually exclusive with "require".
- "require" - matches when the package is loaded via require(). The referenced file should be loadable with require() although the condition matches regardless of the module format of the target file. Expected formats include CommonJS, JSON, and native addons but not ES modules as require() doesn't support them. Always mutually exclusive with "import".
- "node" - matches for any Node.js environment. Can be a CommonJS or ES module file. This condition should always come after "import" or "require".
- "default" - the generic fallback that always matches. Can be a CommonJS or ES module file. This condition should always come last.
b) The Webpack documentation at https://webpack.js.org/guides/package-exports/#target-environment which states:
The following conditions are set depending on the target environment:
Condition | Description | Supported by
-- | -- | --
browser | Code will run in a browser. | webpack
electron | Code will run in electron. | webpack
worker | Code will run in a (Web)Worker. | webpack
worklet | Code will run in a Worklet. |
node | Code will run in Node.js. | webpack, Node.js
deno | Code will run in Deno. |
react-native | Code will run in react-native.
Now when looking at https://rollupjs.org/guide/en/#quick-start the example "For Node.js"
rollup main.js --file bundle.js --format cjs
somewhat suggests that the resulting bundle is supposed to run in Node.js. That's why I made the assumption that when bundling for CJS I would automatically get the Node.js-style package.exports resolution. But maybe I'm misinterpreting things here a bit.
I do agree that browser: false can probably not automatically mean node: true…
So maybe now that package.exports support arrived in the node-resolve plugin it's now also time for a target: option for the node-resolve plugin, similar to what webpack does? Otherwise I see a lot of potential for confusion around this topic.
Definitely, and no matter how we go from here, there should be clear examples in the documentation that show-case the main use-cases (i.e. bundling for Node and bundling for the web).
Most helpful comment
Definitely, and no matter how we go from here, there should be clear examples in the documentation that show-case the main use-cases (i.e. bundling for Node and bundling for the web).