Skip to content

refactor(storybook): rebuild the unified host as a devframe hub - #139

Merged
antfu merged 5 commits into
mainfrom
smart-pianos-move
Jul 28, 2026
Merged

refactor(storybook): rebuild the unified host as a devframe hub#139
antfu merged 5 commits into
mainfrom
smart-pianos-move

Conversation

@antfubot

@antfubot antfubot commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

What

Rebuilds the unified Storybook host (@devframes/storybook) as a devframe hub (on @devframes/hub) instead of a Storybook Composition shell. The hub is the UI shell; each built-in plugin's Storybook is its own type: 'launcher' dock that boots its storybook dev process on demand, with the live terminals plugin docked alongside.

  • Each Storybook registers a ctx.commands command (storybook:launch:<id>) plus a launcher dock bound to it.
  • Hitting Start dispatches the command over the serializable hub:commands:execute path, which spawns storybook dev through ctx.terminals (a read-only hub terminal session), streams the tail of the boot output onto the launcher's digest, tracks it via terminalSessionId, and returns the resolved URL.
  • On success the client swaps the launcher tile in place for the Storybook iframe (kept mounted across tab switches). Build mode resolves to the pre-built storybook-static/<id> served on one origin.

The former Storybook Composition wiring (.storybook/, refs, the HTML host shell, Introduction.stories.ts, @storybook/html-vite) is removed.

Housekeeping

  • Removes the examples/storybook-hub example — its hub code now lives in the storybook/ package (self-contained; no cross-dependency).
  • pnpm storybook runs the host hub (pnpm -C storybook dev), which spawns each plugin's Storybook lazily, rather than fanning out every plugin's storybook dev in parallel. Plugins keep their own storybook scripts for standalone use.
  • turbo.json: swaps the storybook-hub#build task for @devframes/storybook#build. cleanupUnusedCatalogs prunes the now-unused @storybook/html-vite catalog entry.

Why

The unified host now dogfoods devframe end to end — the hub's launcher primitive (bound command + terminalSessionId + live digest) drives each Storybook instead of Storybook Composition.

Verification

  • tsc --noEmit, eslint, and vite build all pass for the storybook/ package.

This PR was created with the help of an agent.

Follow-up fix

fix(hub): don't mutate frozen dock entries in register().update — surfaced while launching a Storybook: projecting a dock into the devframe:docks shared state runs it through Immer's produce, which deep-freezes the object the registry holds, so register().update(patch)'s in-place Object.assign threw "Cannot assign to read only property 'launcher'" on the first patch after sync. The handler now merges into a fresh object and swaps it in; added a regression test that freezes the stored view and patches it.

Each plugin's Storybook is now a first-class `type: 'launcher'` dock bound
to a `ctx.commands` command, replacing the iframe docks + bespoke
`storybook-hub:ensure` RPC. Hitting Start dispatches the command over
`hub:commands:execute`, which spawns `storybook dev` through
`ctx.terminals`, streams the boot output onto the launcher's digest, and
returns the resolved URL the client iframes in place.
@netlify

netlify Bot commented Jul 28, 2026

Copy link
Copy Markdown

Deploy Preview for devfra ready!

Name Link
🔨 Latest commit 73aa0d4
🔍 Latest deploy log https://app.netlify.com/projects/devfra/deploys/6a6842d92a270c00073635a4
😎 Deploy Preview https://deploy-preview-139--devfra.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

antfu and others added 2 commits July 28, 2026 13:55
Replace the @devframes/storybook Storybook Composition shell with a
devframe hub (built on @devframes/hub): each plugin's Storybook is a
`type: 'launcher'` dock bound to a `ctx.commands` command that spawns
`storybook dev` through `ctx.terminals` on demand, streams boot output
to the launcher digest, and iframes the running instance in place. The
live terminals plugin docks alongside so the spawned processes are
watchable.

Drop the now-redundant examples/storybook-hub example (its hub code
lives in the storybook package now), and point `pnpm storybook` at the
host hub rather than fanning out every plugin's storybook in parallel.
@antfubot antfubot changed the title refactor(storybook-hub): start each Storybook from a launcher dock refactor(storybook): rebuild the unified host as a devframe hub Jul 28, 2026
antfubot added 2 commits July 28, 2026 05:24
Projecting dock entries into the `devframe:docks` shared state runs them
through Immer's `produce`, which deep-freezes the very objects the docks
registry holds. The `register().update(patch)` handler then merged with
an in-place `Object.assign`, throwing "Cannot assign to read only
property" the first time a launcher (or any entry) was patched after the
initial sync. Merge into a fresh object and swap it into the registry
instead.
…gins in the hub

Give the two plugins that lacked a Storybook their own Vue setup
(`.storybook` config mirroring the existing plugins, plus presentational
component stories with static fixtures), and dock every plugin's
Storybook in the unified hub — data-inspector, og, and the pre-existing
messages Storybook now join git/inspect/code-server/terminals/a11y as
launcher docks.
@antfu
antfu merged commit a88350d into main Jul 28, 2026
12 checks passed
@antfu
antfu deleted the smart-pianos-move branch July 28, 2026 06:03
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.

2 participants