性能

一个 Storybook 附加组件,帮助更好地理解和调试 React 组件的性能

在 Github 上查看

一个 storybook 附加组件,帮助更好地理解和调试 React 组件的性能

📺 项目概述 by Jack Herrington

亮点 🌟

  • 零配置(除了交互):无需任何配置即可生成与服务器端渲染和客户端挂载相关的性能信息
  • 固定结果:您可以运行一些任务,固定结果,进行一些更改,重新运行任务并查看发生了哪些变化
  • 保存/加载结果:您可以运行一些任务,将结果保存为本地工件,并在以后通过将工件加载回附加组件中来再次运行它们。
  • 交互:添加您自己的自定义用户交互作为故事的参数运行。这使您可以计时交互需要多长时间。此 API 非常灵活且强大!
  • 控制:运行所有任务以获取概述,或运行单个任务以深入了解特定问题
  • 标记:所有任务都使用 用户计时 API 标记,以便在浏览器的性能分析器中轻松调试单个任务

安装

  1. 安装 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. .storybook/main.js 中注册附加组件
module.exports = {
  addons: ['storybook-addon-performance'],
};
  1. 添加装饰器

您可以在 .storybook/preview.js 中将装饰器全局添加到每个故事中(推荐)

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

export const decorators = [withPerformance];

或者您也可以将其添加到单个故事中

使用 组件故事格式 (CSF)

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

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

使用 StoriesOf API

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

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

用法:交互

交互任务是一种可以在每个故事的基础上定义和运行的任务类型。它们对于计时组件的交互性能很有用。

要定义您的交互任务,首先创建一个对象数组,每个对象都包含任务的 namedescription(可选),以及一个 run 函数,该函数执行您想要衡量的任何任务

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 });
    },
  },
];

每个任务对象中的 run 函数接受两个参数

  • container:包含故事组件渲染实例的 HTMLElement 容器

  • controls:包含一个异步计时函数,可以根据需要调用它来指定何时开始和结束测量;否则,将测量完成整个 run 函数所需的时间。当任务涉及一些设置工作时很有用。

    要使用它,请将有问题的操作包装在 controls.time 中,如下所示

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

请注意,您可以使用任何您喜欢的库来执行这些交互测试 - 上面的示例使用 @testing-library/dom 在示例中打开选择并等待特定项目。

然后,您可以将交互任务数组包含在故事的 performance 参数中,键为 interactions

// Using the Component Story Format (CSF)
// https://storybook.org.cn/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,
  },
};

提供的类型

如上所示,插件导出两个类型定义,以帮助您创建自己的交互任务

  • PublicInteractionTask:定义交互任务的对象结构;将这些任务的数组作为参数传递给 storybook,如上所示。
  • InteractionTaskArgs:交互任务的 run 函数的参数

用法:保存和加载结果

您可以使用 Save API 将性能任务的结果保存为本地工件。Save API 创建一个特定于故事的工件,然后可以在以后加载,用作基准。这对于 CI 或测试分支中的更改与主干相比很有用。您可以通过 UI 中的“保存结果”/“加载结果”按钮使用此 API。

此 API 的一些注意事项

  • Storybook 运行性能结果是可变的,并且可能会根据运行测试时的 CPU 利用率/内存而改变。如果您打算保存工件,请确保您在尽可能类似于原始运行环境的环境中重新运行/比较结果。
  • 为了使此 API 正确工作,任务工件应基于与原始测试相同的样本/副本数量。

为了获得更一致的结果,我们建议使用 10 个副本/10 个样本来记录工件。

用法:过滤任务组

有些组件不是为在服务器端渲染中或在客户端中工作而设计的。为了支持这一点,我们创建了一个允许列表,您可以根据需要将其传递进来,只允许您想要运行的组。要配置此选项,请将 allowedGroups 选项设置为故事参数的一部分。

  • 默认值:['server', 'client'](运行所有内容)
// Using [Component Story Format (CSF)](https://storybook.org.cn/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'],
  },
};

关于性能指标的说明 💡

为了获得尽可能准确的性能指标,您应该使用 Storybook 的生产版本。有关更多背景信息,请参阅 React 的 优化性能文档

虽然此附加组件适用于开发版本,但您会看到结果变化更大。

本地附加组件开发

在 storybook-addon-performance 文件夹中 (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

感谢

由您在 Atlassian 的朋友们制作 ❤️

With ❤️ from Atlassian

由以下人员制作
  • alexreardon
    alexreardon
  • darkpurple141
    darkpurple141
  • harshai
    harshai
  • andrewcampbell
    andrewcampbell
标签