Skip to content

Commit a0e1227

Browse files
committed
build: write lighthouse reports to allow for debugging
1 parent 8806b9b commit a0e1227

1 file changed

Lines changed: 69 additions & 47 deletions

File tree

tools/lighthouse-audit.js

Lines changed: 69 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,21 @@ const lighthouse = require('lighthouse');
66
const printer = require('lighthouse/lighthouse-cli/printer');
77
const logger = require('lighthouse-logger');
88
const puppeteer = require('puppeteer');
9+
const fs = require('fs');
10+
const path = require('path');
11+
12+
const projectDir = path.join(__dirname, '../');
13+
const reportsDir = path.join(projectDir, 'dist/reports');
914

1015
// Constants
11-
const AUDIT_CATEGORIES =
12-
[ 'accessibility', 'best-practices', 'performance', 'pwa', 'seo' ];
16+
const AUDIT_CATEGORIES = ['accessibility', 'best-practices', 'performance', 'pwa', 'seo'];
1317
/**
1418
* @type {LH.Flags}
1519
*/
1620
const LIGHTHOUSE_FLAGS = {
17-
logLevel : process.env.CI ? 'error' : 'info'
21+
logLevel: process.env.CI ? 'error' : 'info',
1822
}; // Be less verbose on CI.
19-
const SKIPPED_HTTPS_AUDITS = [
20-
'uses-long-cache-ttl', 'canonical', 'uses-text-compression'
21-
];
23+
const SKIPPED_HTTPS_AUDITS = ['uses-long-cache-ttl', 'canonical', 'uses-text-compression'];
2224
const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer';
2325
const WAIT_FOR_SW_DELAY = 5000;
2426

