volta-cli / volta

Volta: JS Toolchains as Code. ⚡
https://volta.sh
Other
10.87k stars 227 forks source link

`npm link` sub-package #1001

Open axelboc opened 3 years ago

axelboc commented 3 years ago

I've been trying to resolve an "invalid hook call" error caused by duplicate versions of React. One of the recommended solutions is to run npm link ../myapp/node_modules/react from inside mylib.

Because Volta doesn't support the relative path syntax for npm link (cf #956), I tried running the two commands separately:

  1. cd path/to/myapp/node_modules/react && npm link
  2. cd path/to/mylib && npm link react

Unfortunately, the first command fails with the following error:

"C:\\Program Files\\Volta\\npm.exe" "link"
Volta v1.0.2

Could not read package.json manifest for myapp

Please ensure the package includes a valid manifest file.

Error cause: The system cannot find the path specified. (os error 3)

It seems that Volta doesn't like that I'm running npm link inside a sub-directory of myapp/ Maybe it thinks I'm trying to link myapp instead of myapp's react dependency? 🤷

charlespierce commented 3 years ago

Hi @axelboc, that's an interesting use-case. I think in this situation you're running into the fact that Volta will ignore package.json files inside of node_modules, since what we care about (generally speaking) is the version that was used by the installer, which comes from the root project. So I suspect that approach isn't going to work generally ☹️ The best solution will likely be for us to get #956 fixed so that it works properly, after which you shouldn't need to worry about those issues.

Separately, we may also be able to adjust our parsing logic to handle npm link within a node_modules directory in the same way that npm does.

tim-phillips commented 2 years ago

As a workaround, I've been using a different npm. I'm on macOS using homebrew and running /opt/homebrew/bin/npm link.

Why does Volta change how npm cli works, does it do more than install it?

charlespierce commented 2 years ago

@tim-phillips There are a number of interrelated reasons that all boil down to: We have to do something otherwise npm link won't work at all. To go into more depth:

Volta's core approach is that the versions (Node, npm, & yarn) should be declarative, so that each project can declare the tools it needs and users can simply switch between them without having to remember to reload the environment (or add anything to slow down their shell experience on every cd). However, npm by default puts global installs and links into a subdirectory of itself. This means that a call to npm link is only valid for one specific npm version.

If two projects had different Node or npm versions, then it wouldn't be possible to link between them, since the outgoing link from one would be tied to its npm version, while the incoming link wouldn't be able to find the directory associated with a completely unrelated npm version. This was the case for a long time with Volta, and led to very confusing and non-obvious errors since Volta's declarative nature made the version switching less explicit (see https://github.com/volta-cli/volta/issues/56 for the start of the discussion).

To work around that, Volta moves all of the global installs (and links) to a separate, shared directory, so that we can properly connect packages even if they aren't using the exact same npm version. This is done by detecting those situations and using the prefix configuration setting to point outside of npm's internal directory. To make all of that work, the interception requires Volta to know more about what package is being linked.

Note: Unlike npm, yarn by default uses a directory outside of itself (~/.config/yarn I believe), so yarn link works across versions already, without any extra shenanigans.

Qocotzxin commented 2 years ago

Is there a workaround to link packages using Volta? My workaround is using Yarn, but would like to keep everything in one tool.

LiveGood commented 1 year ago

@Qocotzxin As a workaround you can just use the file:/ option inside package.json For example a module in package.json could be: "jsonwebtoken": "^8.5.1" You can download jsonwebtoken and make local and link it like this: "jsonwebtoken": "file:/User/user.name/dev/jsonwebtoken" Then delete the remote module and run npm install again rm -rf node_modules/jsonwebtoken && npm install

If the local module is with typescript you will have to to run npm build after every change in order to reflect the changes in the dependant application.

loganmzz commented 1 year ago

Nothing new to fix this ?

Alnipet commented 1 year ago

It still doesn't work

dinfer commented 5 months ago

same problem here, using volta 1.1.1