It’s a been a long night.
First step were some images that were unhinged. Added :processed with imgx
where it was missing and found a 20 MB logo that I swapped for 12 KB.
Some scripts that ChatGPT gave me that helped me figure out the offenders:
[...document.images]
.map(img => ({
src: img.currentSrc || img.src,
w: img.naturalWidth, h: img.naturalHeight,
decodedMB: (img.naturalWidth * img.naturalHeight * 4) / (1024*1024)
}))
.sort((a,b)=>b.decodedMB-a.decodedMB)
.slice(0,20);
- Sum decoded memory per unique URL
(() => {
const rows = [...document.images].map(img => ({
src: img.currentSrc || img.src,
w: img.naturalWidth, h: img.naturalHeight,
decodedMB: (img.naturalWidth * img.naturalHeight * 4) / (1024*1024)
}));
const bySrc = rows.reduce((m, r) => {
const t = m.get(r.src) || {src:r.src, w:r.w, h:r.h, decodedMB:0, count:0};
t.decodedMB = Math.max(t.decodedMB, r.decodedMB); // upper bound per resource
t.count += 1;
return m.set(r.src, t);
}, new Map());
const list = [...bySrc.values()]
.sort((a,b)=>b.decodedMB-a.decodedMB);
const total = list.reduce((s,r)=>s+r.decodedMB,0);
console.table(list.slice(0,30));
console.log("≈ Unique decoded MB (upper bound):", total.toFixed(1));
})();
- Find waste: images way larger than they’re displayed
(() => {
const BAD_RATIO = 2; // natural dimension > 2× display dimension
const rows = [...document.images].map(img => {
const r = img.getBoundingClientRect();
const dispW = Math.max(1, Math.round(r.width * devicePixelRatio));
const dispH = Math.max(1, Math.round(r.height * devicePixelRatio));
const overW = img.naturalWidth / dispW;
const overH = img.naturalHeight / dispH;
return {
src: img.currentSrc || img.src,
natural: `${img.naturalWidth}×${img.naturalHeight}`,
display: `${dispW}×${dispH}`,
overW: +overW.toFixed(2),
overH: +overH.toFixed(2),
decodedMB: ((img.naturalWidth * img.naturalHeight * 4) / (1024*1024)).toFixed(2)
};
}).filter(r => r.overW > BAD_RATIO || r.overH > BAD_RATIO)
.sort((a,b)=>b.decodedMB - a.decodedMB);
console.table(rows.slice(0,50));
console.log("Oversized count:", rows.length);
})();
(() => {
const counts = {};
for (const img of document.images) {
const src = img.currentSrc || img.src;
counts[src] = (counts[src]||0) + 1;
}
const dupes = Object.entries(counts)
.filter(([,c])=>c>3)
.sort((a,b)=>b[1]-a[1]);
console.table(dupes.map(([src,c])=>({uses:c, src})).slice(0,30));
})();