Repository navigation
chore(web): migrate the Storybook family to 10.x (Closes #425) - #449
Merged
Merged
Conversation
Storybook refuses to run unless every one of its packages sits on the same major, so `storybook`, `@storybook/react-vite`, `@storybook/addon-vitest` and `@storybook/addon-a11y` all move together in one change. Splitting them is what made the two Dependabot PRs structurally unmergeable: #413 moved the framework and died on `No matching export ... "Tag"` against core 9, #414 moved core only and made bun resolve a nested storybook@9 under every `@storybook/*` package. `bun pm ls --all` now shows exactly one core (storybook@10.5.5) and no nested copies, and `bun install --frozen-lockfile` is clean.
… 10 bump addon-vitest 10.3+ prints an INFO box telling you to delete this call because it now provisions preview annotations itself. That is true only for the `storybook` Vitest project (the one with the plugin). The `unit` project shares this setup file and has no Storybook plugin, so following the nudge would strip the preview decorators from every composed-story unit test.
@storybook/react-dom-shim ships dist/react-18.js in Storybook 10 (it was dist/react-18.mjs in 9). Both optimizeDeps guard comments named the old file; the guard itself is unchanged (it pre-bundles by package name), only the explanation of WHICH module it covers was stale.
Storybook only runs when every one of its packages sits on the same major, so a per-package major PR is structurally unmergeable — #413 and #414 each moved half the family and neither could ever go green (see #425). This does not contradict #398's decision to ungroup majors: that rationale was "one migration per PR", and the Storybook family IS one migration whose packages must move in lockstep. Listed first so Dependabot keeps the family together for minor/patch too, which have the same lockstep requirement. Kept as the last commit, touching only this file, so it can be dropped with a single revert without touching the migration.
Shironex
force-pushed
the
chore/storybook-10-migration
branch
from
August 1, 2026 00:46
40d422d to
59caa18
Compare
This was referenced Aug 1, 2026
This was referenced Aug 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Moves the whole Storybook family from
9.1.20to10.5.5in one deliberate change, because Storybook refuses to run unless every one of its packages sits on the same major.Why this could not go through Dependabot
storybook,@storybook/react-vite,@storybook/addon-vitestand@storybook/addon-a11yare one migration. The two open Dependabot PRs each moved half of it and were structurally unmergeable:@storybook/react-vite→ 10 while core stayed 9 →No matching export in storybook/dist/preview-api/index.js for import "Tag".storybook@9.1.20under every@storybook/*package, so two cores coexisted in one install.After this change
bun pm ls --allshows exactly one core and no nested copies:bun install --frozen-lockfileis clean.The play-function
Canvassites — root cause, and why the diff is empty thereThe issue predicted a code rewrite at every
canvas.<query>site. It turned out none was needed, and that is the actual finding, so here is the evidence rather than a claim.Canvasis not a Storybook-9 vs Storybook-10 API difference. It is a declaration-merging type that only assembles when one copy of core is installed:storybook/dist/csf/index.d.tsdeclaresinterface Canvas {}(empty), andstorybook/dist/test/index.d.tsfills it in viadeclare module 'storybook/internal/csf' { interface Canvas extends BoundFunctions<typeof queries> {} }.storybook/dist/csf/index.d.ts:1843declaresinterface Canvas extends BoundFunctions<typeof queries> {}directly. No augmentation needed.In #414's split install the augmentation landed on a different physical module than the one
@storybook/react-vite@9resolvedStoryContext['canvas']from, soCanvasstayed the empty interface and every property access reportedTS2339— which is why the log listed one line per query call and looked like an API removal. With the family consistent,Canvascarries the testing-library queries again and all 50 call sites typecheck and run unchanged.The issue's list was truncated at 12 lines; swept for all of them. Every play-function site that destructures
{ canvas }from the play context (7 files, 50 query calls) was verified green — by typecheck and by executing the play functions:canvasquery callssettings/ClaudeNotifyHook/ClaudeNotifyHook.stories.tsxgetByRole×2,getByTextterminal/TerminalGrid/TerminalGrid.stories.tsxgetAllByRole×2,getAllByText,getByLabelText,getByRole,getByText,queryByRoleterminal/TerminalGridPane/TerminalGridPane.stories.tsxgetByRole×5,getByText×3,getByLabelText×2,queryByRole×2terminal/TerminalPane/TerminalPane.stories.tsxgetByText×6,queryByTextterminal/TerminalReadonlyPane/TerminalReadonlyPane.stories.tsxgetByRole×2,getByLabelText×2terminal/TerminalTabs/TerminalTabs.stories.tsxgetByRole×12,getByText×2,getByLabelText,queryByRoleterminal/TerminalView/TerminalView.stories.tsxgetByRoleThe last four files were not in the issue's truncated list — they would have been the second surprise if only the three named files had been checked.
The other ~350
canvas.*calls in the repo come fromwithin(canvasElement)/portaledSurface()(i.e.storybook/test'swithin), never touched theCanvasinterface, and were unaffected either way.Peer dependencies
storybook@10declares three peers, all optional (peerDependenciesMeta), so nothing is newly required:@types/react^16 || ^17 || ^18 || ^19— satisfied by the existing@types/react@^19.2.0.vite-plus^0.1.15 || ^0.2.0— optional and not installed; it is the Vite+ toolchain, not something this repo uses. No action.prettier^2 || ^3— optional, not installed.The widened vite range (
^5 || ^6 || ^7 || ^8, on@storybook/react-viteand@storybook/builder-vite) still covers the pinnedvite@7.3.5— it is a widening, not a floor bump, so nothing forces a Vite major.@storybook/addon-vitestnow peers@vitest/browser^3 || ^4,@vitest/runner^3 || ^4,vitest^3 || ^4(all optional); the repo'svitest@3.2.7/@vitest/browser@3.2.7stay in range, so this migration does not drag in the Vitest 4 major.Config
storybook automigrate --dry-runproposed five migrations; four are additive opt-ins that are out of scope for a version migration (eslintPlugin— new lint dependency,addon-mcp— new addon,addon-a11y-addon-test— the a11ytestparam is already set to'todo'inpreview.ts,wrap-getAbsolutePath— a PnP/monorepo robustness rewrite the current bun-hoisted install does not need;build-storybookis green without it).The fifth (
addon-globals-api) was run and then reverted: it rewritesparameters.backgrounds.disable→disabled, but Storybook 10's own preview runtime destructuresdisable(storybook/dist/preview/runtime.js:30702) and its type declaresdisable?: boolean(storybook/dist/csf/index.d.ts:1417). Applying it would have silently dead-lettered the parameter.Every existing import specifier (
storybook/test,storybook/manager-api,storybook/theming/create,@storybook/react-vite) is unchanged in 10, so no import rewrites were needed..storybook/vitest.setup.tskeeps itssetProjectAnnotationscall even though addon-vitest 10.3+ prints an INFO nudge to remove it — a comment now records why: the nudge is only true for thestorybookVitest project (which has the plugin). Theunitproject shares the same setup file and has no Storybook plugin, so removing the call would strip the preview decorators from every composed-story unit test.The Dependabot group commit — separately revertible
The last commit adds a
storybookgroup to.github/dependabot.ymlwithpatterns: ["storybook", "@storybook/*"]and noupdate-typesrestriction, so it captures majors.This does not conflict with the #398 decision to ungroup majors. That rationale was "one migration per PR" — and the Storybook family is one migration whose packages must move in lockstep. Without the group, every future Storybook major arrives as N individually-unmergeable PRs and a human has to hand-merge them into one branch, which is exactly the work this PR is doing. The group is listed first because Dependabot assigns a dependency to the first group it matches, which keeps the family together for minors and patches too (they have the same lockstep requirement).
It is deliberately its own final commit so it can be dropped with a single revert if you disagree, without touching the migration.
Test plan
bun run lint(eslint +lint:meta) — greenbun run typecheck+bunx tsc -b apps/web— green (this is where TS2339 would surface)bun run codegen:check— greenbun run test:node— 2047 pass / 2 skipbun run test:plugin— 15 passbun run --filter @nightcore/web test:stories— 206 files / 914 tests pass; this is the gate that actually executes every play functionbun run test:web(storybook + unit browser projects) — 514 files / 2937 tests passbun run --filter @nightcore/web build-storybook— builds successfullybun install --frozen-lockfile— cleanbun run audit— no new advisoriesCI is green on the same tree, including
vitest browser coverage (apps/web)— the exact job that red-lined on #414.Closes #425. #413 and #414 should be closed when this lands.