doxa-maps/internal/check-grid-image-loading.mjs
Doxa Maps 2e72d59f35 Keep the reasons, drop the speaker, in the two merged branches
The consolidation brought back two Driver citations from older branches that
the reference sweep had already cleared from development. Both keep their
engineering reason and lose the speaker: a gate's rationale for existing, and
the mechanism of the print collapse.

Caught by check:no-new-driver-references, which is the point of running the
full chain rather than the seven gates the merged package.json had left.
2026-09-29 14:46:07 +00:00

71 lines
3.7 KiB
JavaScript

#!/usr/bin/env node
/**
* check-grid-image-loading — the people-group cards must not fetch 24 photos during boot.
*
* THE MEASUREMENT (rega, SR-LOAD on 21ebb4f26): a cold load of Simple Research downloaded 24
* people-group photos, 5.3 MB, DURING BOOT — competing with the map engine and the API data on the
* same connection. Nothing was wrong with any single image; there was simply no instruction about
* WHEN to fetch them, so the browser fetched them all at once.
*
* ★ WHY A GATE AND NOT JUST THE FIX. This component is being MERGED with the regions list right now
* (a settled decision, regions-plugin building it), and a merge rewrites markup. Four attributes on
* one <img> are exactly the kind of thing that survives a review and not a rewrite — and losing them
* is invisible: the page still works, it just costs 5.3 MB again on every cold load.
*
* ★ AND IT ASSERTS THE FIRST ROW IS EAGER, which is the half a naive "add loading=lazy everywhere"
* would get wrong. Lazy-loading what the reader is already looking at trades a visible flash of empty
* cards for bytes nobody saves.
*
* Exit 0 pass · 1 fail.
*/
import { readFileSync } from 'node:fs'
import { resolve, dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
const TAG = 'GRID-IMAGE-LOADING'
const F = 'plugin-designs/people-groups-grid/people-groups-grid.vue'
const fails = []
const src = readFileSync(join(ROOT, F), 'utf8')
const m = src.match(/<img\b[^>]*class="uupg__image"[^>]*>/s)
if (!m) {
fails.push(`${F}: the card image element was not found — it was renamed or restructured, and this `
+ 'gate would pass while checking nothing. Re-point it before trusting a green run.')
} else {
const tag = m[0]
if (!/:loading=/.test(tag)) {
fails.push('the card image has no loading attribute, so every photo is fetched during boot — '
+ 'rega measured 24 of them, 5.3 MB, competing with the map and the API data.')
}
if (!/decoding="async"/.test(tag)) fails.push('the card image does not decode off the main thread (decoding="async").')
if (!/\bwidth=/.test(tag) || !/\bheight=/.test(tag)) {
fails.push('the card image states no intrinsic size, so the box is unreserved before the '
+ 'stylesheet applies. (.uupg__image\'s aspect-ratio holds it afterwards; these cover the gap.)')
}
if (!/:fetchpriority=/.test(tag)) fails.push('off-screen images are not de-prioritised (fetchpriority).')
// ★ the first row must be EAGER — a bare loading="lazy" would pass every check above and be wrong.
if (/loading="lazy"/.test(tag) && !/:loading=/.test(tag)) {
fails.push('the card image is UNCONDITIONALLY lazy, so the row the reader is already looking at '
+ 'loads late. The first row must stay eager.')
}
if (!/EAGER_IMAGES/.test(tag)) {
fails.push('the eager/lazy split is not keyed on EAGER_IMAGES, so nothing ties it to the column count.')
}
}
// and the constant must exist and be a plausible first-row ceiling
const c = src.match(/const EAGER_IMAGES\s*=\s*(\d+)/)
if (!c) fails.push('EAGER_IMAGES is gone; the first-row exemption has no source.')
else if (Number(c[1]) < 3 || Number(c[1]) > 8) {
fails.push(`EAGER_IMAGES is ${c[1]} — the grid is repeat(auto-fill, minmax(240px, 1fr)), 1 column on a `
+ 'phone and 3-5 on a desktop, so a first-row ceiling outside 3..8 is either short (a visible '
+ 'lazy-load in view) or so generous it undoes the saving.')
}
if (fails.length) {
console.error(`${TAG}: FAIL`)
for (const f of fails) console.error(` ✗ ${f}`)
process.exit(1)
}
console.log(`${TAG}: PASS — card photos past the first row load lazily, at low priority, decoded off the main `
+ 'thread, with their box reserved; the first row stays eager.')