How this site is built
A note on how this site is put together. People ask what the machinery is, and some of it is unusual enough to be worth writing down.
What it is
Eleventy 3.1.6, Nunjucks templates, and CSS written by hand. There is no framework, no component library and no CSS pipeline: one stylesheet for the whole site, about 11 KB over the wire once compressed, and a few more that load only on the pages they belong to. The build produces 110 pages of static HTML, which S3 serves and CloudFront caches.
0 runtime dependencies. Nothing this site sends you pulls in anyone else's code. There are 6 development dependencies, which is Eleventy and the things that build and check the output; none of them reaches a browser.
Each script ships only to the pages that use it. enhance.js is about 5 KB compressed and runs on every page: copy buttons, the / palette, progressive niceties that the page works without. The second is about 80 KB and loads on exactly two pages, because it is a game, and it would be rude to send it to everyone else. The third is about 2 KB and loads only on the comic pages, where it does the small things those pages need. The fourth renders the social-card tool, and loads on the one page that has it. It used to live inside the first, which meant forty pages carried a card renderer for the benefit of one.
goosey’s script is the largest after the game, about 19 KB, and loads only on goosey. carnot’s fleet calculator is about 8 KB and loads only on the paper that carries it. Another, about 7 KB, runs the polymorphism explainer’s widgets and its quiz, and loads on the explainer and the quiz. The last two are a few hundred bytes each: the cookieless page-view counter, which every page loads, and the copy button on the feed pages.
The palette is deliberately absent from the game’s two pages. Both are a shell or a game that reads raw keystrokes, and a sitewide handler taking / away from them is a bug this site has already had once, from a skip link.
What it will not do
The content security policy has no 'unsafe-inline', which means no inline style="" attributes and no inline <script> anywhere in the markup. Everything is a stylesheet class or a hashed file. This is a mild inconvenience roughly once a month and it removes an entire category of problem permanently, which seems a fair trade.
There is no analytics beyond a cookieless page-view counter, no tag manager and no third-party fonts fetched at runtime. The one third-party embed is the map on the contact page, which comes from Google and says so in the privacy notice.
Rather more tests than this needs
There are several hundred tests across 109 files, for a site with 110 pages. That is disproportionate and we know it. What made it worth doing is that the site deploys itself every hour without anyone looking at it, so anything that can go wrong quietly will eventually go wrong quietly.
The ones worth describing are the ones that check the checks:
guardsBreaks the site on purpose, one violation at a time — a dead link, a wrong company number, a heading outline that starts at h5 — and fails if the test suite stays green. A suite that asserts the build is clean says nothing about whether it would notice if it weren't.mutantsThe same idea for the logic: flip a comparison, shift a threshold, invert a return, and check something fails.ci-checkRuns the suite the way CI runs it — a clone at the pipeline's own depth — because a test that reads git history passes locally and fails on a shallow checkout, and reports which tests skip there, since a test that skips in CI is not a test CI ran.og-corpusandog-fuzzThe social-card checker against 75 real websites and 250,000 generated tag-soup cases, because the interesting failures come from markup nobody would write deliberately.
The recurring lesson, and the reason those exist: the thing doing the checking is wrong more often than the thing being checked. A test that cannot fail is worse than no test, because it also stops anyone looking.
How it ships
Every push runs the build, the full suite, and terraform fmt and validate over the infrastructure. The site then redeploys itself hourly whether or not anything changed, which is how version numbers and release dates on the product pages stay current: they are fetched at build time, so the page is only ever as stale as the last hour.
Uploads are ordered so there is never a broken intermediate state — hashed assets first and never deleted, HTML last, so no page can reference a stylesheet that has not landed yet. Afterwards a smoke test hits the live site and checks the pages, the security headers and the redirects.
Deploys that a human starts get one extra step: a read of the actual prose on every changed page before anything goes out. Machines are good at catching a dead link and hopeless at catching a sentence that is true but unwise.
The infrastructure
S3 and CloudFront, with Route 53 for DNS and Lambda behind the one API this site offers. All of it is Terraform, in the same repository as the site, and npm run drift plans every configuration read-only to check that what is deployed still matches what is written down.
The bird
The 404 page is not a 404 page. Neither is this one. Both were built for fun on evenings, they are the reason one of those script bundles is 80 KB, and no apology is offered for either.
The first of those borrows its house style — object classes, containment procedures, redacted addenda — from the SCP Foundation, a collaborative fiction project published under CC BY-SA 3.0. No article of theirs is reproduced and no designation of theirs is used; what we wrote in that style is offered back under the same licence.
If any of the above is useful to you, or you want the same discipline pointed at something larger, get in touch.
Have a system to build, or one that needs work?
Get in touch