Programmatically audit with Lighthouse and performance budgets
James
Posted on March 2, 2021
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;
}
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
}
]
}
I've written about sending these metrics to Datadog in a following post.
Posted on March 2, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.