#!/usr/bin/env node /** * Performance budget gate from latest Lighthouse site report. * Usage: * node scripts/a11y/audit-perf-gate.mjs [--min=85] [--max-lcp=2500] [--require] * Env: MIM_PERF_GATE_MIN, MIM_PERF_GATE_MAX_LCP_MS, MIM_PERF_GATE_REQUIRE=1 */ import { readFileSync, existsSync } from 'node:fs' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' const __dirname = dirname(fileURLToPath(import.meta.url)) const repoRoot = join(__dirname, '../..') const reportPath = join(repoRoot, 'reports/status/mim4u-site-lighthouse-latest.json') const minArg = process.argv.find((a) => a.startsWith('--min=')) const lcpArg = process.argv.find((a) => a.startsWith('--max-lcp=')) const minScore = Number(minArg?.split('=')[1] || process.env.MIM_PERF_GATE_MIN || 85) const maxLcpMs = Number(lcpArg?.split('=')[1] || process.env.MIM_PERF_GATE_MAX_LCP_MS || 2500) const requireReport = process.argv.includes('--require') || process.env.MIM_PERF_GATE_REQUIRE === '1' if (!existsSync(reportPath)) { const msg = `Perf gate: no report at ${reportPath} — run npm run a11y:site-lighthouse` if (requireReport) { console.error(msg) process.exit(1) } console.warn(`${msg} (skipped)`) process.exit(0) } const report = JSON.parse(readFileSync(reportPath, 'utf8')) const perf = report.scores?.performance const lcpMs = report.lcpMs console.log( `Perf gate: performance=${perf ?? 'n/a'} (min ${minScore})${lcpMs != null ? `, LCP=${lcpMs}ms (max ${maxLcpMs})` : ''}`, ) let failed = false if (typeof perf !== 'number') { console.error('Perf gate: performance score missing from report') if (requireReport) failed = true } else if (perf < minScore) { console.error(`Perf gate FAILED: performance ${perf} < ${minScore}`) failed = true } if (typeof lcpMs === 'number' && lcpMs > maxLcpMs) { console.error(`Perf gate FAILED: LCP ${lcpMs}ms > ${maxLcpMs}ms`) failed = true } if (failed) { console.error('Run CWV sprint / npm run a11y:site-lighthouse after deploy.') process.exit(1) } console.log('Perf gate passed.') process.exit(0)