From 3.3 MB to 180 KB, the image diet behind a fast landing page
A premium product needs big, beautiful photos, and a paid-traffic page needs to load on a phone in a basement car park. A small Node pipeline that gets you both.
The problem
The ads landing page carried 3.3 MB of photos.
The solution
A sharp pipeline: WebP, exact display sizes and lazy loading.
Luxury sells on photography. A premium home-automation brand can’t use small, muddy images. But people arrive at an ads landing page on phones, often on patchy mobile data, and every extra second on a slow load loses some of them.
The question wasn’t “big images or fast page”. It was how to serve images that look big without weighing much.
Where the weight was
The source folder was what you’d expect from a design team: camera exports and renders of up to 16–17 MB each. After a first round of compression the page still pulled about 3.3 MB of images:
| Image set | Before | After |
|---|---|---|
| Hero | 1,772 KB | 35 KB |
| Two experience-centre photos | 429 KB | 53 KB |
| Five project photos | 393 KB | 73 KB |
| Six product cut-outs (PNG) | 701 KB | 22 KB |
Step 1: convert
convert-webp.js runs every source image through sharp and writes WebP at quality 82. At that setting I couldn’t see a difference on a phone, and the files are a fraction of the size. Product cut-outs that had been huge transparent PNGs gained the most.
Step 2: resize to the layout, not the camera
Most of the waste wasn’t compression; it was pixels nobody sees. A 4,000 px photo shown in a 600 px card makes the phone download and then throw away almost everything. resize-for-cdn.js crops and resizes each image to the exact size it displays at, so Lighthouse reports no wasted bytes.
Step 3: let the browser help
- Every image goes through
<picture>with WebP first and JPG or PNG as the fallback. - Every image has explicit
widthandheight, so nothing jumps as it loads. - Everything below the fold is
loading="lazy": 32 images in all. - The hero is preloaded with
fetchpriority="high", and the CDN gets apreconnect.
What else came out of the critical path
- An icon font was replaced with a handful of inline SVGs.
- The web font loads asynchronously, and the theme CSS is inlined.
- The tag manager waits for the first interaction, or a timeout, before loading.
Result
The images went from about 3.3 MB to about 0.18 MB, 94% lighter, with no visible loss on a phone. The page still looks like a luxury brand; it just doesn’t make visitors pay for it in mobile data.