|
| 1 | +function toNumber(value) { |
| 2 | + return typeof value === 'number' && Number.isFinite(value) ? value : 0 |
| 3 | +} |
| 4 | + |
| 5 | +function pct(from, to) { |
| 6 | + return from ? ((to - from) / from) * 100 : 0 |
| 7 | +} |
| 8 | + |
| 9 | +function fmtMs(value) { |
| 10 | + return toNumber(value).toFixed(2) |
| 11 | +} |
| 12 | + |
| 13 | +function fmtPct(value) { |
| 14 | + const n = toNumber(value) |
| 15 | + return `${n >= 0 ? '+' : ''}${n.toFixed(2)}%` |
| 16 | +} |
| 17 | + |
| 18 | +function metric(row, kind) { |
| 19 | + return toNumber(row?.summary?.[`${kind}Steady`]?.median ?? row?.summary?.[kind]?.median) |
| 20 | +} |
| 21 | + |
| 22 | +function average(values) { |
| 23 | + return values.length ? values.reduce((sum, value) => sum + value, 0) / values.length : 0 |
| 24 | +} |
| 25 | + |
| 26 | +function normalizePackageSpec(value) { |
| 27 | + if (value.startsWith('weapp-tailwindcss@')) { |
| 28 | + return value |
| 29 | + } |
| 30 | + return `weapp-tailwindcss@${value}` |
| 31 | +} |
| 32 | + |
| 33 | +export function buildSummary(raw, baselineLabel, currentLabel) { |
| 34 | + const rows = raw.rows ?? [] |
| 35 | + const byKey = new Map(rows.map(row => [`${row.version}::${row.key}`, row])) |
| 36 | + const currentRows = rows.filter(row => row.version === currentLabel) |
| 37 | + const compares = currentRows.map((current) => { |
| 38 | + const baseline = byKey.get(`${baselineLabel}::${current.key}`) |
| 39 | + const baselineBuild = metric(baseline, 'build') |
| 40 | + const currentBuild = metric(current, 'build') |
| 41 | + const baselineHmr = metric(baseline, 'hmr') |
| 42 | + const currentHmr = metric(current, 'hmr') |
| 43 | + return { |
| 44 | + key: current.key, |
| 45 | + project: current.project, |
| 46 | + baselineBuild, |
| 47 | + currentBuild, |
| 48 | + buildDeltaPct: pct(baselineBuild, currentBuild), |
| 49 | + baselineHmr, |
| 50 | + currentHmr, |
| 51 | + hmrDeltaPct: pct(baselineHmr, currentHmr), |
| 52 | + baselineError: baseline?.error, |
| 53 | + currentError: current.error, |
| 54 | + } |
| 55 | + }) |
| 56 | + const errors = rows.filter(row => row.error).map(row => ({ |
| 57 | + version: row.version, |
| 58 | + key: row.key, |
| 59 | + error: row.error, |
| 60 | + })) |
| 61 | + const validCompares = compares.filter(item => !item.baselineError && !item.currentError) |
| 62 | + return { |
| 63 | + generatedAt: raw.generatedAt, |
| 64 | + options: raw.options, |
| 65 | + baseline: baselineLabel, |
| 66 | + current: currentLabel, |
| 67 | + compares, |
| 68 | + errors, |
| 69 | + averages: { |
| 70 | + buildDeltaPct: average(validCompares.map(item => item.buildDeltaPct)), |
| 71 | + hmrDeltaPct: average(validCompares.map(item => item.hmrDeltaPct)), |
| 72 | + }, |
| 73 | + } |
| 74 | +} |
| 75 | + |
| 76 | +export function toMarkdown(summary, baselineSpec) { |
| 77 | + const rows = summary.compares.map((item) => { |
| 78 | + const note = [item.baselineError && 'baseline error', item.currentError && 'current error'].filter(Boolean).join(', ') |
| 79 | + return `| ${item.key} | ${fmtMs(item.baselineBuild)} | ${fmtMs(item.currentBuild)} | ${fmtPct(item.buildDeltaPct)} | ${fmtMs(item.baselineHmr)} | ${fmtMs(item.currentHmr)} | ${fmtPct(item.hmrDeltaPct)} | ${note || '-'} |` |
| 80 | + }).join('\n') |
| 81 | + const errors = summary.errors.length |
| 82 | + ? summary.errors.map(item => `- ${item.version} / ${item.key}: ${String(item.error).split('\n')[0]}`).join('\n') |
| 83 | + : '- 无' |
| 84 | + |
| 85 | + return `# weapp-tailwindcss 当前版本 vs 发布版本 Benchmark |
| 86 | +
|
| 87 | +生成时间:${summary.generatedAt} |
| 88 | +
|
| 89 | +## 基线 |
| 90 | +
|
| 91 | +- 当前版本:${summary.current} |
| 92 | +- 发布基线:${summary.baseline}(${normalizePackageSpec(baselineSpec)}) |
| 93 | +- 样本参数:build ${summary.options.buildRuns} 次,hmr ${summary.options.hmrRuns} 次,timeout ${summary.options.timeoutMs}ms |
| 94 | +
|
| 95 | +## 汇总 |
| 96 | +
|
| 97 | +- Build 稳态中位数平均变化:${fmtPct(summary.averages.buildDeltaPct)} |
| 98 | +- HMR 稳态中位数平均变化:${fmtPct(summary.averages.hmrDeltaPct)} |
| 99 | +- 失败项:${summary.errors.length} |
| 100 | +
|
| 101 | +## 项目矩阵 |
| 102 | +
|
| 103 | +| 项目 | Baseline Build(ms) | Current Build(ms) | Build 变化 | Baseline HMR(ms) | Current HMR(ms) | HMR 变化 | 备注 | |
| 104 | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | --- | |
| 105 | +${rows} |
| 106 | +
|
| 107 | +## 失败项 |
| 108 | +
|
| 109 | +${errors} |
| 110 | +` |
| 111 | +} |
0 commit comments