npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

webperf-snippets

v0.2.0

Published

Run curated WebPerf Snippets headlessly via Playwright. Diagnose Core Web Vitals beyond what Lighthouse exposes.

Downloads

418

Readme

webperf-snippets CLI

Run curated WebPerf Snippets headlessly via Playwright. Diagnose Core Web Vitals beyond what Lighthouse exposes and gate CI on real performance budgets.

Status: v0.2. Core Web Vitals, loading audit, and structural checks. See Roadmap for what's next.

Why

Lighthouse gives you a score. The DevTools snippets give you the diagnosis — TTFB / Resource Load Delay / Element Render Delay sub-parts, LoAF script attribution, render-blocking resources, etc. This CLI runs the same curated snippets in a headless browser so you can:

  • Diagnose LCP regressions in CI without copy-pasting into DevTools.
  • Gate pull requests on real performance budgets.
  • Automate the snippets you already run by hand.

Install

Playwright is a peer dependency. Install both, plus the chromium browser:

npm install --save-dev webperf-snippets playwright
npx playwright install chromium

Usage

npx webperf-snippets <url> [options]

Examples

Run the default Core Web Vitals workflow (LCP + CLS, plus LCP-Subparts if LCP > 2.5s):

npx webperf-snippets https://web.dev

Loading audit (TTFB, FCP, render-blocking, scripts, fonts):

npx webperf-snippets https://web.dev --workflow loading

Structural checks for CI (render-blocking, fonts, priority hints, resource hints):

npx webperf-snippets https://web.dev --workflow audit

Markdown output for PR comments:

npx webperf-snippets https://web.dev --markdown

JSON output (for piping into jq or CI):

npx webperf-snippets https://web.dev --json

Single snippet:

npx webperf-snippets https://web.dev --snippet LCP-Subparts

Synthetic INP measurement with an interaction script:

npx webperf-snippets https://web.dev --snippet INP --interact-script interactions.json

CI gating:

npx webperf-snippets https://web.dev --budget-lcp 2500 --budget-cls 0.1

Options

| Option | Description | | ---------------------------- | ---------------------------------------------------------------------- | | --workflow <name> | Workflow to run. Default: core-web-vitals. Options: core-web-vitals, loading, audit. | | --snippet <name> | Run a single snippet by alias or Category/Name path. | | --json | Output JSON instead of formatted text. | | --markdown | Output GitHub-renderable markdown (for PR comments). | | --viewport <preset> | Viewport preset: mobile (default), tablet, desktop. | | --wait <ms> | Post-load wait before evaluating snippets. Default: 3000. | | --interact-script <path> | JSON file with interactions to run before evaluation (for INP). | | --budget-lcp <ms> | Exit 1 if LCP exceeds this value. | | --budget-cls <score> | Exit 1 if CLS exceeds this value. | | --verbose | Show all items, including passing checks. | | --headed | Show the browser window (debug). | | -h, --help | Show help. |

Snippet aliases

| Alias | Snippet | | ------------------ | ---------------------------------------------- | | LCP | CoreWebVitals/LCP | | CLS | CoreWebVitals/CLS | | LCP-Subparts | CoreWebVitals/LCP-Subparts | | fonts | Loading/Fonts-Preloaded-Loaded-and-used-above-the-fold | | render-blocking | Loading/Find-render-blocking-resources | | resource-hints | Loading/Resource-Hints-Validation | | preload-scripts | Loading/Validate-Preload-Async-Defer-Scripts | | priority-hints | Loading/Priority-Hints-Audit | | critical-css | Loading/Critical-CSS-Detection | | ttfb | Loading/TTFB-Sub-Parts | | script-parties | Loading/First-And-Third-Party-Script-Info | | script-loading | Loading/Script-Loading | | lazy-atf | Loading/Find-Above-The-Fold-Lazy-Loaded-Images | | lazy-conflict | Loading/Find-Images-With-Lazy-and-Fetchpriority | | eager-below-fold | Loading/Find-non-Lazy-Loaded-Images-outside-of-the-viewport |

Exit codes

| Code | Meaning | | ---- | --------------------------------------------- | | 0 | All checks passed. | | 1 | Budget violation, or a snippet errored. | | 2 | Usage error (missing URL, unknown workflow). |

CI example

GitHub Actions, fail the PR if LCP exceeds 2.5s:

- run: |
    npm install --no-save webperf-snippets playwright
    npx playwright install --with-deps chromium
    npx webperf-snippets https://staging.web.dev --budget-lcp 2500 --budget-cls 0.1

Publishing

The CLI package is published to npm via a tag-based workflow. Publishing is explicit and intentional — it only happens when a cli-v* tag is pushed.

Release steps

  1. Bump the version in cli/package.json.
  2. Commit the version change.
  3. Tag and push:
    git tag cli-v0.2.0
    git push origin cli-v0.2.0
  4. The publish-cli CI job runs, executes the full test suite, and publishes to npm.

Why tag-based and not path-based

An alternative is to publish automatically on every push to main that touches cli/, using a version check to skip republishes. Tag-based publishing was chosen instead because it keeps releases deliberate — a passing CI on main does not mean the package is ready to ship, and a tag communicates that intent explicitly.

Access control

Tag protection rules restrict who can push cli-v* tags. Configure them under Settings → Rules → New ruleset in the repository, targeting the cli-v* tag pattern and limiting push access to admins or maintainers. This ensures only authorized collaborators can trigger a publish.

Required secret

The NPM_TOKEN secret must be set in the repository settings with publish access to the webperf-snippets npm package.

Known limitations

  • CLS in headless is conservative: layout shifts that only happen on scroll are missed unless you script the scroll.
  • First navigation only: each webperf-snippets invocation runs one URL. SPAs need the post-route URL passed directly.
  • Synthetic INP ≠ field INP: --interact-script measures handler latency for a single scripted event. Real INP reflects the worst interaction across all user sessions — use RUM for field data.

Roadmap

  • ~~v0.2: Loading workflow (TTFB, FCP, render-blocking, scripts, fonts), shared page session, synthetic interactions for INP, markdown reporter for PR comments.~~ ✓ Released
  • v0.3: GitHub Action wrapper.
  • v0.4: Auth flows (login + measure logged-in pages), CrUX field-data enrichment.

How it works

  1. Launches headless chromium via Playwright.
  2. Pre-registers PerformanceObservers for LCP and layout-shift before navigation (Chrome doesn't expose these via getEntriesByType without a buffered observer, so the runner shims it).
  3. Navigates, waits for the page to settle.
  4. Evaluates each snippet's IIFE in the page context, capturing the returned object.
  5. Applies the workflow's decision tree to enqueue follow-up snippets.
  6. Renders results (human or JSON) and exits with an appropriate code.

License

MIT — see LICENSE.