Skip to content

Support non-React Storybook frameworks (Web Components, Lit, Vue, etc.) #48

@Rajdeepc

Description

@Rajdeepc

Problem

The addon currently couples metric collection to React via the withPerformanceMonitor decorator, which uses React Profiler and expects stories to return React elements. This means:

  1. Loading the default preview export in a non-React Storybook (e.g. @storybook/web-components-vite) causes rendering errors because the decorator wraps stories in React Profiler components.
  2. The only workaround is loading the addon via /preset (manager panel only) and writing a custom decorator from scratch that reimplements metric collection and channel communication.

We ran into this integrating the addon into Spectrum Web Components (Storybook 10 + @storybook/web-components-vite). Our workaround was a ~600-line custom decorator using web platform APIs (requestAnimationFrame, PerformanceObserver, MutationObserver, performance.memory) to feed metrics to the existing manager panel.

Suggestion

Separate the addon into framework-agnostic and framework-specific layers:

  1. Core metrics collector (framework-agnostic) -- The web platform metrics (frame timing, long tasks, CLS, event timing / INP, LoAF, memory, DOM element count) don't depend on React at all. These could live in a shared base class or module.
  2. Framework-specific adapters -- React Profiler metrics (reactRenderCount, reactMountDuration, etc.) are React-specific and should be an optional layer on top. Other frameworks could provide their own equivalents (e.g. Lit's updateComplete timing for web components, Vue's renderTracked/renderTriggered).
  3. Pluggable decorator export -- Instead of a single React-only decorator, export a factory or base decorator that frameworks can extend:
 // Possible API shape
   import { createPerformanceDecorator, WebPlatformCollector } from '@github-ui/storybook-addon-performance-panel/core';
   
   // Web components -- just web platform metrics
   export const withPerformanceMonitor = createPerformanceDecorator({
     collector: new WebPlatformCollector(),
   });
   
   // React -- web platform + React Profiler
   import { ReactProfilerCollector } from '@github-ui/storybook-addon-performance-panel/react';
   export const withPerformanceMonitor = createPerformanceDecorator({
     collector: new CompositeCollector([new WebPlatformCollector(), new ReactProfilerCollector()]),
   });
  1. Metrics schema -- The manager panel could gracefully handle missing metric groups (e.g. hide the React Profiler section when those metrics aren't present) rather than requiring every field to be populated with zeroes.

What I have built as a workaround

Our custom decorator collects these metrics using browser-native APIs:
Link to the gist: https://gist.github.com/Rajdeepc/80215eae8de1d764a176e4411e17f9cc

Metric API
FPS, frame time, dropped frames requestAnimationFrame loop
Long tasks, TBT PerformanceObserver (longtask)
Layout shifts (CLS) PerformanceObserver (layout-shift)
Input latency, INP PerformanceObserver (event)
Long animation frames (LoAF) PerformanceObserver (long-animation-frame)
Memory usage performance.memory
DOM element count MutationObserver

All of this is framework-agnostic and could be the shared foundation. Happy to contribute a PR if the architecture direction makes sense.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions