CI: Track SWC native binary size in PR stats comment (#92938)
### What?
Adds a new "Native Binary" section to the `Stats from current PR`
comment posted by the `generate-pull-request-stats` GitHub Action. The
section reports the size of the SWC native binary
(`packages/next-swc/native/*.node`) built for the PR and the change
relative to the latest value recorded on `canary`.
Example row:
> | Metric | Canary | PR | Change | Trend |
> |:-------|-------:|---:|-------:|:-----:|
> | SWC Binary Size | 113 MB | 121 MB | 🔴 +7.34 MB (+6%) | ▁▃▅▇█ |
### Why?
The `.node` binary is a sizable, user-facing artifact (it ships with
`next`). Today there's no visibility on its size in PRs, so regressions
from Rust/Cargo changes are easy to miss. Surfacing the size (and a diff
vs. canary) in the existing stats comment gives immediate feedback on
any change that affects the binary.
### How?
- **Measurement
(`.github/actions/next-stats-action/src/run/index.js`):** After the
action copies the pre-built native binary into the working dirs, sum the
size of every `*.node` file under the action's `native/` directory and
store it as `General.swcBinarySize` on both the canary and PR stat sets.
- **Canary baseline via KV history
(`.github/actions/next-stats-action/src/add-comment.js`):** The workflow
downloads a single pre-built binary and copies it into both the canary
and PR checkouts, so an in-run diff would always be zero. Instead, for
PR runs we override `mainRepoStats.General.swcBinarySize` with the most
recent `swcBinarySize` from the Vercel KV history (the same store
already used for other canary metrics). Canary runs keep the measured
value, and the existing persistence path (`saveToHistory` / `General`)
writes it back so future PRs see an updated baseline. If no history
exists yet, the Canary column renders `N/A` and no change is shown.
- **Rendering:** New `generateNativeBinarySection` emits a
`<details>`-wrapped section styled like Bundle Sizes / All Metrics,
rendered right after the Bundle Sizes block. It reuses `prettify`,
`formatChange`, and `generateTrendBar` so formatting, thresholds, and
sparklines are consistent with the rest of the comment. A tight
threshold entry (`swcBinarySize: { absoluteMin: 10 KB, percentMin: 0.5%,
percentOnly: 0.05% }`) is added so meaningful movement is flagged while
tiny determinism noise is ignored.
- **Top-line summary:** Because `swcBinarySize` lives on `General`, the
existing `generateChangeSummary` automatically promotes significant
changes into the headline regression/improvement table at the top of the
comment, using the label `SWC Binary Size`.
- **Sharded runs:** The workflow runs two sharded jobs (Webpack and
Turbopack). The binary is bundler-independent, so both shards report the
same value; `aggregate-results.js` merges `General` via `Object.assign`,
which is correct here (last-writer-wins on an identical value).
No workflow changes are required — the existing `pull_request_stats.yml`
already downloads the `next-swc-binary` artifact and copies it into the
action's `native/` directory.
### Verification
Smoke-tested `add-comment.js` locally with `LOCAL_STATS=1` in two
scenarios:
- No KV history configured → Canary column renders `N/A`, PR value
renders, Change is `-`, section still shown.
- Mocked KV history containing prior `swcBinarySize` values → full diff
rendered in both the Native Binary section and the top-level
significance summary, with a sparkline of the last 5 historical entries.
Closes NEXT-
<!-- NEXT_JS_LLM_PR -->
---------
Co-authored-by: Tobias Koppers <sokra@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>