By Shehab Waleed, Founder, Cairo Studio 3 min read
During a performance pass on our site, we looked at the size of the HTML itself, before any image or script. The homepage was 275KB. The universe page was 265KB. A service page was 400KB. None of them show anywhere near that much text.
Where the bytes came from
A SvelteKit page renders on the server, then hydrates in the browser. To hydrate, the browser needs the same data the server used, so SvelteKit writes the return value of every server load into the HTML as a script. Whatever the load returns, the visitor downloads.
Our loads returned what Prismic returned. The homepage carousel needed a title, a slug and a poster for each project. It received each project whole: galleries, credits, every slice on the case study. Service pages carried the full bodies of their related services, which are whole pages of their own.
Return what the component reads
The fix is dull and it works. For each loader we listed the fields its components read, and returned only those. Two helpers do most of it. One drops named fields from a document:
function omitData(doc, keys) {
return {
...doc,
data: Object.fromEntries(
Object.entries(doc.data)
.filter(([key]) => !keys.includes(key))
)
};
}The other builds a small object for each project the carousel shows, with only the fields it draws.
const carouselProject = (doc) => ({
id: doc.id,
uid: doc.uid,
data: {
title: doc.data.title,
poster: doc.data.poster,
year: doc.data.year
}
});That one is simplified. Ours reads a few different fields, with the same idea.
Why HTML size matters more than it looks
HTML is the first thing the browser downloads, and nothing else starts until it arrives. On a phone network, 200KB of data the visitor will never see sits directly in front of the first paint. Lighthouse also counts the bytes requested before the largest paint when it simulates a slow phone, so the same waste shows up in the score.
We saw a similar pattern when PageSpeed's test machine had no graphics card: the number reflected work the page did that no visitor benefited from.
What to watch for
Trimming has one risk. A field can be read by a child component three files away, and if you drop it, that component renders empty without any error. We check each trimmed page by eye, and we keep the field list next to the component that reads it.
Checking the result needs nothing special.
curl -s https://cairo-studio.com/en | wc -c
We run that against each template whenever a loader changes. The homepage is 87KB today, a little above where we left it, because the carousel has gained projects since.
