GithubHelp home page GithubHelp logo

atlassian-labs / storybook-addon-performance Goto Github PK

View Code? Open in Web Editor NEW
645.0 13.0 30.0 8.36 MB

🚧 A storybook addon to help better understand and debug performance for React components.

Home Page: https://storybook-addon-performance.netlify.com

License: Other

JavaScript 1.04% TypeScript 98.96%

storybook-addon-performance's Introduction

storybook-addon-performance 🚀

A storybook addon to help better understand and debug performance for React components

storybook-addon-performance demo

📺 Project overview by Jack Herrington

Highlights 🌟

  • Zero config (except for interactions): Generate performance information relating to server-side rendering and client-side mounting without any configuration
  • Pin results: You can run some tasks, pin the result, make some changes, rerun the tasks and see what changed
  • Save/Load results: You can run some tasks, save the results as a local artifact, and run them again later by loading the artifact back into the addon.
  • Interactions: Add your own custom user interactions to run as a parameter to your story. This lets you time how long interactions take. The API for this is super flexible and powerful!
  • Control: Run all tasks for an overview, or run individual tasks to drill down on specific problems
  • Marked: All tasks are marked with the User Timing API to allow for easy debugging of individual tasks in your browser's performance profiler

Marking tasks

Installation

  1. Install storybook-addon-performance
# pnpm
pnpm add storybook-addon-performance --dev

# yarn
yarn add storybook-addon-performance --dev

# npm
npm install storybook-addon-performance --save-dev
  1. Register the addon in .storybook/main.js
module.exports = {
  addons: ['storybook-addon-performance'],
};
  1. Add the decorator

You can either add the decorator globally to every story in .storybook/preview.js (recommended)

import { withPerformance } from 'storybook-addon-performance';

export const decorators = [withPerformance];

Or you can add it to individual stories:

Using Component Story Format (CSF)

import MyComponent from './MyComponent';
import { withPerformance } from 'storybook-addon-performance';

export default {
  title: 'MyComponent',
  component: MyComponent,
  decorators: [withPerformance],
};

Using StoriesOf API

import MyComponent from './MyComponent';
import { withPerformance } from 'storybook-addon-performance';

storiesOf('MyComponent', module)
  .addDecorator(withPerformance)
  .add('MyComponent', () => <MyComponent />);

Usage: Interactions

Interaction tasks are a task type that can be defined and run on a story-by-story basis. They are useful for timing the interactive performance of your components.

To define your interaction tasks, first create an array of objects, each containing the name and description (optional) of the task, and a run function that performs whatever tasks you'd like to measure:

import { InteractionTaskArgs, PublicInteractionTask } from 'storybook-addon-performance';
import { findByText, fireEvent } from '@testing-library/dom';

// ...

const interactionTasks: PublicInteractionTask[] = [
  {
    name: 'Display dropdown',
    description: 'Open the dropdown and wait for Option 5 to load',
    run: async ({ container }: InteractionTaskArgs): Promise<void> => {
      const element: HTMLElement | null = container.querySelector('.addon__dropdown-indicator');
      invariant(element);
      fireEvent.mouseDown(element);
      await findByText(container, 'Option 5', undefined, { timeout: 20000 });
    },
  },
];

The run function in each task object takes two arguments:

  • container: an HTMLElement container that contains a rendered instance of the story component

  • controls: contains an async timing function that can be optionally called to specify when to start and finish measurements; otherwise the time taken to complete the entire run function is measured. Useful when a task involves some set-up work.

    To use, wrap the operations in question with controls.time as shown below:

    run: async ({ container }: InteractionTaskArgs): Promise<void> => {
      // setup
      await controls.time(async () => {
        // interaction task you'd like to measure
      });
    };

Note that you can use whatever libraries you'd like to perform these interaction tests – the example above uses @testing-library/dom to open the select in the example and wait for a specific item.

You can then include the array of interaction tasks inside the performance parameters of your story, with the key interactions:

// Using the Component Story Format (CSF)
// https://storybook.js.org/docs/formats/component-story-format/
import { findByText, fireEvent } from '@testing-library/dom';
import { PublicInteractionTask } from 'storybook-addon-performance';
import React from 'react';
import Select from 'react-select';
import invariant from 'tiny-invariant';

