Environment
main. Reproduced on a clean clone.
Description
Running pnpm add -D <anything> at the workspace root re-resolves the root importer's peers from scratch and moves typescript from 6.0.3 to 5.9.3, churning ~320 lockfile lines along the way. The package being added is irrelevant — it is a property of the current dependency graph.
$ pnpm add -D @conventional-commits/parser@0.4.1
$ git diff --stat pnpm-lock.yaml
pnpm-lock.yaml | 321 ++++++++++++++++++++++-----------------------
- version: 6.0.3
+ version: 5.9.3
Cause
Two facts combine:
package.json declares typescript as a non-optional peerDependency (^5.6.3 || ^6.0.0 || ^7.0.0) and does not list it in devDependencies, so pnpm auto-installs the peer and is free to choose within that range.
@nuxt/module-builder@1.0.3, a root devDependency, declares peer typescript: ^5.9.3 — which excludes 6.x. It is the only typescript peer range in the tree that does (pnpm-lock.yaml:1833).
pnpm install alone is stable: pnpm install --lockfile-only with no changes leaves the lockfile byte-identical, and --frozen-lockfile passes. Only pnpm add forces the re-resolve, and the intersection lands on 5.9.3.
Why it matters
It is silent and it is attached to the most ordinary action there is. Anyone adding a dependency gets an unrelated TypeScript downgrade in their diff, and the plausible reactions are all bad: not noticing, noticing and reverting the lockfile by hand, or concluding the package they added is at fault. The last one already happened — PR #449 avoided a devDependency entirely on that basis, until review established the real cause.
Suggested fix
Either:
- pin it in devDependencies — add
"typescript": "^6.0.3" to root devDependencies, so the resolution is stated rather than derived; or
- add an override —
typescript: ^6.0.3 in pnpm-workspace.yaml, alongside the overrides already there for vite and rolldown and for the same reason: a peer range elsewhere pulling the tree somewhere the project does not want.
The second matches the file's existing pattern, and those overrides already carry comments explaining exactly this kind of trap.
Adding the devDependency the manual way — appending to package.json and running pnpm install — produces a clean 33-line pure-addition lockfile diff with typescript untouched, which is what #449 ended up doing. That is a workaround for one PR, not a fix for the next person.
Additional context
Found by an independent review pass over #449.
Environment
main. Reproduced on a clean clone.Description
Running
pnpm add -D <anything>at the workspace root re-resolves the root importer's peers from scratch and movestypescriptfrom 6.0.3 to 5.9.3, churning ~320 lockfile lines along the way. The package being added is irrelevant — it is a property of the current dependency graph.Cause
Two facts combine:
package.jsondeclarestypescriptas a non-optional peerDependency (^5.6.3 || ^6.0.0 || ^7.0.0) and does not list it indevDependencies, so pnpm auto-installs the peer and is free to choose within that range.@nuxt/module-builder@1.0.3, a root devDependency, declares peertypescript: ^5.9.3— which excludes 6.x. It is the only typescript peer range in the tree that does (pnpm-lock.yaml:1833).pnpm installalone is stable:pnpm install --lockfile-onlywith no changes leaves the lockfile byte-identical, and--frozen-lockfilepasses. Onlypnpm addforces the re-resolve, and the intersection lands on 5.9.3.Why it matters
It is silent and it is attached to the most ordinary action there is. Anyone adding a dependency gets an unrelated TypeScript downgrade in their diff, and the plausible reactions are all bad: not noticing, noticing and reverting the lockfile by hand, or concluding the package they added is at fault. The last one already happened — PR #449 avoided a devDependency entirely on that basis, until review established the real cause.
Suggested fix
Either:
"typescript": "^6.0.3"to rootdevDependencies, so the resolution is stated rather than derived; ortypescript: ^6.0.3inpnpm-workspace.yaml, alongside the overrides already there forviteandrolldownand for the same reason: a peer range elsewhere pulling the tree somewhere the project does not want.The second matches the file's existing pattern, and those overrides already carry comments explaining exactly this kind of trap.
Adding the devDependency the manual way — appending to
package.jsonand runningpnpm install— produces a clean 33-line pure-addition lockfile diff withtypescriptuntouched, which is what #449 ended up doing. That is a workaround for one PR, not a fix for the next person.Additional context
Found by an independent review pass over #449.