Skip to content
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

[Feature] Resolve Real (Portable) Path for Workspace Dependencies #1052

Closed
1 of 2 tasks
warrenfalk opened this issue Mar 10, 2020 · 3 comments
Closed
1 of 2 tasks

[Feature] Resolve Real (Portable) Path for Workspace Dependencies #1052

warrenfalk opened this issue Mar 10, 2020 · 3 comments
Labels
enhancement New feature or request

Comments

@warrenfalk
Copy link

  • I'd be willing to implement this feature
  • This feature can already be implemented through a plugin

Describe the user story

For workspace dependencies, I want PnP to resolve the real, portable path to that dependency so that I can share that path with external tools.

Example 1: I want my IDE to know that import "project/file" refers to the same file that it is already aware of at /code/project/file because it is a workspace dependency. So that if I ask my IDE to take me to the file pointed to by that import, I want it to open the file it already knows about.

Example 2: I want to be able to tell a non-node script about a file in a workspace dependency.

Example 3: TypeScript package references require one tsconfig.json to reference another by its path, thus disambiguating which tsconfig.json file corresponds to which inputs and outputs. But this can only work by comparing the tsconfig.json reference paths to the dependency paths.

Describe the solution you'd like

I want resolveToUnqualified() to return the real path for a dependency if that dependency is indeed backed by a real path.

Note: Yarn has resolveVirtual() which for workspace paths returns a path which works inside and outside of a PnP context, but which for non-workspace paths returns a path which works neither inside nor outside. So to use it you have to know if the dependency is a workspace or not.

Note: realpath() is another candidate. If pnp's fake realpath() were (in addition to resolving symlinks) to resolve the real path of virtual paths backed by real paths, but for others resolve only symlinks, then this would also suffice.

Describe the drawbacks of your solution

None that I’m aware of. I can’t think of any scenario where the virtual path is more useful than the real path that backs it. Simply always returning the real path would seem to only improve compatibility by default.

Describe alternatives you've considered

It seems possible to use the other pnpapi functions to inspect the dependency and try to determine if a dependency is a workspace so that it can resolveVirtual() only in these cases. But it wasn't clear how to do this reliably and this seems fragile.

Additional context

I’m running into this currently while trying to implement TypeScript package references in the fuse-box bundler. When resolving dependencies I need to know the real path so this can later be matched against the tsconfig.json references. But if I call resolveVirtual() on all dependencies then only the workspace dependencies are readable, but if I call it on none, then all are readable, but I can’t match workspace dependencies to real files.

Apologies if this has already been discussed somewhere. I couldn't find it.

@warrenfalk warrenfalk added the enhancement New feature or request label Mar 10, 2020
@warrenfalk warrenfalk changed the title [Feature] [Feature] Resolve Real (Portable) Path for Workspace Dependencies Mar 10, 2020
@warrenfalk
Copy link
Author

Ah, the drawback is that the output to resolveToUnqualified() is expected to be used as the input when recursing dependencies. So in light of that, this statement is not true:

I can't think of any scenario where the virtual path is more useful than the real path that backs it

Because peer dependency resolution requires retaining enough information about from where the thing was referenced. I.e. you can't find whether the peer dependencies of a workspace package have been installed if all you have is the real path of the workspace package.

So this means that the ideal solution must, in fact, be a function that is called on the output of resolveVirtual. I think we're back to making realpath() do this. This more closely mirrors what realpath() does to workspaces in Yarn 1 also.

@arcanis
Copy link
Member

arcanis commented Mar 10, 2020

Because peer dependency resolution requires retaining enough information about from where the thing was referenced. I.e. you can't find whether the peer dependencies of a workspace package have been installed if all you have is the real path of the workspace package.

Exactly. Virtual paths are necessary to keep structural dependency tree information, and without them TypeScript wouldn't return the right information regarding the file dependencies.

Note: realpath() is another candidate. If pnp's fake realpath() were (in addition to resolving symlinks) to resolve the real path of virtual paths backed by real paths, but for others resolve only symlinks, then this would also suffice.

Virtual paths don't get resolved by realpath precisely because it would otherwise break many applications 🙂 For example, Node itself calls realpath on all resolutions (unless --preserve-symlinks is defined), and as such other resolver tools such as Webpack do it as well. To make peer dependencies work, one would have to disable the symlink resolution on all those third-party tools, which was problematic (hence why we switched to this different model of making virtual paths "true" directories as far as realpath is concerned).

@arcanis
Copy link
Member

arcanis commented Mar 10, 2020

Also note that this feature can already be implemented in userland, so it's not very important for us to do it natively. To answer the specific issue you had:

Note: Yarn has resolveVirtual() which for workspace paths returns a path which works inside and outside of a PnP context, but which for non-workspace paths returns a path which works neither inside nor outside. So to use it you have to know if the dependency is a workspace or not.

You can know if the dependency is a workspace or not by calling findPackageLocator and checking whether the result is part of getDependencyTreeRoots.

You can also check whether the target is an archive or a real path by using an algorithm similar to the one I describe in this comment: #499 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants