-
Notifications
You must be signed in to change notification settings - Fork 147
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
Yarn Plug'n'Play: Getting rid of node_modules #101
Conversation
I read the paper. I love the concept, moving the resolver into an exportable the |
Really love this idea! Would this have to be implemented on a package manager level, bundler, or both? |
@davidnagli Mostly package managers. Bundlers could however be able to consume the |
⚰️
|
For reference, I always wanted to symlink packages directly from the store in pnpm (related issue: pnpm/pnpm#1001). We also did a partial implementation (using the Lots of packages already don't work with pnpm because of its strict node_modules. This is one of the reasons pnpm isn't adopted as much as Yarn or npm. I see in the RFC that it is planned to make this hooked resolution algorithm "strict" as well. I think it would be good for pnpm as we don't have the power to make the ecosystem fix itself. Even fixes that we contribute are sometimes not merged and published for years. So this is a very brave design. I wonder how it will be welcomed when all the issues will arise. I wonder whether the design will be adjusted or you will insist to keep the strict resolution (this scenario would be best for pnpm) |
accepted/0000-plug-an-play.md
Outdated
|
||
Since Plug'n'Play flattens the dependency tree while still preserving the links between the nodes, the paths Node will get will be the same for any `package-c@1.0.0` inside the dependency tree, causing the package to be instantiated a single time. | ||
|
||
### A. users cannot require dependencies that aren't listed in their dependencies |
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. => E.
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.
tfw you reorder sections and forget to update the identifiers
accepted/0000-plug-an-play.md
Outdated
|
||
In order to solve this, Plug'n'Play details a special case when a package makes a require call to a package it doesn't own but that the top-level has listed as one of its dependencies. In such a case, the require call will succeed, and the path that will be returned will be the exact same one as the one that would be obtained if the top-level package was making the call. | ||
|
||
### e. edit-in-place workflows need different tools |
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.
e. => E.
/ping @such
Strange that npm has just released a similar concept (as package manager called crux): https://blog.npmjs.org/post/178027064160/next-generation-package-management |
My $0.02 is that any changes to replace the An awful lot of existing code and infrastructure depends on the current behavior of I don't want to have to worry about whether my dependencies are compatible with node_modules, pnp, or crux. If a future version of node allows package managers to supply an alternative implementation of |
How is this going to change yarn checksum behaviors, if at all? I noticed that it wasn't even mentioned. |
@schmod Note that the goal here isn't to sidestep the Node processes. Rather, we want to show a practical implementation that we know is solid enough for a first iteration, and use it to ignite discussions. If you want to compare it to something else, see it as what Boost sometimes is compared to the standard C++ library: it's only after |
I'm always interested in changes like this one. 👏 I guess this would break TypeScripts |
An important note from the
Will this be possible with pnp as well? I poke around in node_modules very often to debug and better understand the libraries I'm using. |
accepted/0000-plug-an-play.md
Outdated
|
||
### C. users working on multiple projects across a system won't pay increasing install costs | ||
|
||
A common occurence in the Javascript world is developers working on multiple disconnected projects sharing similar dependencies (for example all projects created through `create-react-app`). Due to how package managers currently work, the files used by those projects were typically copied from the cache into multiple `node_modules`, multiplying both the total size of the installs on the disk and the time wasted running installs. |
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.
typo: occurence
-> occurrence
accepted/0000-plug-an-play.md
Outdated
|
||
The reason this is a problem is that both of those actions don't have the same meaning and as such interfere with each other. The symlinks used for the virtual packages implementation referenced in Section 3 are a direct consequence of this: while it would be possible to implement this concept by making `require.resolve` create and return special in-memory identifiers that `require` would be able to understand, it wouldn't be possible to use those identifiers as paths (unless we were to patch the `fs` module, which is totally unacceptable). | ||
|
||
A fix would be to split require.resole in two: |
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.
typo: resole
-> resolve
accepted/0000-plug-an-play.md
Outdated
* An exception is made if the package being required is listed in the dependency detail of the top-level. In this case, the package making the request will obtain the exact same **instance** than if the top-level package had made the require call (note the emphasis on instance rather than version). | ||
* We however discourage packages from relying on this exception, since it's only been implemented to lower the adoption cost and help plugin systems. Packages should prefer using `peerDependencies` if applicable. | ||
* Two packages depending on the same reference of the same dependency that itself has a transitive peer dependency **MUST** get the exact same instance of this dependency, whatever their locations in the dependency tree are. | ||
* Two packages depending on the same reference of the same dependency that itself has a transitive peer dependency **MUST** get different instances of this dependency. |
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 rule has the same condition as the previous one, but have different results. Is it a mistook?
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.
Yes, the first one should be:
Two packages depending on the same reference of the same dependency that doesn't have any transitive peer dependencies MUST get the exact same instance of this dependency, whatever their locations in the dependency tree are.
In short, if two packages resolve to lodash 1.0.0
, they are guaranteed to share the exact same instance (because lodash
doesn't have any peer dependency).
If two packages depend on react-dom 1.0.0
, they are guaranteed to each have their own instance (because react-dom
has a peer dependency on react
).
|
Could you please provide a link to that new API? |
Cf loader hooks. This API only applies on imports coming from ESM modules, unfortunately. |
How does this work with modules that wrap native code? So is the idea that no more native modules will be allowed? The example given is node-sass but there are plenty of other modules that require post install logic. |
Noticed the bit about |
Really interesting proposal -- Glad to see that the One issue with relying on Aside from this issue, I'd love to hear the yarn team's thoughts on @azz's questions. I think @schmod's excellent point is answered pretty well by @arcanis's analogy to @zkat I'd really love to hear your thoughts on how this proposal differs from and is analogous to some of the design decisions npm has been making with Thanks && I love the Node community because of awesome developments like this! |
Also on the post-install but less agreeable.
This impacts a whole class of packages which genuinely rely on actually using some other language. For example, I've built a binding for a camera that interacts with linux4video2. While the camera has official bindings for both Node and C++, it doesn't have bindings for wasm. For this project, we genuinely need the low level capabilities, speed, and parallelism that C++ provides, but we can't use wasm because none of the APIs are available for wasm. The solutions proposed in this proposal don't impact this in any way, as far as I can tell, and we'll be able to use pnp across all our projects. However, I'm just a little nervous reading that sentence. |
Very smart and clean concept about the next generation dependency handling with yarn. Great! 👍 |
@rivertam Just to be clear: postinstall scripts will be supported, there is no plan to deprecate them in this RFC. I guess I should have been clearer 😃
@transitive-bullshit I have some research to do on this side - I believe
@azz Yep, totally. For most packages, using
@azz The binaries are "hidden in the cache", but you can access them through
@azz Not entirely sure what you mean, but this "fallback to the top-level" doesn't consider whether things are a dependency or not. If a package makes a require call to something it doesn't own (either through dependencies or peer dependencies, which are resolved at install-time).
@azz They were initially absolute, but I made them relative to the location of the .pnp.js file (which is at the root of the project). It could be relative to an environment variable, even if I'm not sure it's something we really want to encourage. Opinions welcome! |
FWIW, the
This could be repeated for known meta-values of significance (e.g., OS version for EDIT: This would be consistent with the accepted caching RFC Idempotent Install still to be implemented. |
Hey @arcanis, thanks for putting this together. I'd like to try to discuss the impact this might have on the TypeScript community. While I'll be traveling for the next few weeks, maybe we can schedule a call or something in the near future. From my personal view, the high-level goals sound like a great idea. Apart from the use-cases given here, when it comes to powering tools like TypeScript (including editor scenarios for both TypeScript and JavaScript in tools like VS and VS Code), resolution tends to be a pretty costly process that can cause delays. Minimizing that sounds great! However, there are a few issues I'd like to raise. Alternative ResolutionYou may already know, but TypeScript effectively overlays a "mirrored" resolution process to find files it's interested in. Specifically:
So even if TypeScript had some sort of resolution support to plug into Yarn PnP, PnP itself is oblivious to what TypeScript is actually trying to search for. Arbitrary Code ExecutionI think @liftM covered some of this already on #101 (comment), but I think another broadly-applicable motivating scenario would be helpful here. Let's say we were able to resolve this issue, and that language services that power editors were able to Now imagine someone places a BifurcationMuch as these ideas are great, npm's simultaneous effort on tink (formerly crux) means that there are potentially two approaches for us to support which isn't ideal. Ideas & MitigationsI think that @sokra had some good insights over Twitter.
|
The Plug'n'Play API is split in two parts: So in your case, your resolver would just have to use
It's a great point, I didn't consider it before. It's worth noting that this problem already occurs now, though: while not native to the editor, various extensions already transparently execute Javascript files obtained from freshly cloned projects - a classic example being the eslint plugin for vscode. |
The serif font on the paper makes it unreadable |
Someone gets rid of node_modules, the largest folder in your project, your computer, your neighborhood, and the universe, and YET, someone complains about A FUCKING FONT. That's our community ladies and gentleman. If this was written in 7px Comic Sans it would still be a better read than most of the stuff you find online nowadays. |
I appreciate the support, but please let's keep it civil. Everyone is entitled to their opinions, especially on a process that specifically asks for feedbacks - 'voting' with your reactions is the best way to signal whether you agree with them or not 🙂 |
ok i don't know what i did wrong but i still get node_modules :( |
@ChuksFestus It probably doesn't work because Edit: |
@levrik you can't really do |
Hey @ChuksFestus, can you open an issue on the Yarn repo if you still have an issue? 🙂 It's likely caused by a wrong version of Yarn being used, and I prefer to keep this thread focused on the design of the feature, keeping the implementation out of the RFC repository. Thanks! |
And actually, since the feature has already landed in Yarn 1.12 (currently in RC), I'm going to go ahead and merge this PR 🎊 Thanks everyone for the feedback you provided, this is but the beginning and we'll keep working with you to improve Plug'n'Play and make it a rock-solid foundation for your projects 👊 In case you have any question, feel free to open an issue on the Yarn repo or to ping me on Twitter and I'll make sure to come back to you. Cheers! (interestingly, github seems to have merged the commit but somehow forgot to mark the PR as such... So I'll close it manually, but you can find the document merged here) |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Please don't use this thread for support requests, use the yarn repo or stack overflow. Notifications go out to 45+ people who were giving feedback on the RFC and 60+ folks interested in RFCs for yarn. |
This PR is locked to prevent sending notifications to people who are only interested in the high-level design. For any technical issue, please direct your questions to the Yarn repository.
Hi folks!
We propose in this RFC a new alternative and entirely optional way to resolve dependencies installed on the disk, in order to solve issues caused by the incomplete knowledge Node has regarding the dependency tree. We also detail the actual implementation we went with, describing the rational behind the design choice we made.
I'll keep it short here since there's much to discuss in the document itself, but here are some highlights:
This is but a high-level description of some of the benefits unlocked by Plug'n'Play, I encourage you to give a look at the document for more information about the specific design choices - and in case anything is missing, please ask and I'll do my best to explain them more in depth!
I should mention that we've been using in production inside Facebook for about two weeks now, and didn't get issues since then. Now that it passed the trial by fire we felt confident enough that this solution was the right solution, and share it openly so that we can all iterate on it.
Working on this project has been super exciting for me, and I can't wait to see the new possibilities that it will unlock! Especially from a tooling perspective, the benefits of having a unified indirection allowing package managers to dictate the way the dependency are loaded unlocks new incredible patterns and make it easier and safer for tools to integrate with it.
Paging some community members that have been made aware of the project during its development and helped us in various ways, either through actual contributions (kudos to @imsnif for implementing
yarn unplug
!) or by their feedback: