@mui/internal-benchmark
v0.0.1
Published
Benchmark utilities for MUI projects. Internal package.
Maintainers
Keywords
Readme
Benchmark
A React component render benchmarking tool built on Vitest and Playwright. Runs benchmarks in a real browser using React's profiling build to capture accurate render durations.
Features
- Measures React component render durations using
React.Profiler - Captures paint metrics via the Element Timing API
- Runs in a real Chromium browser via Playwright
- Uses React's profiling build for accurate production-like measurements
- IQR-based outlier removal for stable results
- Configurable warmup and measurement runs
- JSON results output
Usage
Setup
Create a vitest.config.ts:
import { createBenchmarkVitestConfig } from '@mui/internal-benchmark/vitest';
export default createBenchmarkVitestConfig();Writing benchmarks
Create *.bench.tsx files:
import * as React from 'react';
import { benchmark } from '@mui/internal-benchmark';
function MyComponent() {
return (
<div>
{Array.from({ length: 100 }, (_, i) => (
<span key={i}>{i}</span>
))}
</div>
);
}
benchmark('MyComponent mount', () => <MyComponent />);The second argument is a render function (not an element) — it's called on each iteration to produce a fresh React element.
Interactions
To benchmark re-renders, pass an interaction callback:
benchmark(
'Counter click',
() => <Counter />,
async () => {
document.querySelector('button')?.click();
},
);Paint metrics
By default, every benchmark captures a paint:default metric — the time from iteration start until the browser actually paints the rendered output. This uses the Element Timing API via an invisible sentinel element that the benchmark harness renders automatically.
You can track additional paint metrics by placing <ElementTiming> markers and awaiting them in an interaction callback. The component renders an invisible <span> that fires in the same paint frame as its surrounding content.
import { benchmark, ElementTiming } from '@mui/internal-benchmark';
function MyComponent() {
return (
<div>
<ElementTiming name="my-component" />
{/* ... */}
</div>
);
}
benchmark(
'MyComponent mount',
() => <MyComponent />,
async ({ waitForElementTiming }) => {
await waitForElementTiming('my-component');
},
);This produces a paint:my-component metric alongside the automatic paint:default.
waitForElementTiming accepts an optional timeout in milliseconds (default: 5000). Pass 0 or Infinity to rely on the test timeout instead.
Options
benchmark('name', renderFn, interaction, {
runs: 20, // measurement iterations (default: 20)
warmupRuns: 10, // warmup iterations before measuring (default: 10)
afterEach: () => {
/* cleanup between iterations */
},
});Running
vitest runConfiguration
createBenchmarkVitestConfig accepts:
outputPath— path for JSON results (default:benchmarks/results.json)launchArgs— additional browser launch arguments
To override standard Vitest options (e.g. include, testTimeout, headless), use mergeConfig:
import { mergeConfig } from 'vitest/config';
import { createBenchmarkVitestConfig } from '@mui/internal-benchmark/vitest';
export default mergeConfig(createBenchmarkVitestConfig(), {
test: {
include: ['**/*.perf.tsx'],
},
});API
benchmark— define a benchmark test caseElementTiming— invisible marker component for paint timing (renders a<span>tracked by the Element Timing API)createBenchmarkVitestConfig— create a Vitest config with browser benchmarking defaultsBenchmarkReporter— Vitest reporter that collects and outputs benchmark results
