[BUG] npm does not preserve hoisted packages in the root node modules when upgrading
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 10.1k
- Forks
- 4.7k
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 19
Description
Is there an existing issue for this?
- I have searched the existing issues
This issue exists in the latest npm version
- I am using the latest npm
Current Behavior
When I update a package that is depended on by multiple workspaces, npm ends up installing the same version of the new package in each workspace, instead of in the root where it currently lives (even though all workspaces use the same version).
Expected Behavior
I would generally expect a normal npm install in this situation to keep the packages hoisted if compatible.
Is there some other workflow people should follow to upgrade packages (personally I've had very little luck using npm update for monorepos, since all workspaces need to be updated at once).
I have found that running npm dedupe after does fix this particular issue, however setting prefer-dedupe = true in my .npmrc does not. So there is some recourse, though it feels a bit awkward, and depends on people remembering to do it.
NOTE: I've seen many online suggesting avoiding hoisting for monorepos altogether, however that makes more sense for monorepos of completely independant applications. This repo if following the increasingly common pattern of having a monorepo with apps for each platform (web/mobile/desktop) and some shared code. As well as using the import/no-extraneous-dependencies eslint rule to prevent workspaces using packages they don't directly depend on. In these setups, having separate copies of the same library (even if they're the same version) in each workspace leads to all sort of issues. instanceof breaks, mocking in tests breaks, etc.
Steps To Reproduce
- example repo (linked to relevant starting commit): https://github.com/pentible/typescript-app-template/tree/44912fd742abb639fc98463c467b965178d2afbf
- upgrading a package depended on by multiple workspaces (ie. upgrading trpc/react-query)
# NOTE: in practice would propably use `npm-check-updates`, but including a hardcoded example here for reproducibility
sed -i '' \
-e 's/"4.29.23"/"5.25.0"/g' \
-e 's/"5.0.0-alpha.80"/"5.25.0"/g' \
-e 's/"10.34.0"/"11.0.0-next-beta.316"/g' \
package.json {apps,packages}/*/package.json
npm i
- the workspaces now have these upgraded packages in their
node_modules
$ tree -d -L 4 -P 'node_modules/' -I 'src*' -I 'assets' -I 'expo-plugins' apps packages
apps
├── desktop
│ └── node_modules
│ ├── @tanstack
│ │ ├── query-core
│ │ ├── react-query
│ │ └── react-query-next-experimental
│ └── @trpc
│ ├── client
│ ├── react-query
│ └── server
├── mobile
│ └── node_modules
│ ├── @tanstack
│ │ ├── query-core
│ │ └── react-query
│ └── @trpc
│ ├── client
│ ├── react-query
│ └── server
└── web
└── node_modules
├── @tanstack
│ ├── query-core
│ ├── react-query
│ └── react-query-next-experimental
└── @trpc
├── client
├── react-query
└── server
packages
├── api
│ └── node_modules
│ ├── @tanstack
│ │ ├── query-core
│ │ └── react-query
│ └── @trpc
│ ├── client
│ ├── react-query
│ └── server
└── db
41 directories
- and the root no longer has these packages
$ ls -la node_modules/@tanstack
total 0
drwxrwxr-x 2 william staff 64 10 Mar 13:21 .
drwxrwxr-x 843 william staff 26976 10 Mar 13:21 ..
$ ls -la node_modules/@trpc
total 0
drwxrwxr-x 2 william staff 64 10 Mar 13:21 .
drwxrwxr-x 843 william staff 26976 10 Mar 13:21 ..
Environment
- npm: 10.2.3
- Node.js: v18.19.0
- OS Name: macOS Sonoma 14.3
- System Model Name: Macbook Pro
- npm config:
; "user" config from /Users/william/.npmrc
//npm.pkg.github.com/:_authToken = (protected)
fund = false
; save-exact = true ; overridden by project
; save-prefix = "" ; overridden by project
; "project" config from /Users/william/pentible/typescript-app-template/.npmrc
audit = false
save-exact = true
save-prefix = ""
; node bin location = /Users/william/.local/share/mise/installs/node/18.19.0/bin/node
; node version = v18.19.0
; npm local prefix = /Users/william/pentible/typescript-app-template
; npm version = 10.2.3
; cwd = /Users/william/pentible/typescript-app-template
; HOME = /Users/william
; Run `npm config ls -l` to show all defaults.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the workspace upgrade with the linked typescript-app-template commit using npm 10.2.3, then compare the resulting root and workspace node_modules trees. Read the npm install workspace and hoisting behavior before comparing it with npm dedupe and the prefer-dedupe configuration. Done means compatible packages remain hoisted at the root after npm install, with a regression test covering this case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, nodejs
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100