/** * Lighthouse CI configuration — per ADR-0017 (Performance budgets). * * Thresholds match the Google "Good" Core Web Vitals values plus the * Lighthouse Performance score floor we set as the project bar. * * Critical-routes list grows as features land. v1 checks the * static-served portal-shell bundle on both locale entry points * (`/fr/` is the default served at the production root via the smart * redirect; `/en/` is the alternate). ADR-0019 mandates that both * locales clear the same bar. Per-route assertions land alongside * the features that introduce those routes. */ module.exports = { ci: { collect: { // Serve the production bundle statically (no BFF needed for v1 // measurements). With `--localize` the build emits per-locale // folders (`browser/en/`, `browser/fr/`); we serve their parent // and Lighthouse hits each locale's root index.html directly. startServerCommand: 'pnpm nx run portal-shell:serve-static', startServerReadyPattern: 'Available on:', url: ['http://localhost:4200/fr/', 'http://localhost:4200/en/'], numberOfRuns: 3, settings: { // Slow-4G profile so scores are stable across CI runners and // comparable to industry public benchmarks. preset: 'desktop', // Chrome's user-namespace sandbox is disabled inside the act // runner container (AppArmor restriction on the host kernel), // so Chrome fails to launch with a "No usable sandbox" zygote // error. `--no-sandbox` is the standard Lighthouse / Puppeteer // / Playwright workaround for containerised CI: the residual // risk is acceptable because Chrome only loads our own freshly // built bundle from http://localhost:4200/ inside an ephemeral // self-hosted runner container — no untrusted content reaches // the browser process. chromeFlags: '--no-sandbox', }, }, assert: { assertions: { // Core Web Vitals (Google "Good"), per ADR-0017 'largest-contentful-paint': ['error', { maxNumericValue: 2500 }], 'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }], 'total-blocking-time': ['error', { maxNumericValue: 200 }], 'server-response-time': ['error', { maxNumericValue: 800 }], // Aggregate score — our gate is "Performance >= 90" 'categories:performance': ['error', { minScore: 0.9 }], // a11y is enforced by the dedicated a11y gate (axe-core, // ADR-0016) — keep Lighthouse a11y as a soft signal here. 'categories:accessibility': ['warn', { minScore: 0.9 }], // Best practices and SEO are advisory in this gate. 'categories:best-practices': ['warn', { minScore: 0.9 }], 'categories:seo': 'off', }, }, upload: { target: 'filesystem', outputDir: './.lighthouseci', }, }, };