Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Performance Budget Lab

Performance Budgets Report Lighthouse Budgets

Performance score 20 → 100. The same page, the same markup, the same copy — only the loading changed.

A Lighthouse score is a number nobody acts on. A budget turns it into a decision: this release ships, or it does not. This repository measures both builds of a property-listings page, enforces budgets in CI, and publishes a before-and-after report.

Performance budget report showing 20 versus 100 and the metric comparison

Open the live report →


The measured difference

Median of 3 Lighthouse runs, emulated mid-tier mobile over 4G:

Metric Legacy build Remediated build Budget Change
Performance score 20 100 ≥ 90
Largest Contentful Paint 9,216 ms 908 ms ≤ 2,500 ms −90%
First Contentful Paint 8,916 ms 833 ms ≤ 1,800 ms −91%
Speed Index 8,916 ms 833 ms ≤ 3,400 ms −91%
Total Blocking Time 1,952 ms 0 ms ≤ 200 ms −100%
Cumulative Layout Shift 0.197 0.000 ≤ 0.1 −100%
Transfer size 880 KB 15 KB ≤ 400 KB −98%

7 of 7 budgets breached on the legacy build; 0 of 7 on the remediated one.

What actually causes it

Four ordinary mistakes, none of which change how the page looks once it has settled — which is exactly why they survive code review.

Defect What it costs Where
Render-blocking script in <head> that also burns 900 ms of main thread before paint FCP, LCP, Speed Index app/blocking.js
880 KB of parsed-but-unused payload on the critical path Transfer size, parse time app/blocking.js
Content injected above existing content 600 ms after paint Cumulative Layout Shift app/late-content.js
Long tasks scheduled after first paint Total Blocking Time app/late-content.js
Images with no intrinsic dimensions, no lazy loading Layout stability, wasted bytes app/slow.html

The remediated build defers its script, declares image dimensions, lazy-loads below-the-fold media, and ships the notice in the HTML instead of injecting it. Read the two files side by side — the diff is the fix list.

What this demonstrates

Capability Where to look
Lighthouse driven programmatically, not by hand scripts/run-audit.mjs
Budgets as data, versioned with the code budgets/budgets.json
A failing budget exits non-zero and fails the build scripts/run-audit.mjs
Median-of-N runs, because a single run is noise scripts/run-audit.mjs
Before/after reporting with gauges and deltas scripts/build-report.mjs
Nightly runs, so drift is caught without a push ci.yml

Quick start

Requires Node 20+ and Chrome.

npm ci
npm run serve &        # app under test on :4175
npm run report         # audit both builds, enforce budgets, build the report
npm run audit -- --runs 5              # more samples, less noise
npm run audit -- --preset desktop      # desktop form factor
npm run report:build                   # rebuild the report from the last run

Then open report/site/index.html, or compare the builds yourself at /slow.html and /fast.html.

Design decisions

Only the remediated build gates. The legacy build is a fixture, kept so the budgets are proven capable of failing. A budget that has never gone red is a budget nobody has tested.

The median of several runs, not a single sample. Lighthouse timings move by hundreds of milliseconds between runs on a busy machine, and a shared CI runner is noisier than a laptop. A budget built on one sample is a coin toss, so CI defaults to three runs and the flag goes higher when it matters.

Budgets live in version control as data. budgets/budgets.json is reviewable, diffable, and arguable in a pull request. Thresholds buried in a script are none of those things.

The failure message names the number and the limit. A red build prints Total Blocking Time: 1952ms (limit 200ms) — the gap, not just a verdict.

Opportunities are captured, not just scores. The report carries Lighthouse's top suggested fixes with their estimated savings, so a breach arrives as a task list.

Budgets are set at the Core Web Vitals thresholds. LCP ≤ 2.5 s, CLS ≤ 0.1, and a score floor of 90 — the same bar Google applies, rather than numbers chosen to be comfortably passable.

Notes

  • The application under test ships with this repository, so a measurement cannot be invalidated by someone else's deployment.
  • Timings on a shared CI runner are slower than on a laptop. That is the point of budgets rather than fixed expectations: the remediated build clears the bar on both.
  • This repository contains no code, data, or credentials from any employer. Every line was written for this portfolio.

Companion projects

Licence

MIT

About

Lighthouse performance budgets enforced in CI: the same page built fast and slow (score 20 vs 100), with budgets as versioned data and a published before/after report.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages