diff --git a/pages/benchmark.tsx b/pages/benchmark.tsx new file mode 100644 index 0000000..55271bb --- /dev/null +++ b/pages/benchmark.tsx @@ -0,0 +1,288 @@ +import React from 'react'; +import Head from 'next/head'; +import NextLink from 'next/link'; +import { Badge, Box, Container, Text, Link, Button } from '@modulz/design-system'; +import { StitchesLogo } from '../components/StitchesLogo'; +import { TitleAndMetaTags } from '../components/TitleAndMetaTags'; +import { format } from 'date-fns'; + +function collectBenchesPerTestCase(entries) { + const map = new Map(); + for (const entry of entries) { + const { commit, date, tool, benches } = entry; + for (const bench of benches) { + const result = { commit, date, tool, bench }; + const arr = map.get(bench.name); + if (arr === undefined) { + map.set(bench.name, [result]); + } else { + arr.push(result); + } + } + } + return map; +} + +const fontFamily = 'Untitled Sans, -apple-system, BlinkMacSystemFont, system-ui, sans-serif'; + +export default function BenchmarkPage({ data, ...props }) { + if (!data) { + return null; + } + + const dataSets = Object.keys(data.entries).map((name) => ({ + name, + dataSet: collectBenchesPerTestCase(data.entries[name]), + })); + + React.useEffect(() => { + // Global Chart.js overrides + (window as any).Chart.defaults.global.defaultFontFamily = fontFamily; + (window as any).Chart.defaults.global.animation.duration = 0; + }, []); + + return ( + + + + + + + + + + Stitches homepage + + + + + + + + Stitches Benchmarks + + + + Updated: {format(data.lastUpdate, 'dd/MM/yy')} at {format(data.lastUpdate, 'HH:mm')}{' '} + {format(data.lastUpdate, 'O')} + + + {dataSets.map(({ name, dataSet }) => ( + + ))} + + + Repository: {data.repoUrl} + + + + + + ); +} + +function Bench(props: any) { + return ( + <> + {[...props.dataSet.entries()].map(([name, data], i) => ( + + ))} + + ); +} + +function Chart({ dataSet, name }: any) { + const canvasRef = React.useRef(null); + + React.useEffect(() => { + const data = { + labels: dataSet.map((d) => d.commit.id.slice(0, 7)), + datasets: [ + { + label: name, + data: dataSet.map((d) => d.bench.value), + + borderColor: 'hsl(252,80%,70%)', + backgroundColor: 'hsla(252,80%,70%, 0.2)', + pointBackgroundColor: 'hsl(252,80%,70%)', + pointBorderColor: 'white', + pointRadius: 5, + pointHoverRadius: 5, + pointHitRadius: 3, + }, + ], + }; + const options = { + global: { + defaultFontFamily: fontFamily, + }, + hover: { + animationDuration: 0, + }, + scales: { + xAxes: [ + { + gridLines: { + color: 'hsla(252,80%,70%, 0.4)', + zeroLineColor: 'hsla(252,80%,70%, 0.4)', + }, + scaleLabel: { + display: true, + labelString: 'commit', + }, + }, + ], + yAxes: [ + { + gridLines: { + color: 'hsla(252,80%,70%, 0.4)', + zeroLineColor: 'hsla(252,80%,70%, 0.4)', + }, + scaleLabel: { + display: true, + labelString: dataSet.length > 0 ? dataSet[0].bench.unit : '', + }, + ticks: { + beginAtZero: true, + }, + }, + ], + }, + tooltips: { + displayColors: false, + xPadding: 15, + yPadding: 15, + titleFontFamily: fontFamily, + bodyFontFamily: fontFamily, + footerFontFamily: fontFamily, + titleSpacing: 5, + titleMarginBottom: 10, + bodySpacing: 5, + bodyMarginBottom: 0, + cornerRadius: 5, + callbacks: { + afterTitle: (items) => { + const { index } = items[0]; + return dataSet[index].commit.message; + }, + label: (item) => { + let label = item.value; + const { range, unit } = dataSet[item.index].bench; + label += ' ' + unit; + if (range) { + label += ' (' + range + ')'; + } + return label; + }, + afterLabel: (item) => { + const { extra } = dataSet[item.index].bench; + return extra ? extra : ''; + }, + }, + }, + onClick: (_mouseEvent, activeElems) => { + if (activeElems.length === 0) { + return; + } + const index = activeElems[0]._index; + const url = dataSet[index].commit.url; + window.open(url, '_blank'); + }, + }; + + new (window as any).Chart(canvasRef.current, { + type: 'line', + data, + options, + }); + }, [dataSet]); + + return ( + + + + ); +} + +const RAW_GITHUB_URL = 'https://raw.githubusercontent.com'; + +function getErrorText(res) { + try { + return res.text(); + } catch (err) { + return res.statusText; + } +} + +export async function getError(msg, res) { + const errorText = await getErrorText(res); + const error = new Error(`${msg} (${res.status}): ${errorText}`) as any; + + error.url = res.url; + error.status = res.status; + error.headers = res.headers.raw(); + + return error; +} + +async function getRawFileFromGitHub(path) { + const res = await fetch(RAW_GITHUB_URL + path); + + if (res.ok) return res.text(); + throw await getError('GitHub raw download error', res); +} + +export async function getStaticProps(context) { + // raw.githubusercontent.com/jonathantneal/stitches/gh-pages/dev/bench/data.js + const rawData = await getRawFileFromGitHub(`/jonathantneal/stitches/gh-pages/dev/bench/data.js`); + const data = rawData.replace('window.BENCHMARK_DATA = ', ''); + return { + props: { + data: JSON.parse(data), + }, + }; +}