DEV Community

James
James

Posted on

2 2

Programmatically audit with Lighthouse and performance budgets

Lighthouse is a fantastic tool for auditing websites. Not only can it be run in Chrome Devtools and on the CLI, but also programmatically! This is especially useful in CI pipelines where we can use Lighthouse to check metrics such as Core Web Vitals on local or ephemeral environments, in order to warn the engineer(s) that quality attributes have degraded before going to production.

const PORT = 8041;

function createAuditor(budget) {
  const flags = {
    port: PORT,
    disableStorageReset: true,
  };
  const optionsArray = [];
  const mobileOptions = {
    extends: 'lighthouse:default',
    settings: {
      budgets: budget && [budget],
    },
  };
  optionsArray.push(mobileOptions);

  return async function audit(url) {
    const lighthouse = require('lighthouse');
    const puppeteer = require('puppeteer');
    const browser = await puppeteer.launch({
      args: [`--remote-debugging-port=${PORT}`],
      headless: true,
    });
    const results = [];

    for (const options of optionsArray) {
      const runnerResult = await lighthouse(url, flags, options);
      const budgetReport = getBudgetReport(runnerResult.report);
      const { categories, finalUrl, configSettings } = runnerResult.lhr;

      results.push({
        url: finalUrl,
        formFactor: configSettings.formFactor,
        accessibility: categories.accessibility.score * 100,
        bestPractices: categories['best-practices'].score * 100,
        performance: categories.performance.score * 100,
        pwa: categories.pwa.score * 100,
        seo: categories.seo.score * 100,
        budgetReport,
      });
    }

    await browser.close();
    return results;
  };
}

function getBudgetReport(result) {
  const report = JSON.parse(result);
  const getOverBudget = (item) => item.countOverBudget || item.sizeOverBudget || item.overBudget;
  const perfBudget = report.audits['performance-budget'];
  const timingBudget = report.audits['timing-budget'];
  const budgetReport = [];

  if (perfBudget && perfBudget.details) {
    const perf = perfBudget.details.items.filter(getOverBudget);
    budgetReport.push(...perf);
  }

  if (timingBudget && timingBudget.details) {
    const timings = timingBudget.details.items.filter(getOverBudget);
    budgetReport.push(...timings);
  }

  return budgetReport;
}
Enter fullscreen mode Exit fullscreen mode

The example implementation uses Puppeteer, as this would allow us to interact and navigate before beginning the audit. The audit method returns the results including metrics that have not met the budget requirements, allowing us to fail a build and/or report metrics.

Below is an example of the Lighthouse performance budget.

{
    "resourceCounts": [
        {
            "resourceType": "script",
            "budget": 15
        }
    ],
    "resourceSizes": [
        {
            "resourceType": "script",
            "budget": 180
        }
    ],
    "timings": [
        {
            "metric": "interactive",
            "budget": 4500
        },
        {
            "metric": "first-contentful-paint",
            "budget": 1300
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

I've written about sending these metrics to Datadog in a following post.

Top comments (0)

SurveyJS custom survey software

JavaScript Form Builder UI Component

Generate dynamic JSON-driven forms directly in your JavaScript app (Angular, React, Vue.js, jQuery) with a fully customizable drag-and-drop form builder. Easily integrate with any backend system and retain full ownership over your data, with no user or form submission limits.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay