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

302 lines of shared components carry 1,035 uses across 392 pages, and no two page families reach for the same half

CogniPrep has three families of long-form content pages, and they are all hand-written React: family page files lines inline <Link> /employers/* 212 46,778 662 /blogs/* 117 26,112 372 /cheating/* 66 10,540 6

CogniPrep has three families of long-form content pages, and they are all hand-written React:

family page files lines inline <Link>
/employers/* 212 46,778 662
/blogs/* 117 26,112 372
/cheating/* 66 10,540 61
395 83,430 1,095

83,430 lines of JSX whose job is prose. Serving all of it is one file, components/shared/content-blocks.tsx, which is 302 lines and exports ten components. They are used 1,035 times across 392 of those 395 pages. The three that use none are the three index pages, which is correct.

A 1,035-to-302 ratio is the easy part of the story. The interesting part is who uses what.

The same vocabulary, three dialects

block pages uses employers blogs cheating
Callout 247 283 117 91 39
SpecList 174 197 61 73 40
StatStrip 188 188 150 25 13
DoDont 102 102 22 39 41
CardGrid 70 76 6 41 23
NumberedSteps 69 69 36 24 9
KeyTakeaways 43 43 7 32 4
SplitCompare 38 39 4 20 14
SectionIndex 24 24 4 12 8
TimeBudget 14 14 2 10 2

Nobody specified any of that. StatStrip is an employer-page habit: 150 of its 188 uses, on 71 percent of employer pages and 21 percent of blog articles. KeyTakeaways and CardGrid are blog habits. DoDont leans to the cheating guides, which makes sense once you think about what those pages are for, and which nobody planned.

Two conclusions I did not expect from a census this boring:

A shared component library does not produce a shared style. It produces a shared range, and each family settles into its own corner of it. If you want consistency across families you need a page template, not a block library, and a page template is the thing these pages specifically refuse to be.

The usage profile is a decent description of what a page family is for. Employer pages are reference material, so they lead with figures in a grid. Blog articles are arguments, so they summarise. Cheating guides are advice, so they list what to do and what not to. I could have got that from reading twenty pages; I got it from one Counter.

Why these are JSX and not a registry

The same repository renders several hundred other content pages straight out of data registries, and those pages are much easier to test, lint and count. So why are these 395 hand-written components?

1,095 inline links. A sentence in one of these pages routinely links to two or three other pages mid-clause. The moment prose in a registry needs a link inside a sentence, you have to invent a markup language, write a parser for it, and then write a second function that strips your markup back out when the same string goes into structured data. We have done exactly that elsewhere in this codebase, with inline tokens and a stripInline helper, and it is fine. It is also a thing you only want to own once.

So the split is deliberate: data where the page is a specification, JSX where the page is an argument with links in it. The cost of the JSX side is that a page is 220 lines on average and nothing stops it being 410.

The long tail is not the problem

TimeBudget is used 14 times in 1,029 page files. By the usual reasoning that is a component that should not exist: 1.4 percent uptake, and inlining it would delete a public export.

I think that reasoning is wrong for a content block library, because the cost of a block is not its line count, it is the decision it removes from the writer. The alternative to a TimeBudget used 14 times is 14 pages each inventing a way to show how long a test takes, and that is 14 chances to get the mobile layout wrong. None of these ten blocks is clever. What they are is decided.

The place that reasoning does apply is the other direction. Two components used by employer pages are specific to a single assessment provider, and they live in that provider's own area rather than in the shared file, even though they are used on ten pages each. The test for whether something belongs in the shared file is not how often it is used, it is whether a second family would ever reach for it.

Where this is still soft

There is no test asserting that a new content page uses the vocabulary at all. A page is a React component, so hand-rolling a <div className="grid grid-cols-2 gap-3"> instead of importing StatStrip is a diff nobody will notice, and the only consequence shows up at 320 pixels wide a month later. The block library's real value is the mobile behaviour baked into each one, like the odd-last-tile rule in StatStrip:

// An odd last tile spans both columns of the two column phone grid
// instead of sitting beside an empty cell.
className="bg-card rounded-lg border p-4 odd:last:col-span-2 md:p-5 md:odd:last:col-span-1"

That line is one of about ten similar decisions in the file, and every one of them is a bug somebody already fixed. Reimplementing the grid by hand reintroduces all of them silently.

See it

Two employer guides at the extremes of the page size distribution, both built from the same ten blocks:

Open both and resize to a phone width. The stat grid pairs its tiles two per row and the odd one out spans the full row rather than sitting next to a gap; the spec list drops its label out of a 224-pixel left column and stacks it above the value. Neither page implements any of that, and that is the whole argument for the 302-line file.

📰 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.