@coralreefventures/site-tools 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/bin/reef-lighthouse.js +7 -4
- package/dist/bin/reef-lighthouse.js.map +1 -1
- package/dist/lighthouse.d.ts +17 -0
- package/dist/lighthouse.d.ts.map +1 -1
- package/dist/lighthouse.js +24 -3
- package/dist/lighthouse.js.map +1 -1
- package/package.json +1 -1
- package/src/bin/reef-lighthouse.ts +7 -4
- package/src/lighthouse.ts +42 -3
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ products' scripts go. The third locks a site behind the door.
|
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
8
|
reef-serve [--root out] [--port 3140]
|
|
9
|
-
reef-lighthouse [--root out] [--reports lighthouse] [--port 3160] [--threshold 90] [--retries 2] [--chrome <path>] [path ...]
|
|
9
|
+
reef-lighthouse [--root out] [--reports lighthouse] [--port 3160] [--threshold 90] [--retries 2] [--shard 1/3] [--chrome <path>] [path ...]
|
|
10
10
|
reef-door-bundle --site <id> [--out out] --door-url <url> --hosts <h1,h2> --jwks-url <url> [--signout-chain id=host,...]
|
|
11
11
|
[--name <display name>] [--mark <file>] [--mark-dark <file>] [--accent #rrggbb] [--accent-dark #rrggbb]
|
|
12
12
|
```
|
|
@@ -27,7 +27,10 @@ a performance score swings a few points between runs of the same page on a share
|
|
|
27
27
|
not fail a gate three runs would pass, while a page every run finds low still fails. A page under it then fails the
|
|
28
28
|
run and leaves its last report in `--reports`. A category's own floor (`--performance 85`) stands in for the
|
|
29
29
|
threshold for that category alone, where a site's shell puts every page a few points under 90 on a shared runner
|
|
30
|
-
while the other three categories hold at 90.
|
|
30
|
+
while the other three categories hold at 90. `--shard <index>/<count>` measures one share of the pages, every
|
|
31
|
+
`count`-th from the `index`-th (1-based, as Playwright's `--shard`), so a site whose gate outgrows one runner splits it
|
|
32
|
+
across a CI matrix: Lighthouse measures one page at a time, about 14 seconds each on a CI runner, and pages measured side
|
|
33
|
+
by side on one runner would skew each other's performance scores. Lighthouse itself is not a dependency, because it
|
|
31
34
|
bundles axe-core (MPL-2.0), which is outside the family's licence allowlist; it runs through `pnpm dlx`, pinned
|
|
32
35
|
(`--lighthouse-version`). Chrome is Playwright's Chromium when `@playwright/test` is installed beside this package,
|
|
33
36
|
or `--chrome`.
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { parseArgs } from "node:util";
|
|
3
|
-
import { categories, runLighthouse } from "../lighthouse.js";
|
|
3
|
+
import { categories, parseShard, runLighthouse } from "../lighthouse.js";
|
|
4
4
|
/**
|
|
5
5
|
* reef-lighthouse [--root out] [--reports lighthouse] [--port N] [--threshold 90] [--retries 2] [--performance N]
|
|
6
|
-
* [--accessibility N] [--best-practices N] [--seo N] [--chrome <path>] [path ...]
|
|
6
|
+
* [--accessibility N] [--best-practices N] [--seo N] [--shard <index>/<count>] [--chrome <path>] [path ...]
|
|
7
7
|
*
|
|
8
8
|
* Lighthouse on every page in the export's sitemap, or the paths given, each category at the threshold or above. The
|
|
9
9
|
* export is served on a free port unless --port pins one (Streamlane's run met EADDRINUSE on a fixed 3160). A page
|
|
10
10
|
* under the threshold is measured again, up to --retries more times, and the median of its runs decides, since a
|
|
11
11
|
* performance score swings a few points between runs on a shared runner. Exits 1 with the failing pages named when
|
|
12
12
|
* one is under, and leaves their reports in --reports. A category's own floor (--performance 85) stands in for the
|
|
13
|
-
* threshold for that category alone.
|
|
13
|
+
* threshold for that category alone. --shard 2/3 measures every third page from the second, so a gate splits across
|
|
14
|
+
* runners.
|
|
14
15
|
*/
|
|
15
16
|
const { values, positionals } = parseArgs({
|
|
16
17
|
allowPositionals: true,
|
|
@@ -24,13 +25,14 @@ const { values, positionals } = parseArgs({
|
|
|
24
25
|
accessibility: { type: "string" },
|
|
25
26
|
"best-practices": { type: "string" },
|
|
26
27
|
seo: { type: "string" },
|
|
28
|
+
shard: { type: "string" },
|
|
27
29
|
chrome: { type: "string" },
|
|
28
30
|
"lighthouse-version": { type: "string", default: "13.5.0" },
|
|
29
31
|
help: { type: "boolean", short: "h" },
|
|
30
32
|
},
|
|
31
33
|
});
|
|
32
34
|
if (values.help) {
|
|
33
|
-
console.log("reef-lighthouse [--root out] [--reports lighthouse] [--port N] [--threshold 90] [--retries 2] [--performance N] [--accessibility N] [--best-practices N] [--seo N] [--chrome <path>] [path ...]");
|
|
35
|
+
console.log("reef-lighthouse [--root out] [--reports lighthouse] [--port N] [--threshold 90] [--retries 2] [--performance N] [--accessibility N] [--best-practices N] [--seo N] [--shard <index>/<count>] [--chrome <path>] [path ...]");
|
|
34
36
|
process.exit(0);
|
|
35
37
|
}
|
|
36
38
|
const threshold = Number(values.threshold) / 100;
|
|
@@ -43,6 +45,7 @@ const results = await runLighthouse({
|
|
|
43
45
|
retries: Number(values.retries),
|
|
44
46
|
thresholds,
|
|
45
47
|
paths: positionals,
|
|
48
|
+
...(values.shard !== undefined && { shard: parseShard(values.shard) }),
|
|
46
49
|
lighthouseVersion: values["lighthouse-version"],
|
|
47
50
|
...(values.chrome !== undefined && { chrome: values.chrome }),
|
|
48
51
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reef-lighthouse.js","sourceRoot":"","sources":["../../src/bin/reef-lighthouse.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"reef-lighthouse.js","sourceRoot":"","sources":["../../src/bin/reef-lighthouse.ts"],"names":[],"mappings":"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"}
|
package/dist/lighthouse.d.ts
CHANGED
|
@@ -16,6 +16,12 @@ export type LighthouseOptions = {
|
|
|
16
16
|
thresholds?: Partial<Record<Category, number>>;
|
|
17
17
|
/** The pages to audit; every page in the export's sitemap when none are given. */
|
|
18
18
|
paths?: readonly string[];
|
|
19
|
+
/**
|
|
20
|
+
* One share of the pages, for a gate split across runners: shard `index` of `count`, 1-based as Playwright's
|
|
21
|
+
* `--shard` is. Lighthouse measures one page at a time, about 14 seconds each on a CI runner, and running pages side
|
|
22
|
+
* by side on one runner would skew the performance scores it measures; separate runners do not.
|
|
23
|
+
*/
|
|
24
|
+
shard?: Shard;
|
|
19
25
|
/**
|
|
20
26
|
* How many more times a page under the threshold is measured; 2 by default, so a page gets three runs and the
|
|
21
27
|
* median of each category's scores. Performance on a shared runner swings a few points between runs of the same
|
|
@@ -45,6 +51,17 @@ export declare const judge: (runs: readonly Record<Category, number>[], threshol
|
|
|
45
51
|
scores: Record<Category, number>;
|
|
46
52
|
low: Category[];
|
|
47
53
|
};
|
|
54
|
+
export type Shard = {
|
|
55
|
+
index: number;
|
|
56
|
+
count: number;
|
|
57
|
+
};
|
|
58
|
+
/** `2/3` as a shard, refusing anything but a whole index from 1 to a whole count of at least 1. */
|
|
59
|
+
export declare const parseShard: (text: string) => Shard;
|
|
60
|
+
/**
|
|
61
|
+
* Shard `index` of `count`: every `count`-th page, starting at the `index`-th, so the shards are within one page of the
|
|
62
|
+
* same size and pages of one kind, which sit together in a sitemap, are spread across them.
|
|
63
|
+
*/
|
|
64
|
+
export declare const shardOf: <Page>(pages: readonly Page[], { index, count }: Shard) => Page[];
|
|
48
65
|
/** Every page's path from the export's sitemap, whatever origin the sitemap names. */
|
|
49
66
|
export declare const pagesFromSitemap: (root: string) => Promise<string[]>;
|
|
50
67
|
/** The report file a page's audit is written to: `/` is `home`, `/docs/security/` is `docs-security`. */
|
package/dist/lighthouse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lighthouse.d.ts","sourceRoot":"","sources":["../src/lighthouse.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,UAAU,oEAAqE,CAAC;AAC7F,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kHAAkH;IAClH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,kFAAkF;IAClF,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,0FAA0F;IAC1F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjC,0CAA0C;IAC1C,GAAG,EAAE,QAAQ,EAAE,CAAC;IAChB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,MAAM,GAAI,QAAQ,SAAS,MAAM,EAAE,KAAG,MASlD,CAAC;AAEF,mGAAmG;AACnG,eAAO,MAAM,KAAK,GAChB,MAAM,SAAS,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EACzC,WAAW,MAAM,EACjB,aAAY,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAM,KACjD;IAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAAC,GAAG,EAAE,QAAQ,EAAE,CAAA;CAKrD,CAAC;
|
|
1
|
+
{"version":3,"file":"lighthouse.d.ts","sourceRoot":"","sources":["../src/lighthouse.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,UAAU,oEAAqE,CAAC;AAC7F,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kHAAkH;IAClH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,kFAAkF;IAClF,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;;OAIG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,0FAA0F;IAC1F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjC,0CAA0C;IAC1C,GAAG,EAAE,QAAQ,EAAE,CAAC;IAChB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,MAAM,GAAI,QAAQ,SAAS,MAAM,EAAE,KAAG,MASlD,CAAC;AAEF,mGAAmG;AACnG,eAAO,MAAM,KAAK,GAChB,MAAM,SAAS,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EACzC,WAAW,MAAM,EACjB,aAAY,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAM,KACjD;IAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAAC,GAAG,EAAE,QAAQ,EAAE,CAAA;CAKrD,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD,mGAAmG;AACnG,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,KAQzC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,OAAO,GAAI,IAAI,EAAE,OAAO,SAAS,IAAI,EAAE,EAAE,kBAAkB,KAAK,KAAG,IAAI,EACrB,CAAC;AAIhE,sFAAsF;AACtF,eAAO,MAAM,gBAAgB,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,MAAM,EAAE,CAGrE,CAAC;AAEF,yGAAyG;AACzG,eAAO,MAAM,UAAU,GAAI,WAAW,MAAM,EAAE,UAAU,MAAM,WACyB,CAAC;AA4ExF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAU,UAAS,iBAAsB,KAAG,OAAO,CAAC,UAAU,EAAE,CAqCzF,CAAC"}
|
package/dist/lighthouse.js
CHANGED
|
@@ -27,6 +27,21 @@ export const judge = (runs, threshold, thresholds = {}) => {
|
|
|
27
27
|
const scores = Object.fromEntries(categories.map((category) => [category, median(runs.map((run) => run[category]))]));
|
|
28
28
|
return { scores, low: categories.filter((category) => scores[category] < (thresholds[category] ?? threshold)) };
|
|
29
29
|
};
|
|
30
|
+
/** `2/3` as a shard, refusing anything but a whole index from 1 to a whole count of at least 1. */
|
|
31
|
+
export const parseShard = (text) => {
|
|
32
|
+
const match = /^(\d+)\/(\d+)$/.exec(text.trim());
|
|
33
|
+
const index = Number(match?.[1]);
|
|
34
|
+
const count = Number(match?.[2]);
|
|
35
|
+
if (!match || count < 1 || index < 1 || index > count) {
|
|
36
|
+
throw new Error(`--shard takes <index>/<count>, with the index from 1 to the count, such as 2/3: not "${text}"`);
|
|
37
|
+
}
|
|
38
|
+
return { index, count };
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Shard `index` of `count`: every `count`-th page, starting at the `index`-th, so the shards are within one page of the
|
|
42
|
+
* same size and pages of one kind, which sit together in a sitemap, are spread across them.
|
|
43
|
+
*/
|
|
44
|
+
export const shardOf = (pages, { index, count }) => pages.filter((_, position) => position % count === index - 1);
|
|
30
45
|
/** Every page's path from the export's sitemap, whatever origin the sitemap names. */
|
|
31
46
|
export const pagesFromSitemap = async (root) => {
|
|
32
47
|
const sitemap = await readFile(path.join(root, "sitemap.xml"), "utf8");
|
|
@@ -100,7 +115,8 @@ export const runLighthouse = async (options = {}) => {
|
|
|
100
115
|
const thresholds = options.thresholds ?? {};
|
|
101
116
|
const version = options.lighthouseVersion ?? "13.5.0";
|
|
102
117
|
const log = options.log ?? console.log;
|
|
103
|
-
const
|
|
118
|
+
const every = options.paths?.length ? options.paths : await pagesFromSitemap(root);
|
|
119
|
+
const paths = options.shard ? shardOf(every, options.shard) : every;
|
|
104
120
|
const chrome = options.chrome ?? (await playwrightChromium());
|
|
105
121
|
const { server, url: origin } = await serve({ root, port: options.port ?? 0 });
|
|
106
122
|
const results = [];
|
|
@@ -127,11 +143,16 @@ export const runLighthouse = async (options = {}) => {
|
|
|
127
143
|
finally {
|
|
128
144
|
server.close();
|
|
129
145
|
}
|
|
146
|
+
log(summary(paths.length, every.length, options.shard, threshold, thresholds));
|
|
147
|
+
return results;
|
|
148
|
+
};
|
|
149
|
+
/** The run's last line: what was measured, how many pages (of how many, for a shard), and the floors. */
|
|
150
|
+
const summary = (measured, every, shard, threshold, thresholds) => {
|
|
151
|
+
const share = shard ? ` (shard ${shard.index} of ${shard.count}, of ${every})` : "";
|
|
130
152
|
const floors = categories
|
|
131
153
|
.filter((category) => thresholds[category] !== undefined)
|
|
132
154
|
.map((category) => `, ${category} ${(thresholds[category] ?? 0) * 100}`)
|
|
133
155
|
.join("");
|
|
134
|
-
|
|
135
|
-
return results;
|
|
156
|
+
return `\n${categories.join(", ")}; ${measured} pages${share}, threshold ${threshold * 100}${floors}`;
|
|
136
157
|
};
|
|
137
158
|
//# sourceMappingURL=lighthouse.js.map
|
package/dist/lighthouse.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lighthouse.js","sourceRoot":"","sources":["../src/lighthouse.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,aAAa,EAAE,eAAe,EAAE,gBAAgB,EAAE,KAAK,CAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"lighthouse.js","sourceRoot":"","sources":["../src/lighthouse.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,aAAa,EAAE,eAAe,EAAE,gBAAgB,EAAE,KAAK,CAAU,CAAC;AAiD7F,8FAA8F;AAC9F,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,MAAyB,EAAU,EAAE;IAC1D,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC;QAC5B,CAAC,CAAE,MAAM,CAAC,MAAM,CAAY;QAC5B,CAAC,CAAC,CAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAY,GAAI,MAAM,CAAC,MAAM,CAAY,CAAC,GAAG,CAAC,CAAC;AACxE,CAAC,CAAC;AAEF,mGAAmG;AACnG,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,IAAyC,EACzC,SAAiB,EACjB,aAAgD,EAAE,EACK,EAAE;IACzD,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAC/B,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CACvD,CAAC;IAC9B,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,CAAC,EAAE,CAAC;AAClH,CAAC,CAAC;AAIF,mGAAmG;AACnG,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAS,EAAE;IAChD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,CAAC,KAAK,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,KAAK,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,wFAAwF,IAAI,GAAG,CAAC,CAAC;IACnH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAO,KAAsB,EAAE,EAAE,KAAK,EAAE,KAAK,EAAS,EAAU,EAAE,CACvF,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,GAAG,KAAK,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;AAIhE,sFAAsF;AACtF,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAAE,IAAY,EAAqB,EAAE;IACxE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC;IACvE,OAAO,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;AACxG,CAAC,CAAC;AAEF,yGAAyG;AACzG,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,SAAiB,EAAE,QAAgB,EAAE,EAAE,CAChE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC;AAExF;;;GAGG;AACH,MAAM,kBAAkB,GAAG,KAAK,IAAiC,EAAE;IACjE,MAAM,SAAS,GAAG,kBAAkB,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,CAAC,MAAM,MAAM,kCAAC,SAAS,EAAC,CAAmD,CAAC;QAC/F,OAAO,UAAU,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,KAAK,GAAG,CAAC,GAAW,EAAE,IAAY,EAAE,OAAe,EAAE,MAA0B,EAAE,EAAE,CACvF,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IACpC,MAAM,GAAG,GAAG,KAAK,CACf,MAAM,EACN;QACE,KAAK;QACL,cAAc,OAAO,EAAE;QACvB,GAAG;QACH,qBAAqB,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QAC3C,eAAe;QACf,eAAe;QACf,iBAAiB,IAAI,EAAE;QACvB,4CAA4C;QAC5C,SAAS;KACV,EACD,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAC5G,CAAC;IACF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,IAAI,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACrH,CAAC,CAAC,CAAC;AAYL,MAAM,KAAK,GAAG,CAAC,MAAgC,EAAE,EAAE,CACjD,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAE9E,oHAAoH;AACpH,MAAM,WAAW,GAAG,KAAK,EAAE,QAAgB,EAAE,IAAY,EAAE,OAAgB,EAAuB,EAAE;IAClG,MAAM,IAAI,GAA+B,EAAE,CAAC;IAC5C,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IACjE,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACvF,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QACnF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,GAAG,IAAI,cAAc,EAAE,MAAM,CAAC,CAAW,CAAC;QACnF,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAC/B,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,CACtD,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClB,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QAC7D,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAC7D,OAAO,CAAC,GAAG,CAAC,SAAS,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,MAAM,OAAO,OAAO,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;QAChH,CAAC;IACH,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,IAAI,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;IAC9G,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AACzF,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,UAA6B,EAAE,EAAyB,EAAE;IAC5F,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,KAAK,CAAC;IACnC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,YAAY,CAAC;IACpD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,GAAG,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,iBAAiB,IAAI,QAAQ,CAAC;IACtD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACnF,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACpE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,kBAAkB,EAAE,CAAC,CAAC;IAC9D,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/E,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,IAAI,EAAE;gBAC/C,MAAM;gBACN,OAAO;gBACP,MAAM;gBACN,SAAS;gBACT,UAAU;gBACV,OAAO;gBACP,GAAG;aACJ,CAAC,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrB,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,MAAM,EAAE,CAAC,GAAG,IAAI,cAAc,CAAC,CAAC;gBAChC,MAAM,EAAE,CAAC,GAAG,IAAI,cAAc,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;IACD,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;IAC/E,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF,yGAAyG;AACzG,MAAM,OAAO,GAAG,CACd,QAAgB,EAChB,KAAa,EACb,KAAwB,EACxB,SAAiB,EACjB,UAA6C,EAC7C,EAAE;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,KAAK,OAAO,KAAK,CAAC,KAAK,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACpF,MAAM,MAAM,GAAG,UAAU;SACtB,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC;SACxD,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC;SACvE,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,KAAK,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,QAAQ,SAAS,KAAK,eAAe,SAAS,GAAG,GAAG,GAAG,MAAM,EAAE,CAAC;AACxG,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coralreefventures/site-tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Command-line tools for a Coral Reef public site: serve the static export as the host does, gate it with Lighthouse, and lock it behind the door.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { parseArgs } from "node:util";
|
|
3
3
|
|
|
4
|
-
import { categories, runLighthouse } from "../lighthouse.ts";
|
|
4
|
+
import { categories, parseShard, runLighthouse } from "../lighthouse.ts";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* reef-lighthouse [--root out] [--reports lighthouse] [--port N] [--threshold 90] [--retries 2] [--performance N]
|
|
8
|
-
* [--accessibility N] [--best-practices N] [--seo N] [--chrome <path>] [path ...]
|
|
8
|
+
* [--accessibility N] [--best-practices N] [--seo N] [--shard <index>/<count>] [--chrome <path>] [path ...]
|
|
9
9
|
*
|
|
10
10
|
* Lighthouse on every page in the export's sitemap, or the paths given, each category at the threshold or above. The
|
|
11
11
|
* export is served on a free port unless --port pins one (Streamlane's run met EADDRINUSE on a fixed 3160). A page
|
|
12
12
|
* under the threshold is measured again, up to --retries more times, and the median of its runs decides, since a
|
|
13
13
|
* performance score swings a few points between runs on a shared runner. Exits 1 with the failing pages named when
|
|
14
14
|
* one is under, and leaves their reports in --reports. A category's own floor (--performance 85) stands in for the
|
|
15
|
-
* threshold for that category alone.
|
|
15
|
+
* threshold for that category alone. --shard 2/3 measures every third page from the second, so a gate splits across
|
|
16
|
+
* runners.
|
|
16
17
|
*/
|
|
17
18
|
const { values, positionals } = parseArgs({
|
|
18
19
|
allowPositionals: true,
|
|
@@ -26,6 +27,7 @@ const { values, positionals } = parseArgs({
|
|
|
26
27
|
accessibility: { type: "string" },
|
|
27
28
|
"best-practices": { type: "string" },
|
|
28
29
|
seo: { type: "string" },
|
|
30
|
+
shard: { type: "string" },
|
|
29
31
|
chrome: { type: "string" },
|
|
30
32
|
"lighthouse-version": { type: "string", default: "13.5.0" },
|
|
31
33
|
help: { type: "boolean", short: "h" },
|
|
@@ -34,7 +36,7 @@ const { values, positionals } = parseArgs({
|
|
|
34
36
|
|
|
35
37
|
if (values.help) {
|
|
36
38
|
console.log(
|
|
37
|
-
"reef-lighthouse [--root out] [--reports lighthouse] [--port N] [--threshold 90] [--retries 2] [--performance N] [--accessibility N] [--best-practices N] [--seo N] [--chrome <path>] [path ...]",
|
|
39
|
+
"reef-lighthouse [--root out] [--reports lighthouse] [--port N] [--threshold 90] [--retries 2] [--performance N] [--accessibility N] [--best-practices N] [--seo N] [--shard <index>/<count>] [--chrome <path>] [path ...]",
|
|
38
40
|
);
|
|
39
41
|
process.exit(0);
|
|
40
42
|
}
|
|
@@ -53,6 +55,7 @@ const results = await runLighthouse({
|
|
|
53
55
|
retries: Number(values.retries),
|
|
54
56
|
thresholds,
|
|
55
57
|
paths: positionals,
|
|
58
|
+
...(values.shard !== undefined && { shard: parseShard(values.shard) }),
|
|
56
59
|
lighthouseVersion: values["lighthouse-version"],
|
|
57
60
|
...(values.chrome !== undefined && { chrome: values.chrome }),
|
|
58
61
|
});
|
package/src/lighthouse.ts
CHANGED
|
@@ -23,6 +23,12 @@ export type LighthouseOptions = {
|
|
|
23
23
|
thresholds?: Partial<Record<Category, number>>;
|
|
24
24
|
/** The pages to audit; every page in the export's sitemap when none are given. */
|
|
25
25
|
paths?: readonly string[];
|
|
26
|
+
/**
|
|
27
|
+
* One share of the pages, for a gate split across runners: shard `index` of `count`, 1-based as Playwright's
|
|
28
|
+
* `--shard` is. Lighthouse measures one page at a time, about 14 seconds each on a CI runner, and running pages side
|
|
29
|
+
* by side on one runner would skew the performance scores it measures; separate runners do not.
|
|
30
|
+
*/
|
|
31
|
+
shard?: Shard;
|
|
26
32
|
/**
|
|
27
33
|
* How many more times a page under the threshold is measured; 2 by default, so a page gets three runs and the
|
|
28
34
|
* median of each category's scores. Performance on a shared runner swings a few points between runs of the same
|
|
@@ -71,6 +77,26 @@ export const judge = (
|
|
|
71
77
|
return { scores, low: categories.filter((category) => scores[category] < (thresholds[category] ?? threshold)) };
|
|
72
78
|
};
|
|
73
79
|
|
|
80
|
+
export type Shard = { index: number; count: number };
|
|
81
|
+
|
|
82
|
+
/** `2/3` as a shard, refusing anything but a whole index from 1 to a whole count of at least 1. */
|
|
83
|
+
export const parseShard = (text: string): Shard => {
|
|
84
|
+
const match = /^(\d+)\/(\d+)$/.exec(text.trim());
|
|
85
|
+
const index = Number(match?.[1]);
|
|
86
|
+
const count = Number(match?.[2]);
|
|
87
|
+
if (!match || count < 1 || index < 1 || index > count) {
|
|
88
|
+
throw new Error(`--shard takes <index>/<count>, with the index from 1 to the count, such as 2/3: not "${text}"`);
|
|
89
|
+
}
|
|
90
|
+
return { index, count };
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Shard `index` of `count`: every `count`-th page, starting at the `index`-th, so the shards are within one page of the
|
|
95
|
+
* same size and pages of one kind, which sit together in a sitemap, are spread across them.
|
|
96
|
+
*/
|
|
97
|
+
export const shardOf = <Page>(pages: readonly Page[], { index, count }: Shard): Page[] =>
|
|
98
|
+
pages.filter((_, position) => position % count === index - 1);
|
|
99
|
+
|
|
74
100
|
type Report = { categories: Record<string, { score: number | null } | undefined> };
|
|
75
101
|
|
|
76
102
|
/** Every page's path from the export's sitemap, whatever origin the sitemap names. */
|
|
@@ -170,7 +196,8 @@ export const runLighthouse = async (options: LighthouseOptions = {}): Promise<Pa
|
|
|
170
196
|
const thresholds = options.thresholds ?? {};
|
|
171
197
|
const version = options.lighthouseVersion ?? "13.5.0";
|
|
172
198
|
const log = options.log ?? console.log;
|
|
173
|
-
const
|
|
199
|
+
const every = options.paths?.length ? options.paths : await pagesFromSitemap(root);
|
|
200
|
+
const paths = options.shard ? shardOf(every, options.shard) : every;
|
|
174
201
|
const chrome = options.chrome ?? (await playwrightChromium());
|
|
175
202
|
const { server, url: origin } = await serve({ root, port: options.port ?? 0 });
|
|
176
203
|
const results: PageResult[] = [];
|
|
@@ -196,10 +223,22 @@ export const runLighthouse = async (options: LighthouseOptions = {}): Promise<Pa
|
|
|
196
223
|
} finally {
|
|
197
224
|
server.close();
|
|
198
225
|
}
|
|
226
|
+
log(summary(paths.length, every.length, options.shard, threshold, thresholds));
|
|
227
|
+
return results;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
/** The run's last line: what was measured, how many pages (of how many, for a shard), and the floors. */
|
|
231
|
+
const summary = (
|
|
232
|
+
measured: number,
|
|
233
|
+
every: number,
|
|
234
|
+
shard: Shard | undefined,
|
|
235
|
+
threshold: number,
|
|
236
|
+
thresholds: Partial<Record<Category, number>>,
|
|
237
|
+
) => {
|
|
238
|
+
const share = shard ? ` (shard ${shard.index} of ${shard.count}, of ${every})` : "";
|
|
199
239
|
const floors = categories
|
|
200
240
|
.filter((category) => thresholds[category] !== undefined)
|
|
201
241
|
.map((category) => `, ${category} ${(thresholds[category] ?? 0) * 100}`)
|
|
202
242
|
.join("");
|
|
203
|
-
|
|
204
|
-
return results;
|
|
243
|
+
return `\n${categories.join(", ")}; ${measured} pages${share}, threshold ${threshold * 100}${floors}`;
|
|
205
244
|
};
|