Skip to content

Reset performance metrics on FORCE_REMOUNT (same story ID)#85

Draft
Copilot wants to merge 2 commits intomainfrom
copilot/add-force-remount-handler
Draft

Reset performance metrics on FORCE_REMOUNT (same story ID)#85
Copilot wants to merge 2 commits intomainfrom
copilot/add-force-remount-handler

Conversation

Copy link
Contributor

Copilot AI commented Mar 7, 2026

When Storybook's remount button triggers FORCE_REMOUNT, the story remounts with the same storyId, so the decorator reused the existing PerformanceMonitorCore and the panel retained stale metrics — neither was reset.

Changes

  • performance-panel.tsx — Added forceRemount channel handler in useChannel, mirroring the storyArgsUpdated pattern:

    forceRemount: () => {
      emit(PERF_EVENTS.RESET)
      dispatch({type: 'RESET_METRICS'})
    },
  • decorators/universal.ts — Extended the new-core condition to also trigger on ctx.forceRemount, stopping the old core before creating a fresh one to avoid leaking intervals/observers:

    const isForceRemount = (ctx as StoryContext & {forceRemount?: boolean}).forceRemount === true
    if (core?.storyId !== ctx.id || isForceRemount) {
      if (core) core.stop()
      core = new PerformanceMonitorCore(ctx.id)
      // ...
    }

    forceRemount isn't in Storybook's published StoryContext typings, hence the intersection cast.

  • __tests__/performance-decorator-universal.browser.test.ts — Two new tests: verifies a fresh core is created on force remount with the same story ID, and that the old core's channel listeners are cleaned up.

Original prompt

Problem

When a user clicks Storybook's refresh/remount button (FORCE_REMOUNT), the story unmounts and remounts with the same storyId. Currently:

  1. Panel side (performance-panel.tsx): No channel handler resets metrics on remount — stale data persists until the next METRICS_UPDATE arrives
  2. Decorator side (decorators/universal.ts): The PerformanceMonitorCore is reused because ctx.id hasn't changed, so accumulated metrics (long tasks, TBT, CLS, render counts, etc.) carry over from the previous session
  3. The storyArgsUpdated handler does reset properly, but there's no equivalent for remount

Required Changes

1. Panel: Listen for forceRemount event in performance-panel.tsx

In the useChannel block inside ConnectedPanelContent (around line 1484-1524), add a forceRemount handler that resets metrics, following the same pattern as the existing storyArgsUpdated handler:

// Add alongside the existing storyArgsUpdated handler in useChannel:
forceRemount: () => {
  emit(PERF_EVENTS.RESET)
  dispatch({type: 'RESET_METRICS'})
},

2. Decorator (universal): Create a new core on remount in decorators/universal.ts

In decorators/universal.ts (around line 105-121), the withPerformanceMonitor function currently only creates a new core when ctx.id changes. It also needs to handle ctx.forceRemount === true by stopping the old core and creating a fresh one:

// Change from:
if (core?.storyId !== ctx.id) {

// To also check forceRemount:
const isForceRemount = ctx.forceRemount === true
if (core?.storyId !== ctx.id || isForceRemount) {
  if (core) {
    core.stop()
  }
  core = new PerformanceMonitorCore(ctx.id)
  setActiveCore(core)
  core.start()
  // ... rest of setup
}

Note: The StoryContext type may not include forceRemount in its type definition. Check the actual Storybook types — it may be accessed via (ctx as any).forceRemount or it might be available on ctx.parameters or the context object directly. Look at how Storybook passes this flag and handle the typing appropriately.

3. Add tests for force remount behavior

In the existing test file packages/storybook-addon-performance-panel/__tests__/performance-decorator-universal.browser.test.ts, add a test case verifying that a new core is created when force remount is triggered with the same story ID:

it('creates a new core when force remount is triggered (same story ID)', () => {
  const ctx = makeCtx({id: 'story-a'})

  withPerformanceMonitor(vi.fn(() => ''), ctx)
  const first = getActiveCore()

  // Simulate force remount — same ID but forceRemount flag
  const remountCtx = makeCtx({id: 'story-a', forceRemount: true})
  withPerformanceMonitor(vi.fn(() => ''), remountCtx)
  const second = getActiveCore()

  expect(second).not.toBe(first)
})

Also add a panel reducer test in the appropriate test file to verify that RESET_METRICS properly resets metrics state.

Key Files to Modify

  • packages/storybook-addon-performance-panel/performance-panel.tsx — Add forceRemount handler in useChannel
  • packages/storybook-addon-performance-panel/decorators/universal.ts — Check forceRemount flag when deciding whether to create a new core
  • packages/storybook-addon-performance-panel/__tests__/performance-decorator-universal.browser.test.ts — Add test for remount behavior

Important Notes

  • The storyArgsUpdated handler already demonstrates the correct pattern: emit PERF_EVENTS.RESET and dispatch RESET_METRICS
  • Make sure the old core is properly stopped before creating a new one to avoid leaking intervals/observers
  • The PR should be opened as a draft

This pull request was created from Copilot chat.


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Co-authored-by: mattcosta7 <8616962+mattcosta7@users.noreply.github.com>
Copilot AI changed the title [WIP] Add force remount handler to reset metrics Reset performance metrics on FORCE_REMOUNT (same story ID) Mar 7, 2026
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