Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions .github/workflows/lighthouse.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: Lighthouse audit

on:
pull_request_target:
types: [opened, synchronize]
Comment thread
ShubhamOulkar marked this conversation as resolved.

permissions:
contents: read
pull-requests: write

jobs:
lighthouse:
if: github.actor != 'dependabot[bot]'
runs-on: ubuntu-latest

steps:
- name: Checkout PR code
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}

- name: Setup Node.js with npm cache
uses: actions/setup-node@v4
with:
node-version: '22.x'
cache: 'npm'

- name: Install dependencies
run: npm install lighthouse

- name: Wait for Netlify preview to be live
run: |
PREVIEW_URL="https://deploy-preview-${{ github.event.pull_request.number }}--expressjscom-preview.netlify.app"
echo "PREVIEW_URL=$PREVIEW_URL" >> "$GITHUB_ENV"
for i in {1..2}; do
if curl -s --head "$PREVIEW_URL" | grep "200 OK" > /dev/null; then
echo "Preview is live!"
break
fi
echo "Waiting for Netlify to deploy... ($i/2)"
sleep 10
done

- name: Run Lighthouse audits
run: |
URLS=(
"$PREVIEW_URL"
"$PREVIEW_URL/en/blog/posts.html"
"$PREVIEW_URL/en/5x/api.html"
)

echo "## 🚦 Lighthouse Results (Mobile & Desktop)" > lighthouse-report.md
echo "| URL | Device | Perf | A11y | Best Practices | ⚠️ SEO score unreliable |" >> lighthouse-report.md
echo "| --- | ------ | ---- | ---- | -------------- | --- |" >> lighthouse-report.md

for device in mobile desktop; do
for url in "${URLS[@]}"; do
if [ "$device" = "desktop" ]; then
lighthouse_args="--preset=desktop"
else
lighthouse_args="--form-factor=mobile"
fi

npx lighthouse "$url" \
$lighthouse_args \
--output json \
--output-path="lighthouse-report-${device}.json" \
--chrome-flags="--headless"

report="lighthouse-report-${device}.json"
perf=$(jq '.categories | .performance.score * 100' $report)
a11y=$(jq '.categories | .accessibility.score * 100' $report)
bp=$(jq '.categories | .["best-practices"].score * 100' $report)
seo=$(jq '.categories | .seo.score * 100' $report)

stoplight() {
if (( $(echo "$1 >= 90" | bc -l) )); then echo "🟢";
elif (( $(echo "$1 >= 75" | bc -l) )); then echo "🟠";
else echo "🔴"; fi
}

perf_stoplight=$(stoplight $perf)
a11y_stoplight=$(stoplight $a11y)
bp_stoplight=$(stoplight $bp)
seo_stoplight=$(stoplight $seo)

path=$(echo "$url" | sed "s|$PREVIEW_URL||")
if [ -z "$path" ]; then path="/"; fi

echo "| $path | $device | $perf_stoplight $(printf "%.0f" $perf) | $a11y_stoplight $(printf "%.0f" $a11y) | $bp_stoplight $(printf "%.0f" $bp) | $seo_stoplight $(printf "%.0f" $seo) |" >> lighthouse-report.md
done
done

- name: Log Lighthouse report
run: |
cat lighthouse-report.md

- name: Upload Lighthouse reports as artifacts
uses: actions/upload-artifact@v4
with:
name: lighthouse-reports
path: |
lighthouse-report.md

- name: Comment on PR with Lighthouse results
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const report = fs.readFileSync('lighthouse-report.md', 'utf8');

const { data: comments } = await github.rest.issues.listComments({
issue_number: context.payload.pull_request.number,
owner: context.repo.owner,
repo: context.repo.repo,
});

const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('🚦Lighthouse Results (Mobile & Desktop)')
);

if (botComment) {
await github.rest.issues.updateComment({
comment_id: botComment.id,
owner: context.repo.owner,
repo: context.repo.repo,
body: report
});
} else {
await github.rest.issues.createComment({
issue_number: context.payload.pull_request.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: report
});
}