-
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: remove file extension and directory resolving for esm #21729
Conversation
ping @zenparsing I borrowed |
src/module_wrap.cc
Outdated
@@ -632,10 +638,27 @@ Maybe<URL> ResolveDirectory(Environment* env, | |||
|
|||
} // anonymous namespace | |||
|
|||
Maybe<URL> Resolve(Environment* env, | |||
Maybe<URL> ResolveRecurse(Environment* env, |
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.
This was done to make a separate code path for resolving dependencies than local modules. Not 100% happy with the current implementation... but there is definitely a difference in the algorithm now (still need to resolve main for modules).
Open to suggestions on better ways to do this
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.
If this is renamed to ResolveRelativeWithExtensions
, and used only by main lookups, then the ShouldBeTreatedAsRelativeOrAbsolutePath
check can be skipped.
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.
I'm against this while we continue discussions in the Modules WG and am in fact increasingly concerned about how package-name-maps work and the viability and usability of matching them so going to wait on those discussions.
@bmeck totally reasonable. I look forward to discussing it. To be explicit I consider this a WIP, and have added the appropriate labels. |
@MylesBorins to be clear I am fairly -1 to package-name-map parity currently and will probably be needing more than just technical work to not think this is a bad idea. |
@bmeck makes sense to discuss in the WG. |
I am +1 to this. |
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.
A few comments on simplifying the implementation, but otherwise seems good to go for experimental to me.
src/module_wrap.cc
Outdated
@@ -586,9 +592,9 @@ Maybe<URL> ResolveMain(Environment* env, const URL& search) { | |||
return Nothing<URL>(); | |||
} | |||
if (!ShouldBeTreatedAsRelativeOrAbsolutePath(pjson.main)) { | |||
return Resolve(env, "./" + pjson.main, search, IgnoreMain); | |||
return ResolveRecurse(env, "./" + pjson.main, search, IgnoreMain); |
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.
This can probably be simplified to a ResolveRelativeWithExtensions
, that doesn't need to do the absolute checks and assumes its input is a relative URL.
src/module_wrap.cc
Outdated
@@ -599,7 +605,7 @@ Maybe<URL> ResolveModule(Environment* env, | |||
do { | |||
dir = parent; | |||
Maybe<URL> check = | |||
Resolve(env, "./node_modules/" + specifier, dir, CheckMain); | |||
ResolveRecurse(env, "./node_modules/" + specifier, dir, CheckMain); |
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.
For simplicity, this can stay as just Resolve
.
src/module_wrap.cc
Outdated
@@ -632,10 +638,27 @@ Maybe<URL> ResolveDirectory(Environment* env, | |||
|
|||
} // anonymous namespace | |||
|
|||
Maybe<URL> Resolve(Environment* env, | |||
Maybe<URL> ResolveRecurse(Environment* env, |
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.
If this is renamed to ResolveRelativeWithExtensions
, and used only by main lookups, then the ShouldBeTreatedAsRelativeOrAbsolutePath
check can be skipped.
} | ||
return ResolveDirectory(env, resolved, check_pjson_main); | ||
if (ResolvesToFile(resolved)) | ||
return Just(resolved); |
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.
Beautiful :)
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 all @zenparsing
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.
BTW, this C++ code is a pleasure to work with 👍
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.
All the implementation work of @bmeck, with many various refactoring contribs.
@guybedford wanna push a patch to address your comments? I'll be afk the rest of the day and likely not have a tonight time to work on this this week |
@MylesBorins also playing holiday catch-up here, but will add it to the list. |
acf6ff3
to
177910d
Compare
2c75c3f
to
177910d
Compare
I've added the changes here, although the latest commit on this branch with some typo corrections isn't being displayed by GitHub for me for some reason... MylesBorins@be9afef. |
@nodejs/modules @bmeck is this perhaps something we can move forward with if we get all the tests passing? |
I’m +1 in getting this landed. |
this build on top of the limitations of the package name map proposal. It removes file extensions and directory resolution in the resolver. This is only currently limited for local development. When resolving dependencies file extension and directory resolution will still work. Refs: https://github.com/domenic/package-name-maps
be9afef
to
3e16cf5
Compare
We cannot saddle both sides of "node's implementation is experimental and subject to breaking changes" and "node's implementation is experimental and enforces patterns". My fear here is we are making a big change to the implementation with great impact on a variety of topics without discussion of those. I don't even see mention on migration patterns for multi-mode packages here? Where is the discussion about the impacts of landing this. Similar to #21317 I don't think this PR is looking at overall impact but instead is scoping its focus to finely to a specific change that makes us lose sight of what this would do to an overall implementation. I also see an incomplete and what I see as problematic package-name-map spec as a large part of the reasoning here, but as pointed out in the past you can achieve this kind of "searching" in package name maps so that invalidates this line of reasoning entirely. I think this needs to be more well discussed about impact than just saying it is for some level of compatibility with a potential future web spec that contradicts this PR. I do consider this change controversial and do not want to see it being discussed without recognizing the impact that this has. Right now it is being phrased as:
|
By "common core shared by all proposals", I specifically mean that it does not rule out any proposal. Optional extensions can be restored later, but having optional extensions prevents any proposal where they are mandatory. As I stated above and in my interop issue, I think that mandatory extensions would cause a migration failure and I am strongly opposed to them in the final product. It's just that until there is consensus, mandatory extensions are the less-commiting choice (you can't remove optional extensions once they are out). I consider landing this PR would be q step backward, but I understand why it's pushed by some people, and it does not preclude reintroducing optional extensions later on. I have invested time in tools relying on the current behavior, but I am fully aware that the implementation is experimental and the burden is on me to keep up with the changes. Edit: Essentially, my comment above corresponds to your third point:
I am mostly worried because I did not expect the current implementation to change until the discussions were resolved. |
We kind of have to accept both to some degree. Anything that works in the experimental implementation will be a painful break at some level if it does not work in the non-experimental implementation. Eg for this reason it is not possible to remove ".mjs" at this point - it is already cemented into the ecosystem (not that we would of course).
Agreed, let's discuss.
Multi-mode support would still work for consumer-side This change of no longer supporting "importing a folder being equivalent to importing a package" is a very important concern definitely, and the loss of a use case in Node. We could consider a change to this PR to retain the "treat folders as packages" behaviour, while still removing the automat extensions behaviours. @MylesBorins let me know if you could get behind such a change as well. @bmeck do please share any other concerns on this. |
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.
this change breaks the world for people like me who are working on developing the loader. additionally to this we agreed on a moratorium which was in part your own suggestion...
@devsnek can you perhaps share some details on how this affects things for you? |
@guybedford it breaks things because node is barely usable without node-style resolution. even if this is undone at some point in the future I see no reason to kneecap ourselves. |
@devsnek could you give an example of what you would expect that wouldn't work here that you deem as this kind of compatibility loss based on my amended proposal in #21729 (comment)? |
I'd say it is more impactful than a mere single use case. The divergence in behaviors means things like const foo = await resolve('pkg/foo');
import(new URL('./bar', foo)); would fail and need to be rewritten as: // this should be rewritten in a safe way to compose specifier paths
// I'm unclear on how to do this easily right now
const foo = 'pkg/foo';
import(`${foo}/../bar`); but the above actually has a bug in it compared to the original. It imports |
@bmeck my amendment in #21729 (comment) would deal with that case as discussed in that comment, so that |
@guybedford
|
@guybedford when I resolve |
@bmeck I'm referring to:
To try and clarify the approach, we could do a package-boundary check, and then apply extensions only if the parent package boundary is a different package to the resolved package boundary. |
We agreed at the last meeting to work on creating a minimal implementation that could be a core that various implementations could build on. It seems to me that what's in core Node should be that minimal implementation, even if it's not fully usable and doesn't satisfy most use cases. This PR seems to me to be along those lines. I think it's time for the "full" experimental-modules implementation to live in a branch, and what's in core is the minimal base we agreed to build. |
Agreed that there are some issues with this approach causing differences when loading with a full path or reative path to other packages, so dismissing my review. I think we may still be able to make some progress on this using package boundaries as discussed in #21729, and I think the potential perf benefits for Node would be worth continuing to explore this.
re: moratorium It was my understanding that we are indeed blocked on landing such changes without consensus within the team, but I did not believe that the moratorium was in place to block opening PRs as an attempt to explore a problem space. If individuals in the team find these PRs to be problematic I am more than happy to not continue this method of exploring a problem. |
The moratorium shouldn’t extend to PRs. If it does we’ll never make any progress. |
i'm used to prs meaning someone wants to land something. if that wasn't the intention here then i suppose its fine... a label or title change might not go amiss to make sure people understand it. |
@GeoffreyBooth the moratorium was on landing code. PRs are generally used to land code. That said, I think as long as we get full consensus we can land "non-controversial" PRs. I actually think that for things to be non-controversial to myself at least they need to discuss the interwoven impact they have on other parts of the implementation. It would probably be better to do them as a combined PR for example in the case of this and For example if we were to split up the PRs for:
If we land any of those, the others have a problem because they are interwoven in use cases. If we were to remove path searching only, we now encourage everyone to import If we were to remove the ability to import If we were to export some level of We can combine these PRs to make a full story on a minimal kernel of sorts, but it doesn't make sense to land them separately without having that story in place. |
Perhaps we could make these PRs against some other branch? To keep the PRs minimal but assemble the story elsewhere until it's cohesive and could then be merged into core. |
@GeoffreyBooth that seems ok. Would put them all to land on that fork/branch and have the overarching discussions before coming back here I would assume. Getting to consensus would still take time as long as that is ok. |
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.
I don't think this should land without a modules team meeting but I'm +1 on the actual change and explicitness.
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.
Like @benjamingr I think the change embodies the direction we agreed in the previous meeting and we should discuss this in the next meeting before landing.
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.
Looking forward to discussing in a meeting; i find extension and directory resolution a critical feature to have by default, so i don’t think this should ever land.
@ljharb would you mind elaborating on why? |
The entire npm ecosystem, including best practices around specifiers, relies on full resolution. Package name maps are hopefully being added to browsers to make them more like node - it would be a massive step backwards for node to lose this feature. |
Moved to nodejs/ecmascript-modules#2 |
this build on top of the limitations of the package name map proposal.
It removes file extensions and directory resolution in the resolver.
This is only currently limited for local development. When resolving
dependencies file extension and directory resolution will still work.
Refs: https://github.com/domenic/package-name-maps
Alternative to #21572