ci(frontend): refresh the bundle-size baseline nightly, not on every push

Persisting a new baseline on every push to master (which happens many
times a day) burns a full production build each time for no benefit a
once-a-day refresh doesn't already cover -- a day-old baseline is fine for
catching relative regressions on PRs. Moves baseline persistence to a new
frontend-bundle-size-nightly.yml (schedule + workflow_dispatch), and
restricts superset-frontend.yml's bundle-size job to pull_request only:
compare-and-alert against the last nightly baseline, never persist.

Also caches webpack's persistent filesystem build cache
(superset-frontend/.temp_cache) across CI runs via actions/cache, keyed on
the same files webpack's own `buildDependencies` invalidates on. Without
this, every PR run would pay the full cold-build cost (several minutes)
instead of the ~20s warm-build cost the cache is supposed to buy --
GH-hosted runners are fresh VMs with nothing carried over between jobs, so
the cache has to be restored explicitly or it does nothing.
This commit is contained in:
Evan Rusackas
2026-07-28 09:38:31 -07:00
parent e1d7e61514
commit f7e29c15d5
2 changed files with 130 additions and 14 deletions

View File

@@ -0,0 +1,100 @@
name: Frontend bundle size (nightly baseline)
# Refreshes the bundle-size baseline that superset-frontend.yml's `bundle-size`
# job compares PRs against. Deliberately NOT triggered on every push to
# master: a day-old baseline is fine for catching relative regressions on
# PRs, and building the production bundle on every one of the many pushes
# master gets per day would burn CI time for no benefit a nightly refresh
# doesn't already cover.
on:
schedule:
- cron: "0 6 * * *"
workflow_dispatch: {}
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true
env:
TAG: apache/superset:bundle-size-nightly-${{ github.run_id }}
permissions:
contents: read
jobs:
refresh-baseline:
runs-on: ubuntu-26.04
timeout-minutes: 30
steps:
- name: "Checkout master"
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: master
- name: Build Docker Image
run: |
docker buildx build \
-t $TAG \
--cache-from=type=registry,ref=apache/superset-cache:3.11-slim-trixie \
--target superset-node-ci \
.
# Same cache the PR-time bundle-size job restores/writes -- webpack's
# persistent filesystem cache turns a warm production build into ~20s
# instead of several minutes. See superset-frontend.yml for the
# matching restore step and why it's keyed this way.
- name: Restore webpack build cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: superset-frontend/.temp_cache
key: >-
webpack-prod-cache-${{ hashFiles('superset-frontend/package-lock.json',
'superset-frontend/babel.config.js', 'superset-frontend/tsconfig.json',
'superset-frontend/webpack.config.js') }}
# Only ever pull the last recorded data point off the cache, keyed by
# run ID -- `restore-keys` prefix-matches the most recently created
# entry. Absent on the very first run ever; benchmark-action starts a
# fresh history in that case.
- name: Restore bundle size history
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: bundle-size-history.json
key: bundle-size-history-${{ github.run_id }}
restore-keys: |
bundle-size-history-
- name: Build production bundle with stats
run: |
mkdir -p ${{ github.workspace }}/superset-frontend/bundle-stats
mkdir -p ${{ github.workspace }}/superset-frontend/.temp_cache
docker run \
-v ${{ github.workspace }}/superset-frontend/bundle-stats:/app/superset-frontend/bundle-stats \
-v ${{ github.workspace }}/superset-frontend/.temp_cache:/app/superset-frontend/.temp_cache \
--rm $TAG \
bash -c \
"npm i && BUNDLE_SIZE_STATS=true npm run build -- --json=bundle-stats/stats.json"
- name: Summarize bundle size
run: |
node superset-frontend/scripts/bundle-size-summary.js \
superset-frontend/bundle-stats/stats.json > bundle-size-summary.json
rm -rf superset-frontend/bundle-stats
# No PR to comment on here, so comment-on-alert is off -- the job
# summary (summary-always) is the only surface for this run.
- name: Update bundle size baseline
uses: benchmark-action/github-action-benchmark@52576c92bccf6ac60c8223ec7eb2565637cae9ba # v1.22.1
with:
tool: customSmallerIsBetter
output-file-path: bundle-size-summary.json
external-data-json-path: bundle-size-history.json
fail-on-alert: false
summary-always: true
- name: Save bundle size history
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: bundle-size-history.json
key: bundle-size-history-${{ github.run_id }}

