It's 2025 and we still can't build websites

#blog Programming.

It's 2025 and we still don't have a clear sensible choice for building websites.

I mean, we can. But every person and their dog has a different way of skinning the beast; more technically said, every person has a different toolchain, which is a chain of tools from different layers (runtime, state-management, programming language, etc). New tools, and ways of chaining them together, are coming out all the time. It's no wonder it's hard to get started on web development, and so it's also no wonder that newcomers just pickup a package deal and cop its problems later on (I'm looking at you, Typescript React with the latest bundler of choice).

Let's walk through the layers and some of the tools within them.

Your choice of tool in each layer has implications for the available choices in the others. Given the overwhelming number of options, you might naively just build with the most popular toolchain choice, but this can lock you into problems. Choosing a more bespoke but sensible path might save you worlds of pain in debugging and performance optimisations later on.

The toolchain I am most excited for is as follows. I have ordered the layers by my chosen priorities.

  1. Type system. ML.
    1. Life is too short for debugging. Type systems are how humans teach a computer to sanity check our work, and how we can model our ideas. I would rather spend my time fighting a type-checker than debugging issues it missed in production. I would rather spend my time writing types that are difficult for a computer to infer rather than explicitly typing everything. My desires for strong inference and soundness mean Typescript is out the window forever. I would rather spend my learning as a programmer on more sophisticated type abstractions than logic patterns. ML is the only language that suits this.
  2. Programming language. OCaml with Reason.
    1. I would rather use object-oriented programming than only use pure functional programming. Haskell and Prolog are out, and OCaml is the natural choice for its popularity.
    2. Reason gives me JSX out of the box, and use efficient Javascript as my runtime through Melange. It also lets me port trusted Javascript packages into OCaml by writing bindings for them. I can start using React out of the box, and if I ever run into performance concerns, I can write bindings for the widely used performant alternative, Preact.
  3. Third-party packages. Reason permits me access to OCaml's package ecosystem (which I would prefer), and Javascript in a pinch through bindings.
  4. Interleaved HTML. I get JSX with Reason.
  5. State management. I'll start with React, but I'll likely move to Preact eventually.
  6. Runtime. Javascript, of course. Maybe when WASM has solid support on many devices and a great responsive UI ecosystem, I'll consider throwing away Javascript and the DOM.

Reason aims to succeed where Typescript has failed. OCaml can be used to write trustworthy performant code, and Melange can handle translation to performant Javascript and interop with trustworthy Javascript packages where OCaml packages fall short (or for runtime-specific packages).

I'm just another person with yet another toolchain. But hopefully the weight of this chain doesn't deplete my strength before I build applications I deem worth making.