Files

95 lines
3.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { parseArgs } from "node:util";
import lighthouse from "lighthouse";
import { launch } from "chrome-launcher";
const { values } = parseArgs({
options: {
url: { type: "string", default: "http://127.0.0.1:4173/" },
runs: { type: "string", default: "3" },
dark: { type: "boolean", default: false },
},
});
const url = new URL(values.url);
const runs = Number(values.runs);
if (!Number.isInteger(runs) || runs < 1 || runs > 10)
throw new Error("--runs must be 1–10");
const directory = ".artifacts/lighthouse";
await mkdir(directory, { recursive: true });
const name = `${url.pathname === "/admin" ? "admin" : "redeem"}-${values.dark ? "dark" : "light"}`;
const results = [];
for (let index = 1; index <= runs; index++) {
// New empty profile, no extensions, no warm cache or saved theme on every run.
const profile = await mkdtemp(join(tmpdir(), "xgift-lighthouse-"));
let chrome;
try {
chrome = await launch({
userDataDir: profile,
chromeFlags: [
"--headless",
"--disable-extensions",
...(values.dark ? ["--force-dark-mode"] : []),
],
});
const result = await lighthouse(url.href, {
port: chrome.port,
logLevel: "error",
output: ["html", "json"],
onlyCategories: ["performance", "accessibility", "best-practices", "seo"],
// Keep Lighthouse's standard mobile device, network and CPU throttling.
});
if (!result || result.lhr.runtimeError)
throw new Error(result?.lhr.runtimeError?.message || "No audit result");
const prefix = `${directory}/${name}-${index}`;
await writeFile(`${prefix}.html`, result.report[0]);
await writeFile(`${prefix}.json`, result.report[1]);
const scores = Object.fromEntries(
Object.entries(result.lhr.categories).map(([key, category]) => [
key,
Math.round(category.score * 100),
]),
);
const entry = {
run: index,
scores,
metrics: Object.fromEntries(
[
"first-contentful-paint",
"largest-contentful-paint",
"total-blocking-time",
"cumulative-layout-shift",
].map((key) => [key, result.lhr.audits[key].numericValue]),
),
report: `${prefix}.html`,
warnings: result.lhr.runWarnings,
};
results.push(entry);
console.log(JSON.stringify(entry));
if (Object.values(scores).some((score) => score < 97)) process.exitCode = 1;
} finally {
await chrome?.kill();
await rm(profile, { recursive: true, force: true });
}
}
await writeFile(
`${directory}/${name}-summary.json`,
JSON.stringify(
{
url: url.href,
theme: values.dark ? "system dark" : "system default",
profile: "new empty temporary profile for each run; extensions disabled",
preset: "Lighthouse default mobile simulated throttling",
target: 97,
results,
},
null,
2,
),
);
if (process.exitCode)
console.error(
"At least one category scored below 97. See .artifacts/lighthouse reports.",
);