Skip to content

Commit a88350d

Browse files
antfubotantfu
andauthored
refactor(storybook): rebuild the unified host as a devframe hub (#139)
Co-authored-by: Anthony Fu <github@antfu.me>
1 parent f39cae8 commit a88350d

40 files changed

Lines changed: 1081 additions & 613 deletions

examples/storybook-hub/README.md

Lines changed: 0 additions & 56 deletions
This file was deleted.

examples/storybook-hub/package.json

Lines changed: 0 additions & 30 deletions
This file was deleted.

examples/storybook-hub/src/client/main.ts

Lines changed: 0 additions & 212 deletions
This file was deleted.

examples/storybook-hub/tsconfig.json

Lines changed: 0 additions & 12 deletions
This file was deleted.

examples/storybook-hub/uno.config.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"docs": "pnpm -C docs run docs",
2222
"docs:build": "pnpm -C docs run docs:build",
2323
"docs:serve": "pnpm -C docs run docs:serve",
24-
"storybook": "pnpm -r --parallel --if-present run storybook",
24+
"storybook": "pnpm -C storybook dev",
2525
"storybook:build": "pnpm --filter @devframes/storybook run storybook:build",
2626
"lint": "eslint --cache",
2727
"test": "pnpm run build && vitest",

packages/hub/src/node/__tests__/host-docks.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { DevframeViewLauncher } from '../../types/docks'
12
import type { DevframeHubContext } from '../context'
23
import { mkdtempSync } from 'node:fs'
34
import { tmpdir } from 'node:os'
@@ -305,4 +306,30 @@ describe('devframeDockHost ~builtin category', () => {
305306
expect(updatedLauncher?.digest).toBe('done')
306307
expect(updatedLauncher?.status).toBe('success')
307308
})
309+
310+
it('updates a registered entry whose stored view was frozen (Immer-projected shared state)', () => {
311+
const host = new DevframeDocksHost(createContext())
312+
const handle = host.register<DevframeViewLauncher>({
313+
type: 'launcher',
314+
id: 'app:build',
315+
title: 'Build',
316+
icon: 'ph:hammer-duotone',
317+
launcher: { title: 'Run build', status: 'idle', command: 'app:run-build' },
318+
})
319+
320+
// Projecting the entry into `devframe:docks` shared state runs it through
321+
// Immer's `produce`, which deep-freezes the very object the registry holds.
322+
Object.freeze(host.values()[0])
323+
324+
// The launch handler patches the launcher as the process boots; the update
325+
// must not throw "Cannot assign to read only property" on the frozen entry.
326+
expect(() => handle.update({
327+
launcher: { title: 'Run build', status: 'loading', command: 'app:run-build', terminalSessionId: 'build-session', digest: 'compiling…' },
328+
})).not.toThrow()
329+
330+
const entry = host.values()[0]
331+
const launcher = entry.type === 'launcher' ? entry.launcher : undefined
332+
expect(launcher?.status).toBe('loading')
333+
expect(launcher?.digest).toBe('compiling…')
334+
})
308335
})

packages/hub/src/node/host-docks.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,12 @@ export class DevframeDocksHost implements DevframeDocksHostType {
148148
if (patch.id && patch.id !== view.id) {
149149
throw diagnostics.DF8101({ id: view.id, attempted: patch.id })
150150
}
151-
this.update(Object.assign(this.views.get(view.id)!, patch))
151+
// Merge into a fresh object rather than mutating the stored entry in
152+
// place: once projected into the `devframe:docks` shared state, the
153+
// stored entry is deep-frozen by Immer, so an in-place `Object.assign`
154+
// would throw "Cannot assign to read only property". A new object is
155+
// always writable, and `update()` swaps it into the registry.
156+
this.update({ ...this.views.get(view.id)!, ...patch } as DevframeDockUserEntry)
152157
},
153158
}
154159
}

0 commit comments

Comments
 (0)