一个 storybook 插件,用于帮助更好地理解和调试 React
组件的性能
亮点 🌟
- 零配置(交互除外):无需任何配置即可生成与服务器端渲染和客户端挂载相关的性能信息
- 固定结果:您可以运行一些任务,固定结果,进行一些更改,然后重新运行任务并查看变化
- 保存/加载结果:您可以运行一些任务,将结果保存为本地工件,稍后通过将工件加载回插件来再次运行它们。
- 交互:添加您自己的自定义用户交互,作为故事的参数运行。这使您可以测量交互所需的时间。此 API 超级灵活且功能强大!
- 控制:运行所有任务以获得概览,或运行单个任务以深入研究特定问题
- 标记:所有任务都使用 User Timing 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];
或者您可以将其添加到单个故事中
使用 组件故事格式 (CSF)
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
来打开示例中的 select 元素并等待特定项目。
然后,您可以在故事的 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 的朋友们用心制作 ❤️
- Alex Reardon @alexandereardon
- Andrew Campbell @andrewcampb_ll
- Daniel Del Core @danieldelcore
- Alex Hinds @DarkPurple141