export default {
  title: 'React select example',
};

const interactionTasks: PublicInteractionTask[] = [
  {
    name: 'Display dropdown',
    description: 'Open the dropdown and wait for Option 5 to load',
    run: async ({ container }: InteractionTaskArgs): Promise<void> => {
      const element: HTMLElement | null = container.querySelector('.addon__dropdown-indicator');
      invariant(element);
      fireEvent.mouseDown(element);
      await findByText(container, 'Option 5', undefined, { timeout: 20000 });
    },
  },
];

select.storyName = 'React Select';
select.parameters = {
  performance: {
    interactions: interactionTasks,
  },
};

Supplied types

As seen above, the plugin exports two type definitions to assist with creating your own interaction tasks:

  • PublicInteractionTask: defines the object structure for an interaction task; pass an array of these tasks as a parameter to storybook, as shown above.
  • InteractionTaskArgs: the arguments for an interaction task's run function

Usage: Saving and loading results

You can save the result of a performance task as a local artifact by using the Save API. The Save API creates a story-specific artifact which can be then be loaded at a later time to be used as a benchmark. This can be useful for CI or testing a change in branch vs the trunk. You can use this API via the Save result / Load result buttons in the UI.

Some caveats with this API:

  • Storybook run performance results are variable, and can change depending on CPU utilisation / memory when the tests are run. If you intend to save an artifact, ensure you're re-running / comparing your results in an environment that is as similar as possible to the environment it was originally run.
  • For this API to work correctly the task artifact should be based on the same number of samples / copies as the original test.

For more consistent results we suggest recording artifacts using 10 copies / 10 samples.

Usage: Filtering task groups

Some components are not designed to work in server side rendering, or on the client. To support this we have created a allowlist that you can optionally pass in to only allow the groups to run that you want to. To configure this option, set the allowedGroups option as part of a story's parameters.

  • Default value: ['server', 'client'] (run everything)
// Using [Component Story Format (CSF)](https://storybook.js.org/docs/formats/component-story-format/)
export const onlyClient = () => <p>A story only measuring client-side performance 👩‍💻</p>;

onlyClient.parameters = {
  performance: {
    allowedGroups: ['client'],
  },
};

export const onlyServer = () => <p>A story only measuring server-side performance ‍☁️</p>;

onlyServer.parameters = {
  performance: {
    allowedGroups: ['server'],
  },
};

A Note on Performance Metrics 💡

In order to get the most accurate performance metrics possible, you should use a production build of Storybook. For more background, see the React optimizing performance documentation.

While this add-on does work with a dev build, you'll see more variability in results.

Local addon development

In the storybook-addon-performance folder (packages/storybook-addon-performance)

# Start the typescript watcher and a local storybook:
pnpm dev

# Start just the typescript watcher
# This is needed as storybook does not compile addons
pnpm typescript:watch

# Start the local storybook
pnpm storybook:dev

Thanks

Made with ❤️ by your friends at Atlassian


With ❤️ from Atlassian

storybook-addon-performance's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

storybook-addon-performance's Issues

Feature request: Store results of performance tests somehow and somewhere for the future usage (e.g. performance regression testing on CI)

Hey 👋
What a great idea for an addon! It reminds me how Stripe was doing performance testing of their components several years ago. They've found that testing performance of specific components have much more value than testing the whole pages with tons of components.

I know that the storybook addons live only in the browser so the idea that I want to propose exceeds the browser boundaries, but... at least it's worth to propose it and generally I'd like to start a discussion about it.

Idea

Store "somehow" and "somewhere" performance results to have automatic regression testing that could be run on CI.

It may be stored by using an API? Maybe tools like Graphite? Even it could be saved like jest's snapshot tests, locally as a file with data in a specific format.

Do you plan to work on something like that in the future in storybook-addon-performance or as a separate project? What do you think?

Observed that Select element does not have an accessible name in ‘performance tab’ page.

