Skip to content

Commit 3a57997

Browse files
HazATclaude
andauthored
ci: Add Lighthouse Test as Nightly CI run (#20850)
Adds a nightly workflow that builds a dedicated `lighthouse-react` Vite fixture in 3 modes (`no-sentry` / `init-only` / `tracing-replay`) and uploads the bundles to https://lighthouse.sentry.gg. The lab runs Lighthouse on dedicated hardware and ships metrics to Sentry. Single job, nightly cron + manual dispatch, never blocks merges. - Lab repo: https://github.com/getsentry/sentry-lighthouse - Dashboard: https://sentry-sdks.sentry.io/dashboard/5335223/ --------- Co-authored-by: Claude claude-opus-4-5 <noreply@anthropic.com>
1 parent ba1a270 commit 3a57997

13 files changed

Lines changed: 382 additions & 0 deletions

File tree

.github/workflows/lighthouse.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: 'Nightly: Lighthouse'
2+
3+
# Nightly: builds the Lighthouse fixture app and uploads bundles to the
4+
# lighthouse.sentry.gg lab. Never blocks merges.
5+
6+
on:
7+
schedule:
8+
- cron: '0 0 * * *'
9+
workflow_dispatch:
10+
11+
jobs:
12+
build-and-upload:
13+
name: Bundle and upload Lighthouse cells
14+
runs-on: ubuntu-24.04
15+
timeout-minutes: 30
16+
env:
17+
LIGHTHOUSE_LAB_URL: ${{ secrets.LIGHTHOUSE_LAB_URL }}
18+
LIGHTHOUSE_UPLOAD_TOKEN: ${{ secrets.LIGHTHOUSE_UPLOAD_TOKEN }}
19+
VITE_E2E_TEST_DSN: 'https://username@domain/123'
20+
steps:
21+
- uses: actions/checkout@v6
22+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
23+
with:
24+
version: 9.15.9
25+
- uses: actions/setup-node@v6
26+
with:
27+
node-version-file: 'package.json'
28+
- run: yarn install --frozen-lockfile --ignore-engines
29+
- run: yarn build:ci
30+
- run: yarn build:tarball
31+
- run: yarn test:prepare
32+
working-directory: dev-packages/e2e-tests
33+
- run: node scripts/lighthouse-bundle-and-upload.mjs
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Lighthouse Fixture</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "lighthouse-react-test-app",
3+
"private": true,
4+
"type": "module",
5+
"sentryTest": {
6+
"skip": true
7+
},
8+
"scripts": {
9+
"build": "vite build",
10+
"build:no-sentry": "vite build --mode no-sentry",
11+
"build:init-only": "vite build --mode init-only",
12+
"build:tracing-replay": "vite build --mode tracing-replay",
13+
"preview": "vite preview",
14+
"clean": "npx rimraf node_modules pnpm-lock.yaml dist",
15+
"test:build": "pnpm install && pnpm build"
16+
},
17+
"dependencies": {
18+
"@sentry/react": "file:../../packed/sentry-react-packed.tgz",
19+
"react": "^18.3.1",
20+
"react-dom": "^18.3.1"
21+
},
22+
"devDependencies": {
23+
"@types/react": "^18.3.0",
24+
"@types/react-dom": "^18.3.0",
25+
"@vitejs/plugin-react-swc": "^3.7.0",
26+
"typescript": "~5.4.0",
27+
"vite": "^5.4.0"
28+
},
29+
"volta": {
30+
"extends": "../../package.json"
31+
}
32+
}
Lines changed: 6 additions & 0 deletions
Loading
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { useEffect, useState } from 'react';
2+
3+
const CARDS = [
4+
{ title: 'Performance', body: 'Measure and optimize your app render times and interaction latency.' },
5+
{ title: 'Accessibility', body: 'Ensure your interface is usable by everyone, including assistive technologies.' },
6+
{ title: 'Best Practices', body: 'Follow modern web development patterns for secure and maintainable code.' },
7+
{ title: 'SEO', body: 'Optimize discoverability with semantic markup and structured metadata.' },
8+
{ title: 'PWA', body: 'Add offline support and installability via service workers and manifests.' },
9+
{ title: 'Security', body: 'Protect users with CSP headers, HTTPS, and input validation.' },
10+
];
11+
12+
export default function App() {
13+
const [count, setCount] = useState(0);
14+
15+
useEffect(() => {
16+
document.title = `Lighthouse Fixture (${count})`;
17+
}, [count]);
18+
19+
return (
20+
<main>
21+
<header>
22+
<nav>
23+
<a href="/">Home</a>
24+
<a href="/docs">Docs</a>
25+
<a href="/about">About</a>
26+
</nav>
27+
</header>
28+
29+
<section className="hero">
30+
<img src="/logo.svg" alt="Lighthouse logo" width={120} height={120} />
31+
<h1>Lighthouse Fixture</h1>
32+
<p>
33+
This app exists to measure JavaScript bundle size and runtime cost across three Sentry instrumentation
34+
configurations. Each build mode ships a different level of SDK integration.
35+
</p>
36+
</section>
37+
38+
<section className="cards">
39+
{CARDS.map(card => (
40+
<article key={card.title} className="card">
41+
<h2>{card.title}</h2>
42+
<p>{card.body}</p>
43+
</article>
44+
))}
45+
</section>
46+
47+
<form
48+
onSubmit={e => {
49+
e.preventDefault();
50+
setCount(c => c + 1);
51+
}}
52+
>
53+
<input type="text" name="name" placeholder="Name" aria-label="Name" />
54+
<input type="email" name="email" placeholder="Email" aria-label="Email" />
55+
<input type="text" name="message" placeholder="Message" aria-label="Message" />
56+
<button type="submit">Submit ({count})</button>
57+
</form>
58+
</main>
59+
);
60+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { createRoot } from 'react-dom/client';
2+
import App from './App';
3+
4+
async function bootstrap() {
5+
const mode = import.meta.env.MODE;
6+
if (mode === 'init-only') {
7+
const { initSentry } = await import('./sentry/init-only');
8+
initSentry();
9+
} else if (mode === 'tracing-replay') {
10+
const { initSentry } = await import('./sentry/tracing-replay');
11+
initSentry();
12+
}
13+
// 'no-sentry' mode: do not import any sentry module — the dynamic-import
14+
// branches above are unreachable and Vite drops them from the bundle.
15+
16+
const root = createRoot(document.getElementById('root')!);
17+
root.render(<App />);
18+
}
19+
20+
void bootstrap();
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import * as Sentry from '@sentry/react';
2+
3+
export function initSentry(): void {
4+
// enabled: false makes the SDK a guaranteed no-op (no transport allocation,
5+
// no DSN warning). We're measuring pure SDK-loading + tree-shaking cost.
6+
Sentry.init({ enabled: false });
7+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function initSentry(): void {
2+
// no-op: this mode intentionally excludes all Sentry imports
3+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as Sentry from '@sentry/react';
2+
3+
export function initSentry(): void {
4+
Sentry.init({
5+
dsn: import.meta.env.VITE_E2E_TEST_DSN as string | undefined,
6+
release: 'lighthouse-fixture',
7+
environment: 'qa',
8+
integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()],
9+
tracesSampleRate: 1.0,
10+
replaysSessionSampleRate: 1.0,
11+
replaysOnErrorSampleRate: 1.0,
12+
});
13+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"useDefineForClassFields": true,
5+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
6+
"module": "ESNext",
7+
"skipLibCheck": true,
8+
"moduleResolution": "bundler",
9+
"allowImportingTsExtensions": true,
10+
"resolveJsonModule": true,
11+
"isolatedModules": true,
12+
"noEmit": true,
13+
"jsx": "react-jsx",
14+
"strict": true,
15+
"noUnusedLocals": true,
16+
"noUnusedParameters": true,
17+
"noFallthroughCasesInSwitch": true
18+
},
19+
"include": ["src"],
20+
"references": [{ "path": "./tsconfig.node.json" }]
21+
}

0 commit comments

Comments
 (0)