npm / cli

the package manager for JavaScript
https://docs.npmjs.com/cli/
Other
8.34k stars 3.07k forks source link

[BUG] npm does not preserve hoisted packages in the root node modules when upgrading #7277

Open ciiqr opened 6 months ago

ciiqr commented 6 months ago

Is there an existing issue for this?

This issue exists in the latest npm version

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 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

  1. example repo (linked to relevant starting commit): https://github.com/pentible/typescript-app-template/tree/44912fd742abb639fc98463c467b965178d2afbf
  2. 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

3. 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

5. 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:
```ini
; "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.
ciiqr commented 6 months ago

including package.json diff for clarity on the versions changed:

diff --git a/apps/desktop/package.json b/apps/desktop/package.json
index e7ecd62..3e5ac47 100644
--- a/apps/desktop/package.json
+++ b/apps/desktop/package.json
@@ -11,11 +11,11 @@
     },
     "dependencies": {
         "@t3-oss/env-nextjs": "0.9.1",
-        "@tanstack/react-query": "4.29.23",
-        "@tanstack/react-query-next-experimental": "5.0.0-alpha.80",
-        "@trpc/client": "10.34.0",
-        "@trpc/react-query": "10.34.0",
-        "@trpc/server": "10.34.0",
+        "@tanstack/react-query": "5.25.0",
+        "@tanstack/react-query-next-experimental": "5.25.0",
+        "@trpc/client": "11.0.0-next-beta.316",
+        "@trpc/react-query": "11.0.0-next-beta.316",
+        "@trpc/server": "11.0.0-next-beta.316",
         "api": "file:../../packages/api",
         "db": "file:../../packages/db",
         "next": "13.4.7",
diff --git a/apps/mobile/package.json b/apps/mobile/package.json
index ee891f0..bb604a5 100644
--- a/apps/mobile/package.json
+++ b/apps/mobile/package.json
@@ -14,9 +14,9 @@
         "@expo/metro-config": "0.10.7",
         "@expo/vector-icons": "^13.0.0",
         "@react-navigation/native": "^6.1.7",
-        "@tanstack/react-query": "4.29.23",
-        "@trpc/client": "10.34.0",
-        "@trpc/react-query": "10.34.0",
+        "@tanstack/react-query": "5.25.0",
+        "@trpc/client": "11.0.0-next-beta.316",
+        "@trpc/react-query": "11.0.0-next-beta.316",
         "api": "file:../../packages/api",
         "expo": "^49.0.6",
         "expo-constants": "~14.4.2",
diff --git a/apps/web/package.json b/apps/web/package.json
index a26c7db..1c10228 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -11,11 +11,12 @@
     },
     "dependencies": {
         "@t3-oss/env-nextjs": "0.9.1",
-        "@tanstack/react-query": "4.29.23",
-        "@tanstack/react-query-next-experimental": "5.0.0-alpha.80",
-        "@trpc/client": "10.34.0",
-        "@trpc/react-query": "10.34.0",
-        "@trpc/server": "10.34.0",
+        "@tanstack/react-query": "5.25.0",
+        "@tanstack/react-query-devtools": "5.25.0",
+        "@tanstack/react-query-next-experimental": "5.25.0",
+        "@trpc/client": "11.0.0-next-beta.316",
+        "@trpc/react-query": "11.0.0-next-beta.316",
+        "@trpc/server": "11.0.0-next-beta.316",
         "api": "file:../../packages/api",
         "db": "file:../../packages/db",
         "next": "13.4.7",
diff --git a/packages/api/package.json b/packages/api/package.json
index f778887..76db2f7 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -7,9 +7,9 @@
     "types": "./src/index.ts",
     "dependencies": {
         "@paralleldrive/cuid2": "2.2.1",
-        "@trpc/client": "10.34.0",
-        "@trpc/react-query": "10.34.0",
-        "@trpc/server": "10.34.0",
+        "@trpc/client": "11.0.0-next-beta.316",
+        "@trpc/react-query": "11.0.0-next-beta.316",
+        "@trpc/server": "11.0.0-next-beta.316",
         "db": "file:../../packages/db",
         "superjson": "1.13.1",
         "zod": "3.21.4"