Test Environment:
OS: Windows 11
OS version: 23H2 (OS Build 25393.1000)
Edge Version: 114.0.1823.51 (Official build) (64-bit)

Repro steps:

  1. Open URL: “Overview - Docs ⋅ Storybook (windows.net)” and sign in with valid credentials. 
  2. In left navigation select “Common navigation with data transform(Desktop)” and invoke it. 
  3. In right page navigate to ‘Performance tab’ item and invoke it. 
  4. Now Run the Accessibility insights for wed for the opened page. 

Actual Result:
Observed that Select element does not have an accessible name in ‘performance tab’ page.

Expected Result:
Ensure Select element has an accessible name in ‘performance tab’ page

Note:
Observation: Narrator announces<<1 Copy , Combo Box , Collapsed ,  has Popup>> ,<<1 Sample , Combo Box , Collapsed ,  has Popup>>. Note: The same issue is observed in the Left navigation in “Ellipsis Menu” , “MSFT Support Ellipsis Menu” , “Feedback” link , “Flyout”, “Navigation Link” and “panel” for copy and select copy boxes under Performance tab item.

Attachments:
Narrator announcement

Fastpass-MSFT support ellipse menu

Fastpass-Flyout

Fastpass-feedback

Fastpass-ellipsis menu

Fastpass-Common navigation with data transform(Desktop)

Fast pass issue

Using this addon leads to duplicate styled-components

styled-components is defined as a direct dependency, which leads to multiple styled-components being installed in node-modules and to issues within the application. Here is the explanation for the library authors on what to do in that case.

Can you please look into this and possible move the styled-components to the peer dependencies instead?

Thanks.

"sideEffects: false" in storybook-addon-performance

Why "false"? Addon changes Storybook interface at least. We have real troubles with prod build of storybook and tree-shaking. Addon merely missed in prod build due to Webpack shook it.

We forced to fix it by:

import dummy from 'storybook-addon-performance/register'
window.__CHEAT_TREE_SHAKING__ = typeof dummy

But it seems like filthy hack. Strongly requesting for sideEffects: true. Beg you.

Not working with styled-components

I tried to use this addon with ThemeProvider from styled-components and it didn't work.

const SpacingContainer = styled.div(({ theme }) => {
  console.log('theme', theme)
  return css`
    padding: ${theme.spacing.xs}rem;
  `
})

export default {
  title: 'Design Tokens',
}

const ThemeSpacing = () => <SpacingContainer />

When Storybook renders this component, it works fine and I can see the whole theme object. However, when I pressed START ALL in the Performance plugin, I could see in the log that the theme object was empty and there were only errors in the Performance addon console.

image

Panel not showing up

I'm using storybook 6.4.19 and have added the withPerformance decorator globally in preview.js but no panel is added to my storybook. My other decorators and addons are working. I've also added storybook-addon-performance/register to main.js addons.

There's not word on what storybook versions are supported, can you confirm that it should work with 6.4.19 please?
Thank you.

Add support for storybook 7

Storybook v7 adds support to esm configuration. This allows in the separate entry point for storybook addon registration to import esm.

Package subpath './package.json' is not defined by "exports"

This plugin is currently causing errors when building a static version of storybook. We weren't experiencing issues in storybook 7.1.x, but we're now having problems after updating to 7.5.x

> storybook build

@storybook/cli v7.5.2

info => Cleaning outputDir: /storybook-static
(node:39475) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './package.json' is not defined by "exports" in ./node_modules/storybook-addon-performance/package.json
    at exportsNotFound (node:internal/modules/esm/resolve:294:10)
    at packageExportsResolve (node:internal/modules/esm/resolve:641:9)
    at resolveExports (node:internal/modules/cjs/loader:585:36)
    at Module._findPath (node:internal/modules/cjs/loader:662:31)
    at Module._resolveFilename (node:internal/modules/cjs/loader:1124:27)
    at Function.resolve (node:internal/modules/helpers:188:19)
    at getAbsolutePath (./.storybook/main.ts:84:26)
    at Object.<anonymous> (./.storybook/main.ts:19:5)
    at Module._compile (node:internal/modules/cjs/loader:1369:14)
    at Module._compile (/Users/andrew/workspace/design-system/node_modules/.pnpm/[email protected][email protected]/node_modules/esbuild-register/dist/node.js:2258:26)
 ELIFECYCLE  Command failed with exit code 1.

