This site ships no JavaScript framework, on purpose
This site is a static Astro build. No React, no Vue, no client-side router, no state library. What gets sent to your browser is HTML, a small amount of inline vanilla JavaScript, one WebGL fragment shader, and a self-hosted font.
That was a deliberate constraint rather than a preference, and after four months it is worth writing down what it actually cost.
What the constraint is
Written down in the project’s own instructions:
The build emits HTML, a little inline vanilla JS, and one WebGL fragment shader. No client-side framework, no CSS framework, no utility-class system, no component library.
That last part is the one that takes discipline. It is easy to hold the line on React and then quietly add Tailwind, a headless UI library, and a date formatter, and end up with 300KB of dependencies serving eleven pages of text.
What it costs
No component state. The language picker, the mobile menu and the QR modal are each about forty lines of vanilla JS talking to the DOM directly. In React each would be five lines. That is a real cost and I pay it three times.
Duplication across languages. Every page exists twice — about.astro and vi/about.astro —
carrying the same markup and CSS with different text. A layout change has to be applied to both
copies. This is a deliberate architectural decision rather than a limitation of the approach, but it
compounds with the no-framework rule: there is no cheap abstraction to hide it behind.
Interactive things are genuinely harder. A filterable, sortable list would be a form submission and a page reload, or a hundred lines of DOM code. I have avoided building one, which is the honest version of “it was not a problem”.
What it buys
Nothing to update. Four months, one dependency bump — Astro itself. No security advisories, no breaking change in a state library, no morning spent on a transitive dependency.
It is fast without effort. No hydration, no bundle to parse, no layout shift while a framework boots. The heaviest thing on any page is the font, which is self-hosted and subset.
The whole thing fits in your head. Eleven page files, six components, three CSS files. I can open any file and understand it without navigating a dependency graph. When something looks wrong, the cause is in one of about twenty files.
It will still build in five years. This is the argument I find most persuasive and it is the hardest to demonstrate. A static site generator producing HTML has a very small surface for the ecosystem to break underneath it.
Tip
The self-hosted font is worth calling out as a specific win. Astro’s font API downloads the files at build time and serves them from this domain, so reading a page sends no request to a font CDN — one fewer third party, and one fewer thing in the privacy policy.
The one place I broke the rule
The home page has a WebGL shader — an animated night beach that runs continuously. That is by far the most complex thing on the site and it is written against the raw WebGL API with no library.
Three.js would have made it easier to write. It would also be about 600KB for a scene that is one oversized triangle and a fragment shader, on a page whose entire job is to say who I am. The raw version is a few kilobytes.
It also has to behave: it stops on visibilitychange, stops when scrolled out of view via an
IntersectionObserver, and honours prefers-reduced-motion by rendering a still frame. A loop
running forever on someone’s laptop battery is not a flourish, it is a bug, and the framework
would not have solved that either.
When I would not do this
I want to be clear that this is not a general recommendation.
If the site is an application, use a framework. Anything with forms, authenticated state, real-time updates or a complex client-side data model is what frameworks are for, and hand-rolling it is how you end up writing a worse React.
If a team is maintaining it, use the thing the team knows. My “it all fits in your head” argument works because there is one head.
If interactivity is the product, the constraint is the wrong one.
What I would keep
Four months in, the decision I am most glad about is not the missing framework — it is the smaller rule underneath it: every dependency has to justify itself against the version without it.
The site has three: Astro, its MDX integration, and its sitemap integration. Each one earns its place. That is a list I can audit in a minute, and it is the reason nothing here has broken since I built it.