[BUG] npm forces download of peer dependencies even if these are present in NODE_PATH
Is there an existing issue for this?
- [X] I have searched the existing issues
This issue exists in the latest npm version
- [X] I am using the latest npm
Current Behavior
I can observe moduleA in node_modules of moduleB
Expected Behavior
npm must not download a peer dependency if it is resolvable within NODE_PATH or any other method described in https://nodejs.org/api/modules.html#loading-from-the-global-folders
Steps To Reproduce
- Install moduleA globally (
npm i -g moduleA) - Install moduleB, where moduleA is set as a peer dependency locally:
NODE_PATH=<node_modules_root_where_moduleA_installled> npm i moduleB - Check node_modules folder of moduleB
Environment
- npm: 8.16.0
- Node.js: v18.5.0
- OS Name: macOS
- System Model Name: Darwin SL-1204 21.5.0 Darwin Kernel Version 21.5.0: Tue Apr 26 21:08:22 PDT 2022; root:xnu-8020.121.3~4/RELEASE_X86_64 x86_64
- npm config:
; copy and paste output from `npm config ls` here
NODE_PATH is highly discouraged and won't ever work in ESM. npm deals with the node_modules folder, and I wouldn't even expect a peer dep higher up the directory structure to satisfy the requirement.
Thanks for your response @ljharb
What would be then a recommended/acceptable way for moduleB to load/see moduleA without duplicating it into moduleB's node_modules?
npm link them in. Duplication isn't a problem, but an atypical resolution path is.
I would be happy to link the stuff, but unfortunately such trick does not work if moduleB has moduleC dependency, whose postinstall scripts have peer dependencies on moduleA. As far as I can see such scripts are being executed in a temporary folder and cannot detect the link.
This is our original PR reverted where we tried the approach with a link: https://github.com/appium/appium/pull/17297/files
Yes, every peer dep has to all be linked in everywhere, so they're shared.
There's some sort of weirdness where npm link <thing> causes prepare to be run, regardless of how thing was installed. I suppose this is abuse, but:
cd foonpm install thingcd ../barnpm link ../foo/node_modules/thing
prepare script of thing gets run. whoops, no dev deps!
tbf, our use case is cursed
Yes, that's the point of "prepare" - it'd be "prepublishOnly" if it was only for publishing and not for linking/installing from git. Dev deps should be present tho when linking, i'd expect?
@ljharb in this case, they aren't, because the thing I'm trying to dedupe (via npm link) was installed via npm install thing. it was surprising behavior to see that something installed this way would try to run prepare. and yes, it should be prepare, because if you clone the repo and run npm install--with all the dev deps--prepare should run.
I can trivially produce this behavior by doing
cd tmpdirnpm install lodash- <edit lodash's
package.jsonto have script{"prepare": "echo PREPARE"}> mkdir ../tmpdir2 && cd ../tmpdir2npm install ../tmpdir/node_modules/lodash --foreground-scripts
PREPARE will be echo'd
I guess I would not expect that to happen. either my reading comprehension is poor or maybe that should be noted in the lifecycle scripts docs. I would expect a postinstall to run there, but not a prepare
I would expect anything that's installed from a local file path to have all dev deps present - iow, it's meant for installing from a project, not from a node_modules folder.
right, which is what I meant by "abuse" above. 😜
(though, that being said, I don't think this behavior is particularly obvious)
Even though node will look in NODE_PATH to resolve require statements, npm itself doesn't take that into consideration when building up the local package tree. All it knows is the local node_modules folder.
NODE_PATH is supported by node.js for historic reasons, and is not taken into consideration by npm. There are no plans to start supporting it either.