Skip to content

Commit 9350ad6

Browse files
committed
refactor: code cleanup
1 parent ffbc13e commit 9350ad6

File tree

4 files changed

+130
-71
lines changed

4 files changed

+130
-71
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"author": "",
2020
"license": "MIT",
2121
"dependencies": {
22+
"chalk": "^4.1.0",
2223
"chrome-launcher": "^0.13.2",
2324
"dotenv": "^8.2.0",
2425
"http-server": "^0.12.3",

src/index.js

Lines changed: 89 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,152 @@
1-
const httpServer = require('http-server');
2-
const puppeteer = require('puppeteer');
3-
const lighthouse = require('lighthouse');
4-
const chromeLauncher = require('chrome-launcher');
51
require('dotenv').config();
2+
const httpServer = require('http-server');
3+
const chalk = require('chalk');
4+
const { getBrowserPath, runLighthouse } = require('./lighthouse');
65

7-
const getServer = (url, serveDir) => {
8-
if (url) {
9-
console.log(`Scanning url '${url}'`);
6+
const getServer = ({ serveDir, auditUrl }) => {
7+
if (auditUrl) {
108
// return a mock server for readability
119
const server = {
1210
listen: async (func) => {
11+
console.log(`Scanning url ${chalk.magenta(auditUrl)}`);
1312
await func();
1413
},
1514
close: () => undefined,
15+
url: auditUrl,
1616
};
17-
return { server, url };
17+
return { server };
1818
}
1919

2020
if (!serveDir) {
2121
throw new Error('Empty publish dir');
2222
}
2323

24-
console.log(`Serving and scanning site from directory '${serveDir}'`);
2524
const s = httpServer.createServer({ root: serveDir });
2625
const port = 5000;
2726
const host = 'localhost';
2827
const server = {
29-
listen: (func) => s.listen(port, host, func),
28+
listen: (func) => {
29+
console.log(
30+
`Serving and scanning site from directory ${chalk.magenta(serveDir)}`,
31+
);
32+
return s.listen(port, host, func);
33+
},
3034
close: () => s.close(),
35+
url: `http://${host}:${port}`,
3136
};
32-
return { url: `http://${host}:${port}`, server };
37+
return { server };
3338
};
3439

35-
const belowThreshold = (id, expected, results) => {
36-
const category = results.find((c) => c.id === id);
40+
const belowThreshold = (id, expected, categories) => {
41+
const category = categories.find((c) => c.id === id);
3742
if (!category) {
38-
console.warn('Could not find category', id);
43+
console.warn(`Could not find category ${chalk.yellow(id)}`);
3944
}
4045
const actual = category ? category.score : Number.MAX_SAFE_INTEGER;
4146
return actual < expected;
4247
};
4348

4449
const getError = (id, expected, results) => {
4550
const category = results.find((c) => c.id === id);
46-
return `Expected category '${category.title}' to be greater or equal to '${expected}' but got '${category.score}'`;
51+
return `Expected category ${chalk.magenta(
52+
category.title,
53+
)} to be greater or equal to ${chalk.green(expected)} but got ${chalk.red(
54+
category.score,
55+
)}`;
56+
};
57+
58+
const formatResults = ({ results, thresholds }) => {
59+
const categories = Object.values(
60+
results.lhr.categories,
61+
).map(({ title, score, id }) => ({ title, score, id }));
62+
63+
const categoriesBelowThreshold = Object.entries(
64+
thresholds,
65+
).filter(([id, expected]) => belowThreshold(id, expected, categories));
66+
67+
const errors = categoriesBelowThreshold.map(([id, expected]) =>
68+
getError(id, expected, categories),
69+
);
70+
71+
const summary = {
72+
results: categories.map((cat) => ({
73+
...cat,
74+
...(thresholds[cat.id] ? { threshold: thresholds[cat.id] } : {}),
75+
})),
76+
};
77+
78+
return { summary, errors };
79+
};
80+
81+
const getConfiguration = ({ constants, inputs }) => {
82+
const serveDir =
83+
(constants && constants.PUBLISH_DIR) || process.env.PUBLISH_DIR;
84+
const auditUrl = (inputs && inputs.audit_url) || process.env.AUDIT_URL;
85+
let thresholds =
86+
(inputs && inputs.thresholds) || process.env.THRESHOLDS || {};
87+
if (typeof thresholds === 'string') {
88+
thresholds = JSON.parse(thresholds);
89+
}
90+
91+
return { serveDir, auditUrl, thresholds };
92+
};
93+
94+
const getUtils = ({ utils }) => {
95+
const failBuild =
96+
(utils && utils.build && utils.build.failBuild) ||
97+
(() => {
98+
process.exitCode = 1;
99+
});
100+
101+
const show =
102+
(utils && utils.status && utils.status.show) || (() => undefined);
103+
104+
return { failBuild, show };
47105
};
48106

49107
module.exports = {
50-
onSuccess: async ({
51-
constants: { PUBLISH_DIR: serveDir = process.env.PUBLISH_DIR } = {},
52-
utils,
53-
inputs: {
54-
audit_url: auditUrl = process.env.AUDIT_URL,
55-
thresholds = process.env.THRESHOLDS || {},
56-
} = {},
57-
} = {}) => {
108+
onSuccess: async ({ constants, utils, inputs } = {}) => {
109+
const { failBuild, show } = getUtils({ utils });
110+
58111
try {
59-
utils = utils || {
60-
build: {
61-
failBuild: () => {
62-
process.exit(1);
63-
},
64-
},
65-
status: {
66-
show: () => undefined,
67-
},
68-
};
69-
70-
if (typeof thresholds === 'string') {
71-
thresholds = JSON.parse(thresholds);
72-
}
112+
const { serveDir, auditUrl, thresholds } = getConfiguration({
113+
constants,
114+
inputs,
115+
});
73116

74-
const { server, url } = getServer(auditUrl, serveDir);
75-
const browserFetcher = puppeteer.createBrowserFetcher();
76-
const revisions = await browserFetcher.localRevisions();
77-
if (revisions.length <= 0) {
78-
throw new Error('Could not find local browser');
79-
}
80-
const info = await browserFetcher.revisionInfo(revisions[0]);
117+
const { server } = getServer({ serveDir, auditUrl });
118+
119+
const browserPath = await getBrowserPath();
81120

82121
const { error, results } = await new Promise((resolve) => {
83122
server.listen(async () => {
84-
let chrome;
85123
try {
86-
chrome = await chromeLauncher.launch({
87-
chromePath: info.executablePath,
88-
chromeFlags: ['--headless', '--no-sandbox', '--disable-gpu'],
89-
});
90-
const results = await lighthouse(url, {
91-
port: chrome.port,
92-
});
93-
if (results.lhr.runtimeError) {
94-
resolve({ error: new Error(results.lhr.runtimeError.message) });
95-
}
124+
const results = await runLighthouse(browserPath, server.url);
96125
resolve({ error: false, results });
97126
} catch (error) {
98127
resolve({ error });
99128
} finally {
100-
if (chrome) {
101-
await chrome.kill().catch(() => undefined);
102-
}
103129
server.close();
104130
}
105131
});
106132
});
133+
107134
if (error) {
108135
throw error;
109136
} else {
110-
const categories = Object.values(
111-
results.lhr.categories,
112-
).map(({ title, score, id }) => ({ title, score, id }));
113-
114-
const errors = Object.entries(thresholds)
115-
.filter(([id, expected]) => belowThreshold(id, expected, categories))
116-
.map(([id, expected]) => getError(id, expected, categories));
117-
118-
const summary = JSON.stringify({ results: categories }, null, 2);
137+
const { summary, errors } = formatResults({ results, thresholds });
119138
console.log(summary);
120-
utils.status.show({
139+
show({
121140
summary,
122141
});
123142

124143
if (errors.length > 0) {
125-
throw new Error(errors.join('\n'));
144+
throw new Error(`\n${errors.join('\n')}`);
126145
}
127146
}
128147
} catch (error) {
129148
console.error(`\nError: ${error.message}\n`);
130-
utils.build.failBuild(`failed with error: ${error.message}`);
149+
failBuild(`Failed with error: ${error.message}`);
131150
}
132151
},
133152
};

src/lighthouse.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const puppeteer = require('puppeteer');
2+
const lighthouse = require('lighthouse');
3+
const chromeLauncher = require('chrome-launcher');
4+
5+
const getBrowserPath = async () => {
6+
const browserFetcher = puppeteer.createBrowserFetcher();
7+
const revisions = await browserFetcher.localRevisions();
8+
if (revisions.length <= 0) {
9+
throw new Error('Could not find local browser');
10+
}
11+
const info = await browserFetcher.revisionInfo(revisions[0]);
12+
return info.executablePath;
13+
};
14+
15+
const runLighthouse = async (browserPath, url) => {
16+
let chrome;
17+
try {
18+
chrome = await chromeLauncher.launch({
19+
chromePath: browserPath,
20+
chromeFlags: ['--headless', '--no-sandbox', '--disable-gpu'],
21+
});
22+
const results = await lighthouse(url, {
23+
port: chrome.port,
24+
});
25+
if (results.lhr.runtimeError) {
26+
throw new Error(results.lhr.runtimeError.message);
27+
}
28+
return results;
29+
} finally {
30+
if (chrome) {
31+
await chrome.kill().catch(() => undefined);
32+
}
33+
}
34+
};
35+
36+
module.exports = {
37+
getBrowserPath,
38+
runLighthouse,
39+
};

yarn.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ chalk@^3.0.0:
538538
ansi-styles "^4.1.0"
539539
supports-color "^7.1.0"
540540

541-
chalk@^4.0.0:
541+
chalk@^4.0.0, chalk@^4.1.0:
542542
version "4.1.0"
543543
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
544544
integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==

0 commit comments

Comments
 (0)