Skip to content

frontend-performance/perf-audit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

perf-audit

A fast, browserless CLI that audits a URL's HTML and response headers for common frontend performance issues — Core Web Vitals risks, caching mistakes, render-blocking resources, font and image pitfalls — and links each finding to a deep-dive explainer on frontend-performance.com.

No Chromium, no headless browser, no Lighthouse. Just fetch + an HTML parser, so it runs in under a second and fits in any CI step.

Install

Not yet on npm. Run directly from GitHub with npx:

npx github:frontend-performance/perf-audit https://example.com

Or clone and link locally:

git clone https://github.com/frontend-performance/perf-audit.git
cd perf-audit
npm install        # builds via the prepare script
npm link           # exposes the `perf-audit` binary

Requires Node.js 20+.

Usage

perf-audit https://example.com
perf-audit https://example.com --json > report.json
perf-audit https://example.com --markdown >> "$GITHUB_STEP_SUMMARY"
perf-audit --file ./dist/index.html
perf-audit https://example.com --fail-on warn   # stricter CI gate

Output modes:

  • default — colorized human-readable report
  • --json — machine-readable JSON (includes score, grade, and severity counts)
  • --markdown (alias --md) — a Markdown report with a findings table, ideal for a PR comment or a GitHub Actions Step Summary

Exit codes:

  • 0 — no findings at the configured severity
  • 1 — at least one finding at or above --fail-on (default: error)
  • 2 — bad arguments or fetch failure

Score & grade

Every run prints a deterministic score and letter grade at the top:

Grade F  12/100  4 error · 5 warn · 3 info

The score starts at 100 and subtracts a fixed weight per finding:

Severity Points
error −15
warn −5
info −1

The total is clamped to 0–100, then graded: A ≥ 90, B ≥ 80, C ≥ 70, D ≥ 60, F < 60. Because the weights are fixed and the checks are static, the same HTML always yields the same score — safe to assert on in CI.

What it checks

Each rule links to a longer explanation on frontend-performance.com — the goal is to explain why a finding matters, not just flag it.

Core Web Vitals

Rule Severity Description
missing-viewport error No <meta name="viewport"> — mobile browsers use a 980px virtual viewport, inflating CLS.
lazy-hero-image error First <img> has loading="lazy", harming LCP.
img-missing-dimensions warn Non-lazy <img> without width/height or CSS aspect-ratio causes layout shift.
lazy-img-missing-dimensions warn Lazy <img> without dimensions — arrives late and shifts layout (strong CLS signal).
eager-below-fold info Images with loading="eager" late in the document waste bandwidth.
high-ttfb warn TTFB > 800ms is the Core Web Vitals "poor" threshold.

→ Background reading: Core Web Vitals thresholds, Reducing CLS, Measuring LCP.

Images & media

Rule Severity Description
hero-image-no-fetchpriority info First (non-lazy) <img> has no fetchpriority="high" — the LCP image could start sooner.
img-no-modern-format info Raster <img> (JPEG/PNG) with no AVIF/WebP fallback via <picture> or srcset.
img-no-responsive-srcset info Large <img> (width ≥ 1000) with no srcset/sizes — small screens overfetch.

→ Background reading: Image CDNs & fetchpriority, Serving AVIF & WebP with fallbacks, Responsive images with srcset & sizes, Lazy-loading without hurting LCP.

JavaScript

Rule Severity Description
render-blocking-script error <script src> in <head> without async / defer / type="module".
large-inline-script warn Inline <script> over 4KB — can't be cached across navigations.
many-third-party-scripts warn More than 10 distinct third-party script hosts — main-thread and connection overhead.
inline-script-total info Total inline JS over 50KB.

→ Background reading: Dynamic imports & route-based splitting, ESM vs CommonJS module formats, Tree shaking & dead-code elimination.

CSS & fonts

Rule Severity Description
many-blocking-stylesheets warn More than 3 render-blocking stylesheets.
large-inline-style warn Inline <style> over 50KB — critical CSS gone too far.
css-import-in-style warn @import inside inline <style> — discovered late, serializes the CSS download.
font-display-missing warn @font-face without font-display causes FOIT.
preload-font-missing-crossorigin error Preloaded fonts need crossorigin or they fetch twice.

Caching, hints, headers

Rule Severity Description
missing-preconnect info A third-party origin is referenced multiple times without preconnect/dns-prefetch.
no-compression error HTML response has no Content-Encoding.
compression-gzip-only info HTML uses gzip — Brotli usually saves another 15–25%.
html-no-cache-control warn No Cache-Control header on the HTML response.
html-immutable warn HTML marked immutable — updates won't reach users.
html-no-swr info Cache-Control is missing stale-while-revalidate.
no-hsts info No Strict-Transport-Security header.

→ Background reading: HTTP Cache-Control headers explained, Stale-while-revalidate, CDN edge caching.

GitHub Actions

Run it straight from GitHub with npx — no publish step needed. Pipe --markdown into $GITHUB_STEP_SUMMARY to render the findings table right on the run summary:

# .github/workflows/perf-audit.yml
name: perf-audit
on: [push, pull_request]

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      # Write the report to the job summary, but don't fail the step yet…
      - run: npx github:frontend-performance/perf-audit https://staging.example.com --markdown --fail-on never >> "$GITHUB_STEP_SUMMARY"
      # …then gate the build on errors (or use --fail-on warn to be stricter).
      - run: npx github:frontend-performance/perf-audit https://staging.example.com --fail-on error

For a PR comment, capture the Markdown and post it with actions/github-script, or capture --json and build your own message.

What this isn't

perf-audit is a static analyzer. It can't measure runtime metrics that require a real browser — LCP timing, INP, layout-shift score, JS execution cost. For those, run Lighthouse or PSI in addition.

The trade-off: static analysis is fast, deterministic, and dependency-free, so it's a great first gate. Most regressions show up here first.

Further reading

Every finding deep-links into one of the four performance clusters on frontend-performance.com:

License

MIT © frontend-performance

About

Fast, browserless CLI that audits a URL's HTML and response headers for common frontend performance issues. Findings link to explainers on frontend-performance.com.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors