Dev.to WebDev 🛠 Dev 👁 0 📖 6 min read

A directory in our repo lived for one hour and fifty-four minutes, and took the stylesheet's only reduced-motion rule with it when it went

Three commits from one evening, with their times: 20:54:24 Make the landing page playful, with a game you can actually play 21:06:39 Serve the handwriting font from the repo 22:48:00 Add mix packs, demo components,

Three commits from one evening, with their times:

20:54:24  Make the landing page playful, with a game you can actually play
21:06:39  Serve the handwriting font from the repo
22:48:00  Add mix packs, demo components, and pricing/guide pages

The first created components/landing/, nineteen files and 2,350 insertions. The second fixed the build it broke. The third deleted the whole directory. Elapsed life of the directory: one hour, fifty-three minutes, thirty-six seconds.

No visitor ever saw it. The live site is built from after the deletion, and the two routes that experiment added answer 404 today:

curl -s -o /dev/null -w '%{http_code}\n' https://pub-trivia.app/play/demo
# 404

This is a post about what a discarded hour actually costs, because the interesting number is not the 2,350 lines. It is the three things the deletion took with it that nobody intended.

What the hour built

Nineteen files, and you can read the shape of the idea off the names alone:

DemoQuiz.tsx         508    the phone, playing itself
FeatureBento.tsx     435    interactive feature cards
ScanToJoin.tsx       298    a QR code and a join form, on the marketing page
LeaderboardRace.tsx  183    a big screen reshuffling
ui.tsx               148    local primitives
QuizNightBoard.tsx   103    a chalkboard
DemoGame.tsx          94
LastOrders.tsx        90    the closing section, with a bell to ring
HeroPhone.tsx         80
demo-data.ts          78
Hero.tsx              59
PhoneFrame.tsx        58
TeamMarquee.tsx       44
fonts.ts              20
LandingMotion.tsx     13

Plus lib/qr-path.ts, a /play/demo route for the QR code to point at, and 41 lines appended to globals.css. The commit message is the clearest statement of intent: "the hero phone runs the real player screens and plays itself until the visitor taps an answer".

That idea survived. Almost nothing else did.

The twelve minutes in the middle

The second commit is the one worth reading if you use next/font. The landing page wanted two extra typefaces, a chunky display face and a handwriting face, loaded on that page only so no other page pays for them:

import { Bricolage_Grotesque, Caveat } from 'next/font/google'

export const handFont = Caveat({
    subsets: ['latin'],
    weight: ['600', '700'],
    variable: '--font-hand',
    display: 'swap',
})

That works locally and fails on Vercel. next/font/google fetches the font CSS at build time, reads the file URLs out of it and asks the bundler to resolve them, and the build could not resolve the ones that came back for this face. The fix, twelve minutes and fifteen seconds later, was to stop asking:

import localFont from 'next/font/local'

/**
 * Caveat (SIL Open Font License), the latin subset of the variable font,
 * served from here. Fetching it from Google at build time broke the Vercel
 * build: Turbopack could not resolve the font URLs that came back.
 */
export const handFont = localFont({
    src: './Caveat-latin.woff2',
    weight: '400 700',
    variable: '--font-hand',
    display: 'swap',
})

So a 74,932-byte binary went into the repository next to the components. It is the only .woff2 ever committed to this project, and it was deleted an hour and forty-one minutes later, which makes it the shortest-lived file in the history by a wide margin. The lesson is still worth keeping: a Google font through the build is a network dependency at build time, and the escape hatch is next/font/local plus the file, with the licence named in a comment because somebody will ask.

What the deletion also removed

The 41 lines of CSS went back out with the components. Here is what was in them:

@utility font-display { font-family: var(--font-display), var(--font-geist), system-ui, sans-serif; }
@utility font-hand    { font-family: var(--font-hand), "Comic Sans MS", cursive; }

@utility animate-marquee         { animation: marquee var(--marquee-duration, 40s) linear infinite; }
@utility animate-marquee-reverse { animation: marquee var(--marquee-duration, 40s) linear infinite reverse; }
@utility animate-scan            { animation: scan 2.4s ease-in-out infinite; }

