一个 storybook 插件,帮助更好地理解和调试React
组件的性能
亮点 🌟
- 零配置(交互除外):无需任何配置即可生成与服务器端渲染和客户端挂载相关的性能信息
- 固定结果:您可以运行一些任务,固定结果,进行一些更改,重新运行任务并查看更改内容
- 保存/加载结果:您可以运行一些任务,将结果保存为本地工件,并在稍后通过将工件加载回插件来再次运行它们。
- 交互:添加您自己的自定义用户交互作为故事的参数运行。这使您可以计时交互需要多长时间。此 API 非常灵活且强大!
- 控制:运行所有任务以获得概述,或运行单个任务以深入了解特定问题
- 标记:所有任务都使用用户计时 API进行标记,以便轻松调试浏览器性能分析器中的单个任务
安装
- 安装
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
- 在
.storybook/main.js
中注册插件
module.exports = {
addons: ['storybook-addon-performance'],
};
- 添加装饰器
您可以将装饰器全局添加到.storybook/preview.js
中的每个故事(推荐)
import { withPerformance } from 'storybook-addon-performance';
export const decorators = [withPerformance];
或者您可以将其添加到各个故事中
import MyComponent from './MyComponent';
import { withPerformance } from 'storybook-addon-performance';
export default {
title: 'MyComponent',
component: MyComponent,
decorators: [withPerformance],
};
import MyComponent from './MyComponent';
import { withPerformance } from 'storybook-addon-performance';
storiesOf('MyComponent', module)
.addDecorator(withPerformance)
.add('MyComponent', () => <MyComponent />);
用法:交互
交互任务是一种可以在每个故事的基础上定义和运行的任务类型。它们对于计时组件的交互性能很有用。
要定义交互任务,首先创建一个对象数组,每个对象包含任务的name
和description
(可选),以及一个执行您想要衡量任何任务的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
函数的参数
用法:保存和加载结果
您可以使用保存 API 将性能任务的结果保存为本地工件。保存 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的朋友们倾情打造 ❤️
- Alex Reardon @alexandereardon
- Andrew Campbell @andrewcampb_ll
- Daniel Del Core @danieldelcore
- Alex Hinds @DarkPurple141