-
Notifications
You must be signed in to change notification settings - Fork 196
Description
When the exports field of a package has top-level conditions leading to subpath conditions, enhanced-resolve does not parse the subpath conditions. Following a discussion with the maintainer, this is expected behaviour as that syntax is not supported by Node.js either.
However, enhanced-resolve parses the exports field without failing, and later on in a Webpack compilation, Webpack fails to resolve subpath imports. Instead, enhanced-resolve should detect this syntax and throw an error message somewhere around buildExportsFieldPathTree
. The reasoning is that it's very hard to understand why subpath imports fail otherwise, because the Webpack and Node.js documentations don't explicitly state that this use of exports is unsupported.
Original ticket
(original title: Exports field trees with top-level conditions are not supported)
From my understanding, enhanced-resolve is supposed to know how to handle the exports
field of package.json
, including exports with conditional names, as there are checks for conditional mappings in the code.
Everything in this ticket relates to the lib/util/entrypoints.js
file.
In the buildExportsFieldPathTree
, we can see that exports that do not start with a dot are rejected. Conditional mappings are checked after the building of the treeRoot
, so this means that exports with top-level conditions are wrongly assumed to be incorrect syntax. This results in treeRoot
containing a single file entry that matches only .
and has the entire exports
field as its content.
package.json:
"exports": {
"import": {
".": "./esm/index.js",
"./*": "./esm/*.js"
},
"require": "./build/bundle.js"
},
Webpack.config.js:
config.resolve.conditionNames = ['import', 'node', 'default']
Obtained treeRoot
:
{
children: null,
folder: null,
wildcards: null,
files: Map(1) { '' => { import: { ".": "./esm/index.js", "./*": "./esm/*.js" }, require: './build/bundle.js' }
}
As a consequence, imports of the form @org/mylib
work, but @org/mylib/foo
fail. Should you need a reproduction example, the one written in the Webpack 5 documentation does not work: https://webpack.js.org/guides/package-exports/#providing-commonjs-and-esm-version-stateful.
I am not sure what the appropriate approach is, hence the lack of patch.
One could perform a conditional mapping match before building treeRoot
, and building the first matching sub-tree, resulting in a treeRoot
like so:
{
children: null,
folder: null,
wildcards: Map(1) { '' => './esm/*.js' },
files: Map(1) { '' => './esm/index.js' }
}
Or one could map conditional trees into trees with a top-level relative path and conditional leaves, resulting in something like:
{
children: null,
folder: null,
wildcards: Map(1) { '' => './esm/*.js' },
files: Map(1) { '' => { import: "./esm/index.js", "require": "./build/bundle.js" } }
}
Or the treeRoot structure itself could be recursive, though I've no idea what impact this would have on the rest of the code.