Issue with version 0.17.1 and Storybook 6 and react.js 18

This issue is the evolution of the issue #132

With these libs :

    "react": "^18.2.0",
    "react-dom": "^18.2.0",

    "@storybook/addon-a11y": "^6.5.16",
    "@storybook/addon-actions": "^6.5.16",
    "@storybook/addon-essentials": "^6.5.16",
    "@storybook/addon-interactions": "^6.5.16",
    "@storybook/addon-links": "^6.5.16",
    "@storybook/addons": "^6.5.16",
    "@storybook/builder-webpack5": "^6.5.16",
    "@storybook/manager-webpack5": "^6.5.16",
    "@storybook/mdx2-csf": "^0.0.3",
    "@storybook/react": "^6.5.16",
    "@storybook/theming": "^6.5.16",
    "storybook-addon-performance": "^0.17.1",

and this config in main.ts :

   addons: [
     { name: '@storybook/addon-a11y' },
     { name: '@storybook/addon-essentials',   
     { 
       name: '@storybook/addon-essentials',
       options: { backgrounds: false },
     },
     { name: '@storybook/addon-interactions' },
     { name: '@storybook/addon-links' },
     { name: 'storybook-addon-performance' },
   ],

and this config in preview.tsx :

import { withPerformance } from 'storybook-addon-performance';

...

export const decorators = [
  (Story: FC): JSX.Element => {
    return (
      <ThemeProvider>
        <Story />
      </ThemeProvider>
    );
  },
  withPerformance
];

making the Storybook server up and running has no errors occurring, but the Performance addon is not appearing on the addons section.

other ideas?

is it related to this #108 and #117 ?

Support React 17.x

With NPM 7 preventing installs by default for incompatible package numbers, package.json should probably be updated. Given how the plugin functions, my guess is there's issues with the few breaking changes in React 17. Thanks!

Invalid hook call due to multiple versions of React

I am using the add-on and got "Invalid hook call." React error. After some digging, I realize the storybook-addon-performance installs and uses React 6.12.0 despite that the React peer dependency is set to ^16.8.0. So since if my app uses version other than 16.12.0, this error will occur.

Issue with version 0.17.0 and Storybook 6 and react.js 18

With these configuration

    "react": "^18.2.0",
    "react-dom": "^18.2.0",

    "@storybook/addon-a11y": "^6.5.14",
    "@storybook/addon-actions": "^6.5.14",
    "@storybook/addon-essentials": "^6.5.14",
    "@storybook/addon-interactions": "^6.5.14",
    "@storybook/addon-links": "^6.5.14",
    "@storybook/addons": "^6.5.14",
    "@storybook/builder-webpack5": "^6.5.14",
    "@storybook/manager-webpack5": "^6.5.14",
    "@storybook/react": "^6.5.14",
    "@storybook/theming": "^6.5.14",
    "storybook-addon-performance": "^0.17.0",

the error that occurs is the following

ModuleNotFoundError: Module not found: Error: Can't resolve 'xstate/lib/utils' in '/Users/MYUSER/Dev/MYAPPLICATION/node_modules/storybook-addon-performance/dist'
Did you mean 'utils.js'?
BREAKING CHANGE: The request 'xstate/lib/utils' failed to resolve only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/Compilation.js:2016:28
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/NormalModuleFactory.js:798:13
    at eval (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:10:1)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/NormalModuleFactory.js:270:22
    at eval (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:9:1)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/NormalModuleFactory.js:434:22
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/NormalModuleFactory.js:116:11
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/NormalModuleFactory.js:670:25
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/NormalModuleFactory.js:855:8
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/NormalModuleFactory.js:975:5
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/neo-async/async.js:6883:13
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/NormalModuleFactory.js:892:17
    at finishResolved (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/Resolver.js:294:11)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/Resolver.js:362:25
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/Resolver.js:434:24
    at eval (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:27:1)
    at done (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/cache/ResolverCachePlugin.js:271:14)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/cache/ResolverCachePlugin.js:177:36
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/HookWebpackError.js:68:3
    at Hook.eval [as callAsync] (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:15:1)
    at Cache.store (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/Cache.js:107:20)
    at ItemCacheFacade.store (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/CacheFacade.js:137:15)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/cache/ResolverCachePlugin.js:173:18
    at jobDone (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/FileSystemInfo.js:1995:5)
    at FileSystemInfo.createSnapshot (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/FileSystemInfo.js:2330:3)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/webpack/lib/cache/ResolverCachePlugin.js:157:21
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/Resolver.js:434:24
    at eval (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:13:1)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/Resolver.js:434:24
    at eval (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:27:1)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/DescriptionFilePlugin.js:88:10
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/Resolver.js:434:24
    at eval (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:27:1)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/Resolver.js:434:24
    at eval (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:13:1)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/Resolver.js:434:24
    at eval (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:57:1)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/ConditionalPlugin.js:54:9
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/Resolver.js:434:24
    at eval (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:13:1)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/forEachBail.js:16:12
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/Resolver.js:434:24
    at eval (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:12:1)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/Resolver.js:434:24
    at eval (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:13:1)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/Resolver.js:434:24
    at eval (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:27:1)
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/DescriptionFilePlugin.js:88:10
    at /Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/lib/Resolver.js:434:24
    at eval (eval at create (/Users/MYUSER/Dev/MYAPPLICATION/node_modules/enhanced-resolve/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:13:1)
resolve 'xstate/lib/utils' in '/Users/MYUSER/Dev/MYAPPLICATION/node_modules/storybook-addon-performance/dist'
  Parsed request is a module
  using description file: /Users/MYUSER/Dev/MYAPPLICATION/node_modules/storybook-addon-performance/package.json (relative path: ./dist)
    Field 'browser' doesn't contain a valid alias configuration
    resolve as module
      /Users/MYUSER/Dev/MYAPPLICATION/node_modules/storybook-addon-performance/dist/node_modules doesn't exist or is not a directory
      looking for modules in /Users/MYUSER/Dev/MYAPPLICATION/node_modules/storybook-addon-performance/node_modules
        /Users/MYUSER/Dev/MYAPPLICATION/node_modules/storybook-addon-performance/node_modules/xstate doesn't exist
      /Users/MYUSER/Dev/MYAPPLICATION/node_modules/node_modules doesn't exist or is not a directory
      looking for modules in /Users/MYUSER/Dev/MYAPPLICATION/node_modules
        existing directory /Users/MYUSER/Dev/MYAPPLICATION/node_modules/xstate
          using description file: /Users/MYUSER/Dev/MYAPPLICATION/node_modules/xstate/package.json (relative path: .)
            using description file: /Users/MYUSER/Dev/MYAPPLICATION/node_modules/xstate/package.json (relative path: ./lib/utils)
              Field 'browser' doesn't contain a valid alias configuration
              /Users/MYUSER/Dev/MYAPPLICATION/node_modules/xstate/lib/utils doesn't exist
      /Users/MYUSER/Dev/node_modules doesn't exist or is not a directory
      /Users/MYUSER/node_modules doesn't exist or is not a directory
      /Users/node_modules doesn't exist or is not a directory
      /node_modules doesn't exist or is not a directory

WARN Broken build, fix the error above.
WARN You may need to refresh the browser.

info => Loading presets
```

Addon is calling examples instead of treating them as components

If I have an example with hooks in it things blow up. This is because you're calling them instead of wrapping them in a React.createElement (or just rendering the JSX).

This can be fixed or at least documented depending on the implications of running the perf checks.


git clone [email protected]:atlassian-labs/compiled-css-in-js.git
cd compiled-css-in-js
yarn
yarn start

then smash the start all button

Feature request: use production bundles for perf testing.

I'm not deeply familiar with where the bundling happens (I think it's storybook) but it would be ideal to do performance measurements using production bundles where process.env.NODE_ENV === 'production'. This would ensure that the perf numbers are running on production React which has quite different characteristics than development.

Is there any way for the addon to create a prod bundle to run against? I am really unsure if this is possible without requiring the author to setup a custom storybook webpack bundle config, but thought I'd bring it up as I've certainly seen huge difference in numbers with that on where things can run in optimized mode.

How to change story args in interaction?

I'd like to do a performance test where the interaction is simply changing the args assigned to the story. From the examples, I see you could do that by using an onClick handler on button with useState, but honestly that seems like a lot of effort for such a simple change.

Any thoughts? Thanks!

Unexpected token export being thrown when running storyshots through jest

Hello!

We are looking to bring this addon into our storybook, as it's already paying off when we're testing stuff out. However when running storyshots, jest is throwing an error of unexpected token export when trying to run storyshots.

Inspecting the error it looks like this is due to the package having the export in index.js which throws the error in jest as i think by default babel does not polyfill node modules.

Below is the error we're hitting and note i cut the path to just the node modules so you're not seeing my horrible directory lol.

C:\node_modules\storybook-addon-performance\dist\index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){export { default as withPerformance } from './decorator/decorator';
 ^^^^^^

SyntaxError: Unexpected token export

Is there anything i can do to help with this? I figure i tell babel to transform this package, but wasn't sure if the library itself can be shipped as es5 to work with jest out of the box.

Panel not showing up

I'm using storybook 6.4.19 and have added the withPerformance decorator globally in preview.js but no panel is added to my storybook. My other decorators and addons are working. I've also added storybook-addon-performance/register to main.js addons.

There's not word on what storybook versions are supported, can you confirm that it should work with 6.4.19 please?
Thank you.

Critical dependency: require function is used in a way in which dependencies cannot be statically extracted

image
//.storybook/main.ts

const config: StorybookConfig = {
    stories: [
        '../storybook/**/*.mdx',
        '../storybook/**/*.story.@(js|jsx|mjs|ts|tsx)'
    ],
    addons: [
        '@storybook/addon-links',
        '@storybook/addon-essentials',
        '@storybook/blocks',
        '@storybook/addon-interactions',
        {
            name: '@storybook/addon-styling',
            options: {}
        },
        '@storybook/addon-a11y',
        '@storybook/addon-designs',
        '@storybook/addon-mdx-gfm',
        'storybook-addon-performance'
    ],
    framework: {
        name: '@storybook/react-webpack5',
        options: {}
    },
    docs: {
        autodocs: 'tag'
    }
};
.storybook/preview.ts
import type { Preview } from '@storybook/react';

import { createGlobalStyle, ThemeProvider } from 'styled-components';
import { withThemeFromJSXProvider } from '@storybook/addon-styling';
import { withPerformance } from 'storybook-addon-performance';
import lightTheme from '../src/constants/defaultThemes/lightThemes';

/* TODO: update import for your custom theme configurations */
// import { lightTheme, darkTheme } from '../path/to/themes';

/* TODO: replace with your own global styles, or remove */
const GlobalStyles = createGlobalStyle`
    body {
      font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    }
  `;

const preview: Preview = {
    parameters: {
        actions: { argTypesRegex: '^on[A-Z].*' },
        controls: {
            matchers: {
                color: /(background|color)$/i,
                date: /Date$/
            }
        }
    },

    decorators: [
        // Adds global styles and theme switching support.
        withThemeFromJSXProvider({
            /* Uncomment for theme switching support */
            themes: {
                light: lightTheme
            },
            defaultTheme: 'light',
            Provider: ThemeProvider,
            GlobalStyles
        }),
        withPerformance
    ]
};

The contrast ratio between foreground and background color of Start button in “Performance pane is 2.647:1 which is less than required ratio 4.5:1

Test Environment:
OS: Windows 11
OS version: 23H2 (OS Build 25393.1000)
Edge Version: 114.0.1823.51 (Official build) (64-bit)

Repro steps:

  1. Open URL: Common Navigation - Scrolling Panel ⋅ Storybook (windows.net) with valid credentials.
  2. Navigate to “App bar” button at right side of the pane invoke it and navigate to “Default” link invoke it.
  3. Now navigate to “Performance” tab item invoke it now apply color contrast for Start button and observe the issue.

Actual Result:
The contrast ratio between foreground and background colors of Start button in “Performance pane is 2.647:1 which is less than required ratio 4.5:1.

Expected Result:
Ensure contrast ratio between foreground and background colors should meets the WCAG 2AA contrast ratio threshold i.e., 4.5:1.

Attachments:

Start button2

Start button

import / export pins

It would be great to be able to export pinned values, and then later import them. This would allow for long term saving as well as sharing.

Currently, we cannot do this with the URL because of an issue with storybook: storybookjs/storybook#8600

We might have to use the file API for now

Address feedback from #59

59 was merged before some maintainers got a full review in. Need to revisit some of the comments.

See #59 for more details.

Needs transpiling downstream with latest Storybook 6

It looks like we have to transpile this downstream in order to get it to play nice with IE/Edge.

Does it make sense to publish a transpiled build of the package so that consumers don't need to manually tweak their storybook config to do so?

If someone has managed to transpile this addon downstream as part of their storybook build it would be greatly appreciated if you could share some config with us - we are struggling to get this to work.

Failed to build the addon with preact

Hi,
Happy new year!
Thanks for providing the tool for react.
When I build a story book based on preact and this addon as a decoractor, I'm seeing a lot of compilation errors like the following.
ModuleDependencyError: Can't reexport the named export 'renderToString' from non EcmaScript module (only default export is available)
at Compilation.reportDependencyErrorsAndWarnings (/Users/kniu/code/jet/jet/packages/playgrounds/jwaldman/node_modules/webpack/lib/Compilation.js:1468:21)
at /Users/kniu/code/jet/jet/packages/playgrounds/jwaldman/node_modules/webpack/lib/Compilation.js:1258:10
at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/kniu/code/jet/jet/packages/playgrounds/jwaldman/node_modules/tapable/lib/HookCodeFactory.js:33:10), :22:1)
at AsyncSeriesHook.lazyCompileHook (/Users/kniu/code/jet/jet/packages/playgrounds/jwaldman/node_modules/tapable/lib/Hook.js:154:20)
at Compilation.finish (/Users/kniu/code/jet/jet/packages/playgrounds/jwaldman/node_modules/webpack/lib/Compilation.js:1253:28)
at /Users/kniu/code/jet/jet/packages/playgrounds/jwaldman/node_modules/webpack/lib/Compiler.js:672:17
at _done (eval at create (/Users/kniu/code/jet/jet/packages/playgrounds/jwaldman/node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)
at eval (eval at create (/Users/kniu/code/jet/jet/packages/playgrounds/jwaldman/node_modules/tapable/lib/HookCodeFactory.js:33:10), :32:22)
at /Users/kniu/code/jet/jet/packages/playgrounds/jwaldman/node_modules/webpack/lib/Compilation.js:1185:12
If I change the way webpack handles mjs file in node_modules folder, compilation succeeds. But index.html of storybook is not generated, so the website cannot be loaded.
I added this in my preview.js to handle mjs files in node_modules.
module.exports.webpackFinal = async config => {
const newMjsRule = {
test: /.mjs$/,
include: /node_modules/,
type: 'javascript/auto'
}
config.module.rules = [newMjsRule, ...config.module.rules];
return config;
}
I'm using storybook 6.3.
So my question is if there is a way to make this addon working with preact.

Thanks

Panel not showing up

I'm using storybook 6.4.19 and have added the withPerformance decorator globally in preview.js but no panel is added to my storybook. My other decorators and addons are working. I've also added storybook-addon-performance/register to main.js addons.

There's not word on what storybook versions are supported, can you confirm that it should work with 6.4.19 please?
Thank you.

Bug : Does not work for storybook 6

For storybook 6, as mentioned in the migration doc, adding this addon in main.js, shows performance tab in stories but clicking on Start all disables this button and there are no results that are shown

Invariant Violation: ReactDOMServer does not yet support Suspense.

I have a component that uses Suspense for code-splitting. I'm not using server-side rendering. When I try to use this add-on, it throws this error

Uncaught (in promise) Invariant Violation: ReactDOMServer does not yet support Suspense.
    at http://127.0.0.1:9009/vendors~main.b2ffbf23a08dd009f236.bundle.js:241387:38
    at ReactDOMServerRenderer.render (http://127.0.0.1:9009/vendors~main.b2ffbf23a08dd009f236.bundle.js:241390:17)
    at ReactDOMServerRenderer.read (http://127.0.0.1:9009/vendors~main.b2ffbf23a08dd009f236.bundle.js:241223:29)
    at Object.renderToString (http://127.0.0.1:9009/vendors~main.b2ffbf23a08dd009f236.bundle.js:241782:27)
    at Object.run (http://127.0.0.1:9009/vendors~main.b2ffbf23a08dd009f236.bundle.js:303094:80)
    at http://127.0.0.1:9009/vendors~main.b2ffbf23a08dd009f236.bundle.js:302708:98
    at mark (http://127.0.0.1:9009/vendors~main.b2ffbf23a08dd009f236.bundle.js:302567:26)
    at http://127.0.0.1:9009/vendors~main.b2ffbf23a08dd009f236.bundle.js:302708:75
    at withContainer (http://127.0.0.1:9009/vendors~main.b2ffbf23a08dd009f236.bundle.js:302831:26)
    at runStaticTask (http://127.0.0.1:9009/vendors~main.b2ffbf23a08dd009f236.bundle.js:302707:89)

An example component that should reproduce this:

// Example/index.js
import React, { Suspense, lazy } from "react";

const LazyExample = lazy(() => import("./Example"));

const Example = props => (
  <Suspense fallback={null}>
    <LazyExample {...props} />
  </Suspense>
);

export default Example;

// Example/Example.js
import React from "react";

const Example = () => <div>Hello, World!</div>

export default Example;

Is there a way to disable the server-side rendering?

Support React 18.x

Hello there,
we want to use this plugin but our project runs on [email protected]
Are there any plans to update dependencies (merge PRs) and release a new version with React 18 support?

Panel not showing up

I'm using storybook 6.4.19 and have added the withPerformance decorator globally in preview.js but no panel is added to my storybook. My other decorators and addons are working. I've also added storybook-addon-performance/register to main.js addons.

There's not word on what storybook versions are supported, can you confirm that it should work with 6.4.19 please?
Thank you.

Feature request: Warn users using metric thresholds

How we can provide better guidance to developers who usually don't work on performance? Here's an idea:

  • Allow setting a threshold for each metric to educate developers about what’s acceptable (e.g. 50ms for mounting a component)
  • If a threshold is exceeded, the metric should clearly stick out (see mockup below)
  • Developers should be able to override the default threshold for each metric

Render times and other metrics can change between runs and machines, and so does the performance in the real world! Calculating the rendering time of a component that runs on a development version of React and on a developer machine might be closer to the performance of components running on real world slow devices in production mode.

Therefore, the threshold should be met even on slow machines and when running uncompressed code.

Panel not showing up

I'm using storybook 6.4.19 and have added the withPerformance decorator globally in preview.js but no panel is added to my storybook. My other decorators and addons are working. I've also added storybook-addon-performance/register to main.js addons.

There's not word on what storybook versions are supported, can you confirm that it should work with 6.4.19 please?
Thank you.

Storybook story source shows <TaskHarness ... /> instead of actual code

Summary

The Story source does not show correct source code of the component with this addon. Instead all stories show with:

<TaskHarness
    channel={[object Object]}
    getNode={function noRefCheck() {}}
    interactions={undefined}
/>

Currently I add the this addon in the config with addDecorator(withPerformance) as recommended. Is there something that I am missing in terms of implementation whether it be with the stories or how I add this addon?

Usage recommendation: dev server vs static build

Thanks for creating this awesome add-on! 🙌🏻

Question on recommended usage: is this designed to be run only off a static Storybook build, so that the production version of React is used? The React docs recommend doing perf benchmarking when using the minified prod build (not the dev server) so I'm wondering if that applies here too. Thanks for any insight.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.