Repository navigation
CLI: Fix vitest ERESOLVE on fresh Next.js apps. - #36310
Conversation
|
@ObviousApp I dislike the solution. The solution should be to only add |
|
Fair — implemented in 72c2b79. The default for fresh installs is back to |
|
@ObviousApp Please consider these issues. Verify before fixing. A pnpm app with @types/node: catalog: and no vitest blows up collectDependencies and skips the whole Vitest install. In
|
When storybook init runs on a project that declares no vitest version (fresh create-next-app@16.3.x scaffolds), collectDependencies() pushed an unpinned `vitest`, which now resolves vitest@5.0.0. Vitest 5 dropped `^20` from its optional `@types/node` peer range, so npm hard-fails with ERESOLVE against the scaffold's `@types/node@^20` pin, and the install silently fails: init exits 0 with no storybook binary. Default the collected vitest family to ^4 (what addon-vitest's devDependencies are tested against) through the existing applyVersionToRelatedPackages alignment, so vitest, @vitest/browser-playwright and @vitest/coverage-v8 stay on one range and the declared-specifier path (including pnpm catalog: references) is untouched.
JsPackageManager.installDependencies runs the install behind a spinner and the captured package-manager output never reaches the caller: the spinner prints a generic failure message, and flows like `storybook init` swallow the thrown error and continue. A failed install therefore surfaces only indirectly — e.g. `sh: 1: storybook: not found` from a later smoke test, exit 127, with no hint that npm ERESOLVE was the cause. Propagate a truncated output tail (last 15 lines, where npm prints its own error summary) into the thrown error message and log it, so the next dependency-resolution failure names itself.
Address review feedback: keep unpinned (latest) vitest as the default for fresh installs, and only fall back to the vitest ^4 family when the project's declared @types/node range conflicts with the latest vitest major's optional @types/node peer (^22.0.0 || >=24.0.0) — e.g. create-next-app scaffolds pinning @types/node@^20.
Review feedback on #36310: - canInstallLatestVitest: validate the @types/node range with semver validRange before intersecting. A pnpm `catalog:` reference threw "Invalid comparator" and aborted the whole Vitest install; unparseable specifiers now fall back to the ^4 family. - getInstallErrorTail: return the tail even when the captured output fits the 15-line window. Short but real package-manager errors were returned as '' and never logged or folded into the thrown error. The dedup (skip appending when the message already contains the tail) stays at the JsPackageManager call site.
72c2b79 to
35f9658
Compare
|
Both verified against the code and fixed in 35f9658 — thank you.
Both suites pass: 77/77 ( |
Package BenchmarksCommit: The following packages have significant changes to their size or dependencies:
|
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 181 | 181 | 0 |
| Self size | 92 KB | 92 KB | 🚨 +48 B 🚨 |
| Dependency size | 38.34 MB | 38.35 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/angular
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 186 | 186 | 0 |
| Self size | 266 KB | 267 KB | 🚨 +108 B 🚨 |
| Dependency size | 31.37 MB | 31.39 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/ember
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 180 | 180 | 0 |
| Self size | 13 KB | 13 KB | 🎉 -18 B 🎉 |
| Dependency size | 33.65 MB | 33.66 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/nextjs
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 447 | 447 | 0 |
| Self size | 641 KB | 641 KB | 0 B |
| Dependency size | 62.25 MB | 62.26 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/nextjs-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 101 | 101 | 0 |
| Self size | 1.42 MB | 1.42 MB | 🚨 +48 B 🚨 |
| Dependency size | 23.53 MB | 23.54 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/react-native-web-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 121 | 121 | 0 |
| Self size | 29 KB | 29 KB | 🚨 +18 B 🚨 |
| Dependency size | 25.43 MB | 25.44 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/react-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 79 | 79 | 0 |
| Self size | 32 KB | 32 KB | 0 B |
| Dependency size | 20.64 MB | 20.66 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/react-webpack5
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 266 | 266 | 0 |
| Self size | 23 KB | 23 KB | 🎉 -12 B 🎉 |
| Dependency size | 50.87 MB | 50.89 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/server-webpack5
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 193 | 193 | 0 |
| Self size | 15 KB | 15 KB | 🚨 +12 B 🚨 |
| Dependency size | 39.61 MB | 39.62 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/svelte-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 11 | 11 | 0 |
| Self size | 54 KB | 54 KB | 0 B |
| Dependency size | 25.54 MB | 25.55 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/sveltekit
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 12 | 12 | 0 |
| Self size | 56 KB | 56 KB | 🎉 -24 B 🎉 |
| Dependency size | 25.59 MB | 25.61 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/tanstack-react
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 80 | 80 | 0 |
| Self size | 132 KB | 132 KB | 0 B |
| Dependency size | 20.68 MB | 20.69 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/vue3-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 94 | 94 | 0 |
| Self size | 31 KB | 31 KB | 0 B |
| Dependency size | 18.64 MB | 18.65 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/preset-react-webpack
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 152 | 152 | 0 |
| Self size | 14 KB | 14 KB | 🚨 +18 B 🚨 |
| Dependency size | 34.99 MB | 35.00 MB | 🚨 +12 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
|
Acknowledged — the deltas here are uniform across every package (dependency count unchanged, dependency size +12 KB, self-size shifts of tens of bytes), which is the rebased core (this branch now tracks current |
Review feedback on #36310: - canInstallLatestVitest: validate the @types/node range with semver validRange before intersecting. A pnpm `catalog:` reference threw "Invalid comparator" and aborted the whole Vitest install; unparseable specifiers now fall back to the ^4 family. - getInstallErrorTail: return the tail even when the captured output fits the 15-line window. Short but real package-manager errors were returned as '' and never logged or folded into the thrown error. The dedup (skip appending when the message already contains the tail) stays at the JsPackageManager call site. (cherry picked from commit 35f9658)
CLI: Fix vitest ERESOLVE on fresh Next.js apps. (cherry picked from commit 06dc54c)
CLI: Fix vitest ERESOLVE on fresh Next.js apps. (cherry picked from commit 06dc54c)
Closes #
What I did
The daily
init-empty-nextjs-tsCI job has been failing withsh: 1: storybook: not found(exit 127) in the "Run storybook smoke test" step. Root cause chain:AddonVitestService.collectDependencies()pushed an unpinnedvitestinto the base dependency set when a fresh project does not declare vitest.@types/nodepeer is^22.0.0 || >=24.0.0(Vitest 5 dropped^20).create-next-appscaffolds pin@types/node@^20— npm hard-fails withERESOLVE.JsPackageManager.installDependenciesruns npm behind a spinner and swallowed the captured stderr on failure, sostorybook initexited 0 with no Storybook binary installed — surfacing only later as the smoke test's exit 127.Two coupled fixes, both in the CLI core:
Peer-aware Vitest selection (
AddonVitestService.ts). When a project declares vitest, the declared specifier is preserved unchanged (including pnpmcatalog:references). When it does not, the CLI now installsvitest@latestby default and falls back to the^4family — the line addon-vitest's own devDependencies test against — when the project's@types/noderange conflicts with Vitest 5's peer requirement. The conflict check (canInstallLatestVitest) intersects the project's declared@types/node(from dependencies, devDependencies, and peerDependencies) withLATEST_VITEST_TYPES_NODE_PEER(^22.0.0 || >=24.0.0) usingsemver.intersects. The selected specifier flows through the existing related-package alignment sovitest,@vitest/browser-playwright, and@vitest/coverage-v8all resolve to the same family (one source of truth), whileplaywrightstays independently unpinned.Surface npm stderr on install failure (
JsPackageManager/ package-manager utils). A newgetInstallErrorTailutility returns the lastINSTALL_ERROR_TAIL_LINES(15) lines of the captured package-manager output.installDependenciesnow logs that tail and appends it to the thrown error message when an install exits non-zero, so the nextERESOLVEnames itself instead of surfacing as a missing binary. Successful installs still clear the installed-version cache as before.Checklist for Contributors
Testing
The changes in this PR are covered in the following automated tests:
AddonVitestService.test.ts: latest selection with no@types/node;^4fallback for@types/node@^20; latest selection for@types/node@^22;canInstallLatestVitestboundary cases; declared specifiers preserved; derived@vitest/*alignment.JsPackageManager.test.ts: truncated npm stderr propagation on failed installs, logger output, and cache clearing on success.Manual testing
Caution
This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!
Reproduced end-to-end against a local Verdaccio registry, mirroring the CI
init-empty-nextjs-tsjob recipe:yarn local-registry --open --publish(proxy on 6001 redirecting@storybook/*to Verdaccio on 6002, other packages to npmjs).storybooktarball contains the fixedcollectDependenciesbundle anddist/bin/dispatcher.js; no staledetectPnpcode increate-storybook).CI=1 STORYBOOK_INIT_EMPTY_TYPE=nextjs-ts npm_config_registry=http://localhost:6001:npx --yes storybook init --yes --package-manager npm.Result (all assertions pass):
initexit code: 0node_modules/.bin/storybook: present (the smoke test would run — no more exit 127)node_modules: 4.1.11 (the^4family, not 5.x)package.json:vitest: ^4,@vitest/browser-playwright: ^4,@types/node: ^20— noERESOLVE, no "Installation of dependencies failed!"Pre-fix, the same flow exited 0 with the binary missing and
vitest: latestin the scaffold, reproducing the CI failure shape exactly.Documentation
Checklist for Maintainers
ci:normal,ci:mergedorci:dailyGH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found incode/lib/cli-storybook/src/sandbox-templates.tsqa:neededorqa:skipbug,ci:normal, andqa:skiplabels (manual QA waived: CLI dependency-selection change covered by unit tests + the Verdaccio repro above)Post-merge:
init-empty-nextjs-tsmust go green in the next CircleCI daily run — PR CI alone does not exercise that job.🔗 Obvious Project · 🧵 Obvious Thread