Skip to content

chore(deps): declare TypeScript instead of deriving it - #453

Merged
IgorShevchik merged 1 commit into
mainfrom
fix/typescript-override
Aug 20, 2026
Merged

chore(deps): declare TypeScript instead of deriving it#453
IgorShevchik merged 1 commit into
mainfrom
fix/typescript-override

Conversation

@IgorShevchik

@IgorShevchik IgorShevchik commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Linked issue

Closes #451.

Type of change

  • Documentation (updates to the documentation or readme)
  • Bug fix (a non-breaking change that fixes an issue)
  • Enhancement (improving an existing functionality)
  • New feature (a non-breaking change that adds functionality)
  • Chore (updates to the build process or auxiliary tools and libraries)
  • Breaking change (fix or feature that would cause existing functionality to change)

Description

typescript was declared only as a peerDependency (^5.6.3 || ^6.0.0 || ^7.0.0) and never as a devDependency, so pnpm picked it from that range. Any root pnpm add re-resolved the root importer's peers from scratch and flipped it to 5.9.3, churning ~305 lockfile lines inside a diff about something else.

main          root 6.0.3  →  pnpm add  →  5.9.3
this branch   root 6.0.3  →  pnpm add  →  6.0.3

It drags the build toolchain with it

This is the part worth knowing, and the first revision of this PR did not have it. On main, one pnpm add moves the whole dist toolchain down:

package main after pnpm add here
@nuxt/module-builder 5.9.3 6.0.3
unbuild 5.9.3 6.0.3
tsconfck 5.9.3 6.0.3
mkdist both 6.0.3
vue-tsc 6.0.3 6.0.3

So main is one ordinary pnpm add away from building the published declarations with a mixed toolchain — and deploy.yml installs without --frozen-lockfile.

A declaration, not an override — and that is the change from the first revision

This PR originally added typescript: ^6.0.3 to overrides in pnpm-workspace.yaml. Review established that the smaller instrument does the same job, and that the larger one costs more than it returns.

What the override did additionally: collapsed the second TypeScript copy, which nuxt-component-meta pulls in through a hard typescript: ^5.9.3 dependency — not, as the first revision's comment claimed, through @nuxt/module-builder's peer. Module-builder already resolved to 6.0.3 on main.

What that cost: rewriting 24 recorded peer ranges to values upstream never published, forcing a third-party package's dependency across a major boundary, and erasing the unmet-peer report for @nuxt/module-builder (not optional), tsconfck and unbuild. With the override, pnpm peers check returns silence; here it still reports the pre-existing mismatch, which is the honest state:

✕ unmet peer typescript
  Installed: 6.0.3
  Wanted:
    ^5.9.3:  @nuxt/module-builder@1.0.3
    ^5.0.0:  tsconfck@3.1.6

The extra copy only ever reached docs-time metadata extraction, and the rendered prop tables are identical either way — 49 of 134 /api/component-meta/*.json payloads shift, entirely in TS-stdlib internals inside the recursive schema field that compactProp already strips, with 0 files differing on the surface ComponentProps.vue displays. Not worth erasing 24 upstream constraints for.

Corrections to the first revision

Four claims in it were wrong, and they are recorded here rather than quietly dropped:

  • "the devDependency does not survive pnpm add" — it does. Both instruments produce the same root resolution and byte-identical 46-line change sets. That row was the sole stated basis for choosing the override, and it was never measured; the probe behind it silently failed to find the root importer.
  • "the only typescript peer range in the tree that excludes 6.x"unbuild@3.6.1 peers ^5.9.2 and tsconfck@3.1.6 peers ^5.0.0. Module-builder is the only non-optional one.
  • "removes a peer complaint rather than adding one" — it removed the report, not the conflict, by rewriting the recorded ranges. Presented as an improvement; it was suppression.
  • "moves zero versions" — measured with a comparator structurally blind to importer flips, i.e. blind to the bug being fixed.

Verification

check result
pnpm install --frozen-lockfile passes
pnpm add -D no longer flips the root 6.0.3 before and after
pnpm peers check still honest — pre-existing mismatch reported
vue-tsc --noEmit clean
eslint . clean
vitest run test/ 302 files, 6870 passed, 6 skipped

The lockfile diff is 6 lines (was 92 under the override).

^6.0.3 is what playgrounds/nuxt, playgrounds/vue and playgrounds/demo already declare — the root was the odd one out.

Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

`typescript` was declared only as a peerDependency
(`^5.6.3 || ^6.0.0 || ^7.0.0`) and never as a devDependency, so pnpm chose it
from that range and any root `pnpm add` re-resolved the root importer's peers
from scratch, flipping it to 5.9.3 and churning ~305 lockfile lines inside a
diff about something else (#451).

Measured, because the flip is invisible in a version-set comparison:

  main             root 6.0.3  ->  pnpm add  ->  5.9.3
  this commit      root 6.0.3  ->  pnpm add  ->  6.0.3

It drags more than the root. On main, one `pnpm add` moves the whole `dist`
build toolchain down — `@nuxt/module-builder`, `unbuild` and `tsconfck` land on
5.9.3 while `vue-tsc` stays on 6.0.3 and `mkdist` splits across both, so the
published declarations would be built by a mixed toolchain. That matters
because `deploy.yml` installs without `--frozen-lockfile`. Here every one of
them stays on 6.0.3.

A declaration rather than an override, and the difference is the point. An
override at the same version was written first and does one thing more — it
collapses the second copy that `nuxt-component-meta` pulls in through a hard
`typescript: ^5.9.3` dependency. It also rewrites 24 recorded peer ranges to
values upstream never published, forces a third-party package's dependency
across a major boundary, and erases the unmet-peer report for
`@nuxt/module-builder`, `tsconfck` and `unbuild` — including one that is not
optional. Since the extra copy only reaches docs-time metadata extraction, and
the rendered prop tables are identical either way, that trade is not worth
making. `pnpm peers check` still reports the pre-existing mismatch here, which
is the honest state.

`^6.0.3` is what `playgrounds/nuxt`, `playgrounds/vue` and `playgrounds/demo`
already declare; the root was the odd one out.

Closes #451.
@IgorShevchik
IgorShevchik force-pushed the fix/typescript-override branch from dd89165 to 90fbadc Compare August 20, 2026 09:36
@IgorShevchik IgorShevchik changed the title chore(deps): state the TypeScript version instead of deriving it chore(deps): declare TypeScript instead of deriving it Aug 20, 2026
@IgorShevchik
IgorShevchik merged commit 5b7ae68 into main Aug 20, 2026
1 check passed
@IgorShevchik
IgorShevchik deleted the fix/typescript-override branch August 20, 2026 09:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

deps: any root pnpm add silently downgrades TypeScript 6.0.3 → 5.9.3

2 participants