Tom MacWright

2025@macwright.com

Blog micro-optimization

My last proper blog post about making a custom frame bag was very image-heavy, which has the downside of making the page heavy. I don't want inefficient pages on my website.

So I took the opportunity to tweak my optimization script. This is the script that minifies HTML, inlines critical CSS, and optimizes images. The optimization part for images looks like this now:

/**
 * @param {Number} i - the order of this image in the file
 */
async function processImage($, im, i) {
	const img = $(im);
	const src = img.attr("src");
	if (!src.startsWith("/images/")) return;
	const ext = path.extname(src);
	if (!(ext === ".jpg" || ext === ".jpeg")) return;

	const input = sharp(path.join("_site/", src));
	const metadata = await input.metadata();
	const webpSrc = src.replace(ext, `.webp`);

	const cachePath = `./.image_cache/${path.basename(webpSrc)}`;
	if (fs.existsSync(cachePath)) {
		fs.renameSync(cachePath, path.join("_site/", webpSrc));
		timings.imageCacheHits++;
	} else {
		await Promise.all([input.webp().toFile(path.join("_site/", webpSrc))]);
		timings.imageCacheMisses++;
	}

	const $picture = cheerio.load(`<picture>
    <source srcset="${webpSrc}" type="image/webp" />
  </picture>`);

	img.attr("width", String(metadata.width));
	img.attr("height", String(metadata.height));

	if (i > 2) {
		img.attr("loading", "lazy");
	}

	$picture("picture").append(img.parent().html());
	return $picture("body").html();
}

So this now does quite a bit to images! Images beyond the first two on a page get loading="lazy" - Browser-level image lazy loading, and it now adds width and height attributes to all of the images it processes so that their lazy-loading doesn't cause page-height jitter or reflow. Works pretty well! The syntax of the <picture> element always throws me for a loop a bit: the <img> inside of the <picture> essentially becomes the element shown on the page, so the lazy and dimension attributes should still go on the img element, but the other <source> elements essentially override that img element's src attribute.

As a sidenote, WebP is almost everywhere, so maybe I'll drop the picture element soon and only serve WebP.