@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes scan    { 0%, 100% { top: 6%; } 50% { top: 90%; } }

@media (prefers-reduced-motion: reduce) {
  .animate-marquee,
  .animate-marquee-reverse,
  .animate-scan {
    animation: none;
  }
}

Three things to notice.

One. "Comic Sans MS", cursive as the fallback stack for the handwriting face is, I maintain, correct. If the handwriting does not load you want the next most handwritten thing available on the machine, and that is what is available.

Two. The two typefaces are gone, which is checkable from outside. The live <body> carries exactly two font variables, Geist and Geist Mono, and the stylesheets contain no trace of the others:

curl -s https://pub-trivia.app/_next/static/chunks/2ox5qqp3hzrjs.css | grep -c 'Caveat\|font-hand\|marquee'
# 0

Three, and this is the one that matters. That @media (prefers-reduced-motion: reduce) block was the only one this project has ever had in CSS. An accessibility audit of the site earlier this month counted zero prefers-reduced-motion rules against 2,710 motion-capable utility classes, and named it as the gap to close. For one hour and fifty-four minutes the gap was partly closed, as a side effect of somebody writing a marquee. Then it was deleted, as a side effect of somebody deleting a marquee.

Both of those stylesheets are still public, so you can confirm there is nothing left:

curl -s https://pub-trivia.app/_next/static/chunks/2ox5qqp3hzrjs.css | grep -c 'prefers-reduced-motion'
# 0

Motion on the site today is respected, but only through JavaScript: the components that animate sit inside a MotionConfig reducedMotion="user", which reads the same media query at runtime. That works, and it covers the mascot and the demos. It does not cover a CSS animation, and we have one of those, an infinite pulse on a loading state.

While I was in the stylesheets I noticed the delivery changed too. Earlier this month this site served one 86,718-byte stylesheet. The current build serves two:

/_next/static/chunks/3x4uycjdjw11v.css      4,114 bytes
/_next/static/chunks/2ox5qqp3hzrjs.css    103,484 bytes
                                        -----------
                                          107,598 bytes

And in those 107,598 bytes, the fifteen --chart custom properties that have never had a consumer are still present, all fifteen, having survived a purge that took out an entire landing page. Dead code that lives in a file nobody is rewriting is immortal.

What survived

Two things, and they are the two that were worth keeping.

The 508-line phone demo was moved rather than rewritten. Git records it as a rename, components/landing/DemoQuiz.tsx to components/demo/PhoneQuiz.tsx, with 264 of its lines changed on the way: the component that plays the real player screens against made-up data is still the thing the homepage shows. The fixture module came back too, demo-data.ts, 78 lines then and 115 now, as the single scripted night that feeds every demo on the site.

What got thrown away was the surrounding apparatus: the chalkboard, the bell, the marquee, the bento grid, the QR code on the marketing page, the two extra typefaces, the local primitives, and a route for the QR code to point at. The replacement is three files in components/demo/, and the thing it shows is not a bespoke marketing illustration, it is the product's own screens with a fixture behind them.

That is the honest summary of the hour: the experiment proved which single idea in it was load bearing, and 2,350 lines was the price of finding out. I would rather pay that in a two-hour window and delete it in one commit than keep nineteen files around because they were expensive.

Check it yourself

Everything above is visible from outside the repository:

# the routes the experiment added
curl -s -o /dev/null -w '%{http_code}\n' https://pub-trivia.app/play/demo    # 404

# the fonts that survived
curl -s https://pub-trivia.app/ | grep -o 'geist[a-z_]*_[a-z0-9]*-module' | sort -u

# the stylesheets, and what is not in them
curl -s https://pub-trivia.app/ | grep -o '/_next/static/chunks/[a-z0-9]*\.css' | sort -u

And the thing the hour was really for is on the homepage: the phone demo partway down, which is the real player screen with a scripted night behind it, and the big screen beside it, which is the real host view. Both of them came out of that directory. Neither of them needs it.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.