From 0064b5de3585fbc1503ec49763c6f161b68fd0d9 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 30 Oct 2026 21:51:21 +0000 Subject: [PATCH] CI: run Lighthouse beside the checks, once per URL on pull requests A CI run took about 8.6 minutes, 5.8 of them in Lighthouse (12 URLs x 3 runs) waiting behind the end-to-end tests; 283 runs in the last 30 days. - Lighthouse moves to its own job that builds the site (seconds) and runs in parallel with the checks. Pull requests audit each URL once; main keeps three runs, since its scores become the commit status and a flaky failure there would hold back a deploy. - Playwright's Chromium is cached on the lockfile in ci.yml and screenshots.yml; the lockfile pins the Playwright version and with it the browser build the screenshot baselines depend on. A hit skips the download and the apt run. docs/development.md describes the new shape. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_0175HbpkZkWEk4P8gomAdRTL --- .github/workflows/ci.yml | 33 ++++++++++++++++++++++++++++++- .github/workflows/screenshots.yml | 11 ++++++++++- docs/development.md | 6 ++++-- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc02102..f074976 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,18 @@ jobs: run: pnpm build - name: Byte budgets run: pnpm check:budgets + # Playwright's pinned Chromium, keyed on the lockfile (which pins the Playwright version). + # Screenshot baselines are only valid for this exact build, so the cache can never hand a + # test a different browser than a fresh install would. A hit also skips the apt run of + # --with-deps; the shared libraries are already on the runner image. + - name: Restore Playwright browsers + id: playwright + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-chromium-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - name: Install Playwright browsers + if: steps.playwright.outputs.cache-hit != 'true' run: pnpm exec playwright install --with-deps chromium - name: End-to-end tests run: pnpm test:e2e @@ -63,8 +74,28 @@ jobs: name: playwright-report path: playwright-report retention-days: 7 + + # Lighthouse was more than half of a CI run (12 URLs x 3 runs, about 6 minutes), waiting + # behind the end-to-end tests. It builds the site itself (a few seconds) and runs beside the + # check job instead. Pull requests audit each URL once; main keeps the three runs of + # lighthouserc.json, since its scores are the ones posted as a commit status and a flaky + # failure there would hold back a deploy. + lighthouse: + name: Lighthouse budgets + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v7 + - uses: pnpm/action-setup@v6 + - uses: actions/setup-node@v7 + with: + node-version-file: .nvmrc + cache: pnpm + - run: pnpm install --frozen-lockfile + - name: Build + run: pnpm build - name: Lighthouse budgets - run: pnpm exec lhci autorun --config=lighthouserc.json + run: pnpm exec lhci autorun --config=lighthouserc.json --collect.numberOfRuns=${{ github.ref == 'refs/heads/main' && 3 || 1 }} env: LHCI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload Lighthouse reports diff --git a/.github/workflows/screenshots.yml b/.github/workflows/screenshots.yml index a232d97..5f656e7 100644 --- a/.github/workflows/screenshots.yml +++ b/.github/workflows/screenshots.yml @@ -32,7 +32,16 @@ jobs: cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm build - - run: pnpm exec playwright install --with-deps chromium + # The same cache as ci.yml: the lockfile pins the Playwright version, and with it the + # Chromium build the baselines must come from. + - name: Restore Playwright browsers + id: playwright + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-chromium-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + - if: steps.playwright.outputs.cache-hit != 'true' + run: pnpm exec playwright install --with-deps chromium - name: Regenerate baselines run: pnpm exec playwright test --update-snapshots --grep "looks right" - name: Commit baselines diff --git a/docs/development.md b/docs/development.md index 4e34c4a..eed33d9 100644 --- a/docs/development.md +++ b/docs/development.md @@ -48,8 +48,10 @@ set. - **End-to-end tests** live in `tests/e2e/` and run against the built site. They check that pages read without JavaScript, that the islands work with it, accessibility with axe, and screenshots per page in both themes and at phone width. -- **Lighthouse budgets** (`lighthouserc.json`) run in CI only: performance and accessibility at or - above 95 on the listed pages, and no more than 150 kB of script per page. Run them locally with +- **Lighthouse budgets** (`lighthouserc.json`) run in CI only, in a job of their own beside the + checks: performance and accessibility at or above 95 on the listed pages, and no more than + 150 kB of script per page. Pull requests audit each page once, main three times (the scores + posted as a commit status). Run them locally with `pnpm build && pnpm exec lhci autorun --config=lighthouserc.json`. - **Byte budgets** (`pnpm check:budgets`) print one row per page and the size of each island, then a summary. Two limits fail the run today: the constitution's 150 kB of compressed