Field Notes

The page that shipped uncompressed

Sheet N-106 · By the Oracis engineering team · · 3 min read

This site is served by a small Node server we wrote, with no dependencies: security headers, cache rules, byte ranges for video, and a redirect to the one public address. It had passed every check we ran on it. It had also been sending every page uncompressed since the day it launched.

How we found it

The security page says the site ships about 2 KB of JavaScript. After adding a script that plays the animated drawings (N-105), we went to check that the sentence was still true, and measured the bytes on the wire rather than the files on disk. The JavaScript came back the same size as the files. So did everything else.

$ curl -s -o /dev/null -D - -H 'Accept-Encoding: gzip, br' https://<site>/
content-type: text/html; charset=utf-8
x-content-type-options: nosniff

$ curl -s -H 'Accept-Encoding: gzip, br' -o /dev/null -w '%{size_download}' https://<site>/
122580

No content-encoding header, and 122,580 bytes for the home page's HTML. The browser had asked for Brotli or gzip on every request; nothing between it and our server compressed the reply, and our server did not either.

Why nothing caught it

Every check we had looked at something adjacent. The build reports file sizes. Our quality gate checks accessibility, links, layout shift and repeated media on every page. Lighthouse scored the pages well, because on a fast connection 120 KB of HTML still arrives quickly. And we had assumed the hosting platform's edge compressed responses, as many do. It does not, for this service, and we had never looked at a response header to find out.

The fix

The server now compresses text itself: HTML, CSS, JavaScript, SVG, XML, JSON and plain text. It honours what the browser says it accepts, including a coding refused with q=0:

export function pickEncoding(header) {
  const accepted = new Map();
  for (const part of String(header || '').toLowerCase().split(',')) {
    const [name, ...params] = part.trim().split(';');
    if (!name) continue;
    const q = params.map((p) => /^\s*q=([\d.]+)\s*$/.exec(p)).find(Boolean);
    accepted.set(name.trim(), q ? Number(q[1]) : 1);
  }
  for (const coding of ['br', 'gzip']) {
    const q = accepted.has(coding) ? accepted.get(coding) : accepted.get('*');
    if (q > 0) return coding;
  }
  return null;
}

Each file is compressed once, at Brotli's highest quality, and kept in memory until the file changes on disk, so the cost is paid on the first request and never again. Images, fonts and video are already compressed and pass through as they are. A byte-range request, which is how browsers fetch video, is answered from the file itself, so range offsets always mean what the client thinks they mean. Every compressible response carries Vary: Accept-Encoding, so a cache never hands a compressed body to a client that cannot read it.

$ curl -s -o /dev/null -D - -H 'Accept-Encoding: gzip, deflate, br, zstd' https://<site>/
content-encoding: br
vary: Accept-Encoding

$ curl -s -H 'Accept-Encoding: br' -o /dev/null -w '%{size_download}' https://<site>/
12216

The home page's HTML went from 122.6 KB to 12.2 KB on the wire, the case studies page from 191.6 KB to 15.8 KB, and the site's JavaScript to 1.4 KB. After the change Lighthouse scored the home page 100 on mobile, with the largest element painted in 1.2 seconds.

The tests send real requests and decode what comes back: Brotli when it is accepted, gzip when only gzip is, nothing when nothing is, the 404 page compressed with its status intact, a changed file compressed afresh, and video and byte ranges left alone.

The general lesson

Check the response, not the build. The size that matters is the one on the wire, and the header that says how it got there is one curl -D - away. We now check it in the post-deployment smoke test, next to the redirect and certificate checks.

Want this kind of engineering on your system?