Your document head is still Vite scaffolding
npm create vite writes you an index.html. You put your app in the
body, and you never open that file again, because nothing in it ever
breaks. Here is this site's, as git blame saw it on 2026-07-28, the day
before it was fixed:
085f702 2023-01-02 <!DOCTYPE html>
085f702 2023-01-02 <html lang="en">
085f702 2023-01-02 <head>
085f702 2023-01-02 <meta charset="UTF-8" />
085f702 2023-01-02 <link rel="icon" type="image/svg+xml" href="/vite.svg" />
085f702 2023-01-02 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
0eb3a85 2023-01-09 <title>Pearachute Design & Technology</title>
0eb3a85 2023-01-09
0eb3a85 2023-01-09 <link rel="preconnect" ...><link href="...family=Ubuntu..." rel="stylesheet">
0eb3a85 2023-01-09 <style> @import url('...family=Ubuntu...'); </style>
085f702 2023-01-02 </head>
085f702 2023-01-02 <body>
085f702 2023-01-02 <div id="app"></div>
085f702 2023-01-02 <script type="module" src="/src/main.js"></script>
085f702 2023-01-02 </body>
085f702 2023-01-02 </html>
085f702 is the commit called stock svelte starter kit. Twelve of the
sixteen lines came from it unchanged. The other four were added a week
later, by styling tweaks, goog fonts. Then nobody opened the file for
1,297 days.
What the scaffolding was doing
Some of it was harmless and some of it was visible to every visitor.
The favicon was the Vite logo. Every browser tab with the site open showed Vite's blue and purple chevron with its yellow lightning bolt, on a consulting site. Nothing was broken, so nothing failed, so nobody looked.
There was no description and no Open Graph or Twitter tags. When someone pasted the site into Slack, LinkedIn or iMessage, it unfurled as a bare URL with no title card, no summary and no image. The one place a small consulting site most needs to look deliberate, a link someone else is sharing, was where it looked most like a template. A separate note covers the per-route metadata work that came after, for a client-rendered app whose real titles only exist once JavaScript runs.
The font was requested twice. Once by a <link>, and again by an
@import inside a <style> block. The second form is the slow one: the
browser has to parse the style block before it finds the import, and the
page can't render until the imported sheet arrives. That cost time on
every page load, and it was invisible, because the font showed up either
way.
None of these are bugs, which is why they lasted. A bug produces an error, and an error gets attention. Scaffolding produces a page that works and looks slightly generic, and nobody files a ticket for that.
The 15 percent photo
The same audit opened the network tab, sorted by size, and found the
home page's background: a 3,696 by 2,448 pixel camera original, 3.6 MB,
drawn full-screen at opacity: 0.15 behind the content. Here is every
byte of a first visit, before and after 7d2ef67, one square per 10 KB:
7d2ef67 and at its parent with the same node_modules, and adding up what the home page requests: the HTML shell, the favicon, the JavaScript and CSS bundles, the logo, and the photo. Google Fonts and the Open Graph card (which only link unfurlers fetch) are left out. Sizes are uncompressed, and a file under 10 KB still gets one square so it stays findable. Hover a square for its file.The measurements as a table
| file | before, bytes | after, bytes |
|---|---|---|
background photo (michigan.jpg) | 3,744,184 | 236,169 |
| JavaScript bundle | 287,014 | 287,032 |
logo (/assets/logo-*.svg) | 20,647 | 20,647 |
| favicon | 1,497 (vite.svg) | 20,647 (logo.svg) |
| CSS bundle | 14,566 | 14,566 |
| HTML shell | 814 | 2,399 |
| total | 4,068,722 | 581,460 |
The photo was 92 percent of a first visit. Resampled to 1,920 by 1,272 at JPEG quality 72, it is 236 KB, a 94 percent cut, and at 15 percent opacity you cannot tell the two apart. A first visit went from about 4 MB to about 570 KB.
The general rule: look at your largest asset at the size and opacity it is actually drawn. A camera original is the right file to keep. It is almost never the right file to ship, and it is especially wrong when the design fades it to near-white.
What the chart shows next
Two things in the after picture are worth being honest about.
The JavaScript is now the page. At 287 KB uncompressed, the bundle is about half of a first visit, and it did not change at all. The photo hid it. The next round of this, if it ever matters, starts there, not with the images.
The favicon got nearly fourteen times heavier. vite.svg was 1,497 bytes.
The replacement is the full Pearachute logo, 20,647 bytes, and it is the
same file the page also loads from /assets/ under a hashed name. Two
URLs mean two downloads of identical bytes on a first visit. It is 20 KB,
so it does not matter much, but it is the same kind of mistake on a
smaller scale: a file nobody looked at, at the size it is actually used,
which for a favicon is 16 pixels.
The 8 MB that never shipped, and still ships
The same commit deleted michigan2.jpg and michigan3.jpg, two more
camera originals, 8.3 MB between them. Nothing had ever imported them,
so no visitor ever downloaded them. Every developer did, because they
were in the repository.
Deleting them took them out of the working tree. It did not take them
out of the clone. Git keeps every version of every file, and these are
JPEGs, which do not compress, so they are still in history at full size,
along with the original 3.6 MB michigan.jpg. The three photos come to
11.5 MiB of this clone's 24.8 MiB pack. Getting that back means
rewriting history and force-pushing, which costs more than 11 MB is
worth for a repository this size. The cheaper lesson is the order:
resample before the first commit, because the first commit is forever.
What is still here
Scaffolding outlives the cleanup too. As of this writing the tree still has:
web/README.md, which begins "This template should help get you started developing with Svelte in Vite."web/src/lib/Counter.svelte, the starter's demo counter, imported by nothing since the day it arrived. It turns up in the note on proving code is dead as the file nobody decided to keep.
Neither ships to a visitor, so neither costs anything but the attention of whoever opens the directory. That is the whole problem with scaffolding in one sentence: it costs almost nothing, so nobody makes a decision about it.
The checklist
What to replace after npm create, before the first deploy:
- The favicon, with your own mark, at a size that makes sense for 16 pixels.
- The title and a meta description, written on purpose.
- Open Graph and Twitter tags, with a 1200 by 630 image. Then paste the URL into a chat app and look at what unfurls.
- The font loading. One
<link>, withpreconnect, and no@import. - The largest asset, checked at the size and opacity it is drawn. Open the network tab, sort by size, and read the top line.
- The demo component and the template README, deleted.
None of this is hard. It took one commit. What makes it last for 1,297 days is that nothing ever forces you to look, so the only fix is a habit: once in a while, view source on your own production page and read the head as a visitor's browser would.