9999 - name : Run UI tests
100100 id : ui_tests
101101 run : npm test
102+ env :
103+ # GitHub Actions sets $HOME=/github/home (uid 1001), but the
104+ # Playwright container runs as root — firefox refuses to launch
105+ # under a $HOME it doesn't own. /root is owned by the running
106+ # user, satisfies firefox, and chromium/webkit don't care.
107+ HOME : /root
102108 - name : Upload Playwright report
103109 id : upload_report
104110 if : always() && steps.ui_tests.conclusion != 'skipped'
@@ -123,6 +129,73 @@ jobs:
123129 header : ui-tests
124130 path : /tmp/ui-test-summary.md
125131
132+ # Lighthouse CI (PRs only). Runs against the freshly-built site and asserts
133+ # against budgets in lighthouserc.json. Reuses the Playwright container
134+ # because it already ships Chrome + Node 20+ (lhci 0.15 needs both).
135+ lighthouse-ci :
136+ if : github.event_name == 'pull_request'
137+ runs-on : ubuntu-latest
138+ container :
139+ image : mcr.microsoft.com/playwright:v1.59.1-jammy
140+ steps :
141+ - name : Checkout
142+ uses : actions/checkout@v4
143+ - name : Install Ruby runtime + build deps
144+ run : |
145+ apt-get update -qq
146+ apt-get install -y -qq --no-install-recommends \
147+ libyaml-0-2 \
148+ build-essential \
149+ libssl-dev
150+ - name : Setup Ruby
151+ uses : ruby/setup-ruby@086ffb1a2090c870a3f881cc91ea83aa4243d408 # v1.195.0
152+ with :
153+ ruby-version : ' 3.1'
154+ bundler-cache : true
155+ cache-version : 0
156+ - name : Build site
157+ run : bundle exec jekyll build
158+ env :
159+ JEKYLL_ENV : production
160+ - name : Install npm deps
161+ run : npm ci
162+ - name : Run Lighthouse CI
163+ id : lhci
164+ # The Playwright image ships chromium at /ms-playwright/chromium-*/...
165+ # rather than /usr/bin/google-chrome, so chrome-launcher (used by lhci)
166+ # can't auto-detect it. Resolve the binary via the playwright Node API
167+ # and pass it through as CHROME_PATH.
168+ run : |
169+ export CHROME_PATH="$(node -e 'console.log(require("playwright").chromium.executablePath())')"
170+ echo "Using Chrome at: $CHROME_PATH"
171+ npx lhci autorun --config=lighthouserc.json
172+ env :
173+ # Optional — set this secret to post lhci status checks via the
174+ # Lighthouse CI GitHub App. Without it, lhci runs but skips the
175+ # status-check post.
176+ LHCI_GITHUB_APP_TOKEN : ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
177+ - name : Upload Lighthouse reports
178+ id : upload_lhci
179+ if : always() && steps.lhci.conclusion != 'skipped'
180+ uses : actions/upload-artifact@v4
181+ with :
182+ name : lighthouse-reports
183+ path : .lighthouseci/
184+ retention-days : 14
185+ - name : Generate Lighthouse summary
186+ if : always() && steps.lhci.conclusion != 'skipped'
187+ env :
188+ ARTIFACT_URL : ${{ steps.upload_lhci.outputs.artifact-url }}
189+ run : |
190+ node scripts/ci-lighthouse-summary.mjs > /tmp/lighthouse-summary.md
191+ cat /tmp/lighthouse-summary.md >> "$GITHUB_STEP_SUMMARY"
192+ - name : Post Lighthouse comment on PR
193+ if : always() && github.event_name == 'pull_request' && steps.lhci.conclusion != 'skipped'
194+ uses : marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.0
195+ with :
196+ header : lighthouse
197+ path : /tmp/lighthouse-summary.md
198+
126199 # Publishes the Pages artifact from build-pages. Runs only on master pushes.
127200 deploy-pages :
128201 environment :
0 commit comments