Skip to content

Commit 42906cb

Browse files
committed
ci: add current package benchmark gate
1 parent 3da58b6 commit 42906cb

9 files changed

Lines changed: 518 additions & 1 deletion

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tailwindcss-config": patch
3+
---
4+
5+
修复发布产物的 ESM 入口文件名与 `package.json` 导出声明不一致的问题,确保依赖已发布 `weapp-tailwindcss` 的 benchmark 工作区可以正确加载 Tailwind 配置工具包。

.github/workflows/benchmark.yml

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
name: Benchmark
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened, ready_for_review]
6+
push:
7+
branches:
8+
- main
9+
- alpha
10+
- beta
11+
- rc
12+
- next
13+
workflow_dispatch:
14+
inputs:
15+
baseline:
16+
description: npm 发布基线;auto 会按当前包版本推断 next/beta/rc/latest
17+
required: false
18+
default: auto
19+
build_runs:
20+
description: 每个项目的 build 采样次数
21+
required: false
22+
default: '3'
23+
hmr_runs:
24+
description: 每个项目的 HMR 采样次数
25+
required: false
26+
default: '5'
27+
only:
28+
description: 可选:只跑指定项目 key,多个 key 用逗号分隔
29+
required: false
30+
default: ''
31+
32+
concurrency:
33+
group: benchmark-${{ github.event.pull_request.number || github.ref }}
34+
cancel-in-progress: true
35+
36+
permissions:
37+
contents: read
38+
39+
jobs:
40+
current-vs-published:
41+
name: Current vs published weapp-tailwindcss
42+
runs-on: ubuntu-latest
43+
timeout-minutes: 180
44+
env:
45+
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
46+
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
47+
WEAPP_TW_BENCH_BASELINE: ${{ github.event.inputs.baseline || 'auto' }}
48+
BENCH_BUILD_RUNS: ${{ github.event.inputs.build_runs || '3' }}
49+
BENCH_HMR_RUNS: ${{ github.event.inputs.hmr_runs || '5' }}
50+
BENCH_ONLY: ${{ github.event.inputs.only || '' }}
51+
52+
steps:
53+
- name: Check out code
54+
uses: actions/checkout@v6
55+
with:
56+
fetch-depth: 2
57+
58+
- uses: pnpm/action-setup@v4
59+
60+
- name: Setup Node.js environment
61+
uses: actions/setup-node@v6
62+
with:
63+
node-version: 22
64+
cache: pnpm
65+
cache-dependency-path: pnpm-lock.yaml
66+
67+
- name: Install dependencies
68+
run: pnpm install --frozen-lockfile
69+
70+
- name: Run current vs published benchmark
71+
run: >
72+
pnpm bench:ci --
73+
--build-runs "$BENCH_BUILD_RUNS"
74+
--hmr-runs "$BENCH_HMR_RUNS"
75+
--timeout 180000
76+
--poll-interval 120
77+
--only "$BENCH_ONLY"
78+
--result-dir .tmp/benchmark-ci/result
79+
80+
- name: Upload benchmark artifacts
81+
if: always()
82+
uses: actions/upload-artifact@v4
83+
with:
84+
name: benchmark-current-vs-published
85+
path: .tmp/benchmark-ci/result/**
86+
if-no-files-found: error
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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

Comments
 (0)