@@ -62,27 +64,31 @@ _main(process.argv.slice(2)).then(() => console.log('Audit completed.'));
6264
* @private
6365
*/
6466
async function _main(args) {
65-
const {url, minScores, logFile} = parseInput(args);
67+
const {url, minScores} = parseInput(args);
6668
const isOnHttp = /^http:/.test(url);
6769
/**
6870
* @type {LH.Flags}
6971
*/
7072
const lhFlags = {
7173
...LIGHTHOUSE_FLAGS,
72-
onlyCategories : Object.keys(minScores).sort()
74+
onlyCategories: Object.keys(minScores).sort(),
7375
};
7476
/**
7577
* @type {LH.Config.Json}
7678
*/
7779
const lhConfig = {
78-
extends : 'lighthouse:default',
80+
extends: 'lighthouse:default',
7981
// Since the Angular ServiceWorker waits for the app to stabilize before
8082
// registering, wait a few seconds after load to allow Lighthouse to
8183
// reliably detect it.
82-
passes :
83-
[ {passName : 'defaultPass', pauseAfterLoadMs : WAIT_FOR_SW_DELAY} ],
84+
passes: [{passName: 'defaultPass', pauseAfterLoadMs: WAIT_FOR_SW_DELAY}],
8485
};
8586

87+
await cleanupAndPrepareReportsDir();
88+
89+
// Always generate report/log files.
90+
const logFile = path.join(reportsDir, `${url.replace(/\//g, '-')}--report.json`);
91+
8692
console.log(`Running web-app audits for '${url}'...`);
8793
console.log(` Audit categories: ${lhFlags.onlyCategories.join(', ')}`);
8894

@@ -102,8 +108,7 @@ async function _main(args) {
102108
onError('Lighthouse failed to return any results.');
103109
}
104110
const success = await processResults(results, minScores, logFile);
105-
console.log(
106-
`\n(Completed in ${((Date.now() - startTime) / 1000).toFixed(1)}s.)\n`);
111+
console.log(`\n(Completed in ${((Date.now() - startTime) / 1000).toFixed(1)}s.)\n`);
107112

108113
if (!success) {
109114
onError('One or more scores are below the minimum required.');
@@ -128,8 +133,11 @@ function formatScore(score) {
128133
* @returns {Promise<LH.RunnerResult | undefined>} the result of the Lighthouse run
129134
*/
130135
async function launchChromeAndRunLighthouse(url, flags, config) {
131-
const browser = await puppeteer.launch();
132-
flags.port = (new URL(browser.wsEndpoint())).port;
136+
const browser = await puppeteer.launch({
137+
// Allow for a custom chromium to be provided (e.g. for M1 native support)
138+
executablePath: process.env.CHROMIUM_BIN,
139+
});
140+
flags.port = new URL(browser.wsEndpoint()).port;
133141

134142
try {
135143
return await lighthouse(url, flags, config);
@@ -147,14 +155,22 @@ function onError(err) {
147155
process.exit(1);
148156
}
149157

158+
async function cleanupAndPrepareReportsDir() {
159+
try {
160+
await fs.promises.rm(reportsDir, {recursive: true});
161+
} catch {}
162+
163+
await fs.promises.mkdir(reportsDir, {recursive: true});
164+
}
165+
150166
/**
151167
* Parse CLI args and throw errors if any are invalid.
152168
* @param {string[]} args <url> <min-scores> [<log-file>]
153-
* @returns {{url: string, minScores: {all?: number, performance?: number, accessibility?: number, 'best-practices'?: number, pwa?: number, seo?: number}, logFile?: string}}
169+
* @returns {{url: string, minScores: {all?: number, performance?: number, accessibility?: number, 'best-practices'?: number, pwa?: number, seo?: number}}}
154170
* the validated URL, parsed minimum scores, and optional file path to write the report to
155171
*/
156172
function parseInput(args) {
157-
const [url, minScoresRaw, logFile] = args;
173+
const [url, minScoresRaw] = args;
158174

159175
if (!url) {
160176
onError('Invalid arguments: <url> not specified.');
@@ -163,21 +179,22 @@ function parseInput(args) {
163179
}
164180

165181
const minScores = parseMinScores(minScoresRaw || '');
166-
const unknownCategories =
167-
Object.keys(minScores).filter(cat => !AUDIT_CATEGORIES.includes(cat));
168-
const allValuesValid =
169-
Object.values(minScores).every(x => (0 <= x) && (x <= 1));
182+
const unknownCategories = Object.keys(minScores).filter(cat => !AUDIT_CATEGORIES.includes(cat));
183+
const allValuesValid = Object.values(minScores).every(x => 0 <= x && x <= 1);
170184

171185
if (unknownCategories.length > 0) {
172-
onError(`Invalid arguments: <min-scores> contains unknown category(-ies): ${
173-
unknownCategories.join(', ')}`);
186+
onError(
187+
`Invalid arguments: <min-scores> contains unknown category(-ies): ${unknownCategories.join(
188+
', '
189+
)}`
190+
);
174191
} else if (!allValuesValid) {
175192
onError(
176-
`Invalid arguments: <min-scores> has non-numeric or out-of-range values: ${
177-
minScoresRaw}`);
193+
`Invalid arguments: <min-scores> has non-numeric or out-of-range values: ${minScoresRaw}`
194+
);
178195
}
179196

180-
return {url, minScores, logFile};
197+
return {url, minScores};
181198
}
182199

183200
/**
@@ -202,13 +219,15 @@ function parseMinScores(raw) {
202219
raw = `all:${raw}`;
203220
}
204221

205-
raw.split(',')
206-
.map(x => x.split(':'))
207-
.forEach(([ key, val ]) => minScores[key] = Number(val) / 100);
222+
raw
223+
.split(',')
224+
.map(x => x.split(':'))
225+
.forEach(([key, val]) => (minScores[key] = Number(val) / 100));
208226

209227
if (minScores.hasOwnProperty('all')) {
210-
AUDIT_CATEGORIES.forEach(cat => minScores.hasOwnProperty(cat) ||
211-
(minScores[cat] = minScores.all));
228+
AUDIT_CATEGORIES.forEach(
229+
cat => minScores.hasOwnProperty(cat) || (minScores[cat] = minScores.all)
230+
);
212231
delete minScores.all;
213232
}
214233

@@ -236,19 +255,23 @@ async function processResults(results, minScores, logFile) {
236255
console.log(`\nLighthouse version: ${lhVersion}`);
237256
console.log('\nAudit results:');
238257

239-
const maxTitleLen =
240-
Math.max(...Object.values(categories).map(({title}) => title.length));
241-
return Object.keys(categories).sort().reduce((aggr, cat) => {
242-
const {title, score} = categories[cat];
243-
const paddedTitle = `${title}:`.padEnd(maxTitleLen + 1);
244-
const minScore = minScores[cat];
245-
const passed = !isNaN(score) && (score >= minScore);
246-
247-
console.log(` - ${paddedTitle} ${formatScore(score)} (Required: ${
248-
formatScore(minScore)}) ${passed ? 'OK' : 'FAILED'}`);
249-
250-
return aggr && passed;
251-
}, true);
258+
const maxTitleLen = Math.max(...Object.values(categories).map(({title}) => title.length));
259+
return Object.keys(categories)
260+
.sort()
261+
.reduce((aggr, cat) => {
262+
const {title, score} = categories[cat];
263+
const paddedTitle = `${title}:`.padEnd(maxTitleLen + 1);
264+
const minScore = minScores[cat];
265+
const passed = !isNaN(score) && score >= minScore;
266+
267+
console.log(
268+
` - ${paddedTitle} ${formatScore(score)} (Required: ${formatScore(minScore)}) ${
269+
passed ? 'OK' : 'FAILED'
270+
}`
271+
);
272+
273+
return aggr && passed;
274+
}, true);
252275
}
253276

254277
/**
@@ -257,7 +280,6 @@ async function processResults(results, minScores, logFile) {
257280
* @param {LH.Config.Json} config
258281
*/
259282
function skipHttpsAudits(config) {
260-
console.log(
261-
` Skipping HTTPS-related audits: ${SKIPPED_HTTPS_AUDITS.join(', ')}`);
262-
config.settings = {...config.settings, skipAudits : SKIPPED_HTTPS_AUDITS};
283+
console.log(` Skipping HTTPS-related audits: ${SKIPPED_HTTPS_AUDITS.join(', ')}`);
284+
config.settings = {...config.settings, skipAudits: SKIPPED_HTTPS_AUDITS};
263285
}

0 commit comments

Comments
 (0)