View File

@@ -196,9 +196,15 @@ jobs:
docker run --rm $TAG bash -c \
"npm run build-storybook && npx playwright install-deps && npx playwright install chromium && npm run test-storybook:ci"
# Compares a PR's own bundle size against the last nightly-recorded
# baseline (see frontend-bundle-size-nightly.yml, which owns actually
# persisting new baselines). PR-only: a push to master doesn't need this
# check re-run against itself, and re-persisting the baseline on every
# push to master -- which happens many times a day -- would burn a full
# production build for no benefit nightly refresh doesn't already cover.
bundle-size:
needs: frontend-build
if: needs.frontend-build.outputs.should-run == 'true'
if: needs.frontend-build.outputs.should-run == 'true' && github.event_name == 'pull_request'
runs-on: ubuntu-26.04
timeout-minutes: 15
permissions:
@@ -219,10 +225,26 @@ jobs:
run: |
zstd -d < docker-image.tar.zst | docker load
# webpack's persistent filesystem cache (superset-frontend/webpack.config.js)
# turns a warm production build into ~20s instead of several minutes,
# but GH-hosted runners are fresh VMs with nothing carried over between
# jobs -- without restoring it explicitly, every single PR would pay
# the full cold-build cost. Keyed on the same files webpack's own
# `buildDependencies` invalidates on, so a stale cache is never used.
- name: Restore webpack build cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: superset-frontend/.temp_cache
key: >-
webpack-prod-cache-${{ hashFiles('superset-frontend/package-lock.json',
'superset-frontend/babel.config.js', 'superset-frontend/tsconfig.json',
'superset-frontend/webpack.config.js') }}
# Only ever pull the last recorded data point off the cache, keyed by
# run ID -- `restore-keys` prefix-matches the most recently created
# entry. Absent on the very first run ever; benchmark-action starts a
# fresh history in that case.
# entry, which is always the latest nightly run. Absent before the
# first nightly run ever happens; benchmark-action starts a fresh
# history in that case.
- name: Restore bundle size history
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
@@ -234,8 +256,10 @@ jobs:
- name: Build production bundle with stats
run: |
mkdir -p ${{ github.workspace }}/superset-frontend/bundle-stats
mkdir -p ${{ github.workspace }}/superset-frontend/.temp_cache
docker run \
-v ${{ github.workspace }}/superset-frontend/bundle-stats:/app/superset-frontend/bundle-stats \
-v ${{ github.workspace }}/superset-frontend/.temp_cache:/app/superset-frontend/.temp_cache \
--rm $TAG \
bash -c \
"npm i && BUNDLE_SIZE_STATS=true npm run build -- --json=bundle-stats/stats.json"
@@ -246,7 +270,9 @@ jobs:
superset-frontend/bundle-stats/stats.json > bundle-size-summary.json
rm -rf superset-frontend/bundle-stats
- name: Track bundle size
# Comparison + alert only -- this job never persists. See
# frontend-bundle-size-nightly.yml for why.
- name: Compare bundle size against nightly baseline
uses: benchmark-action/github-action-benchmark@52576c92bccf6ac60c8223ec7eb2565637cae9ba # v1.22.1
with:
tool: customSmallerIsBetter
@@ -257,13 +283,3 @@ jobs:
alert-threshold: "110%"
fail-on-alert: false
summary-always: true
# Only the trunk's own bundle size becomes the baseline everyone else
# is compared against -- an unmerged PR's numbers (including ones that
# regress on purpose to test something) never get persisted.
- name: Save bundle size history
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: bundle-size-history.json
key: bundle-size-history-${{ github.run_id }}