-
Notifications
You must be signed in to change notification settings - Fork 29.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
modules: Package exports validations and fallbacks #28949
Closed
Closed
Changes from 9 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
fe2648c
module: pkg exports validations and fallbacks
guybedford 3a1d493
feedback, ownproperty checks
guybedford 7597165
node_modules filtering in exports and boundaries
guybedford 6cdcf6c
linting fixes
guybedford 20f06d8
Fixup backslash escaping
guybedford 110fa26
Closing bracket
guybedford 406cb02
fixup double node_modules check
guybedford 9d95b1d
pr feedback - validations on paths
guybedford a7e3e76
improve validation failure errors
guybedford 0274de7
or -> and spec fixup
guybedford 52fb846
ensure target dir mappings remain in target dir
guybedford File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -202,11 +202,12 @@ NODE_MODULES_PATHS(START) | |
5. return DIRS | ||
``` | ||
|
||
If `--experimental-exports` is enabled, | ||
node allows packages loaded via `LOAD_NODE_MODULES` to explicitly declare | ||
which filepaths to expose and how they should be interpreted. | ||
This expands on the control packages already had using the `main` field. | ||
With this feature enabled, the `LOAD_NODE_MODULES` changes as follows: | ||
If `--experimental-exports` is enabled, Node.js allows packages loaded via | ||
`LOAD_NODE_MODULES` to explicitly declare which file paths to expose and how | ||
they should be interpreted. This expands on the control packages already had | ||
using the `main` field. | ||
|
||
With this feature enabled, the `LOAD_NODE_MODULES` changes are: | ||
|
||
```txt | ||
LOAD_NODE_MODULES(X, START) | ||
|
@@ -224,10 +225,10 @@ RESOLVE_BARE_SPECIFIER(DIR, X) | |
b. If "exports" is null or undefined, GOTO 3. | ||
c. Find the longest key in "exports" that the subpath starts with. | ||
d. If no such key can be found, throw "not found". | ||
e. If the key matches the subpath entirely, return DIR/name/${exports[key]}. | ||
f. If either the key or exports[key] do not end with a slash (`/`), | ||
throw "not found". | ||
g. Return DIR/name/${exports[key]}${subpath.slice(key.length)}. | ||
e. let RESOLVED_URL = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❤️ |
||
PACKAGE_EXPORTS_TARGET_RESOLVE(pathToFileURL(DIR/name), exports[key], | ||
subpath.slice(key.length)), as defined in the esm resolver. | ||
f. return fileURLToPath(RESOLVED_URL) | ||
3. return DIR/X | ||
``` | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we perhaps warn on them, instead of silently ignoring them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with warnings in Node.js is that when you warn for behaviour of packages in node_modules, there isn't much the user can do. This is in contrast to the browser, where warnings are for developers not users (console = developers), wheras in Node.js the users get the console.
So if we just spit out these warnings and we have a future-compatibility path, then it's just going to be spam, so I'd be against that.
Perhaps we can explicitly make these debug messages though under
NODE_DEBUG=exports
or similar in a follow-on PR.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That’s a fair point, but it’s the same with that event emitter memory leak issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not quite the same as the memory leak warning because we expect that there are invalid entries and ignoring them on older versions is exactly what should be happening on those. I would compare it to warning on unknown
package.json
properties. It would catchmian: lib.js
but it would be much more likely to warn on all kinds of stuff that is perfectly correct.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It’s the same in that it’s not actionable to the top level app, because it originates in an installed package.
The same is true for npm audit warnings.
I think this kind of warning is important for encouraging proper ecosystem behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The latest commit I just added gives the following for invalid export resolutions -
eg -
import 'pkg/x'
will then provide the error:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about for any processing of that package.json? I’d expect a warning when the package is read, not just when that path is imported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could imagine a package that provides one export
pkg/newfeature
for modern Node.js, and anotherpkg/legacyfeature
for legacy Node.js. If we validate all exports on load we get the same issue discussed above with warnings for things that aren't used.As mentioned, I'd be open to a top-level flag for this kind of global validation, but I'd be against making it the default behaviour for the reason that it is simply entirely unactionable to the user - you can't even post a PR to the dependency package itself like other Node.js warnings for node_modules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again, I’m talking about invalid ones, not nonexistent ones.
I think it’s appropriate to always warn when using a package whose package.json has any exports that can’t be used in my node version. The actionable item is “stop using that package” or “upgrade node”.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Along the lines of Jan's comment above, this is like saying that an API exporting:
should warn in legacy environments that the
modern
function exists just because it might call an undefined core library if you runpkg.modern()
.There is nothing wrong with
pkg.modern
function existing if it isn't called in legacy environments. Similarly there should be nothing wrong with defining exports that only apply to modern use cases.As I've mentioned, I'm happy to have a global validation mode as opt-in, but it shouldn't be the default for these reasons.