Yes, it's true. If you're reading this post, then this website is now built using React instead of Eta and Stimulus.
This is, perhaps, outrageous. Here are some complaints I could imagine you making:
This website is just a blog with some text and a few hundred lines of Typescript for the toys. Why are you shipping megabytes of Javascript to the client?
React sucks for
insert reason
. You should have usedmy preferred client-side UI library
.
You might be right (you probably are), but I want to lay out why I did this way.
TSX is a built-in extension of Typescript's syntax that allows you to write HTML inside your Typescript files. Typescript can compile JSX directly into React function calls (as can many other Javascript compilers).
A React function component.
This otherwise-completely-normal Typescript function,
when compiled by Typescript in react
JSX mode,
can be used by React to render the HTML that it looks like it renders.
export function HelloWorld({ name }: { name: string }) { return <p>Hello {name}!</p> }
Notice that we can interpolate an argument (name
) directly into the HTML-like return value.
This immediately solves several of my issues with every template language I've used.
If you mess up, templates generally fail at runtime, in unexpected ways.
Pass a None
into your Jinja template, or a nil
into your ERB template?
You'll silently get nothing, or you'll leak an internal representation into the HTML, or whatever.
JSX, on the other hand, can be type-checked via Typescript.
That gives me a level of confidence around my edge cases that I would not otherwise be able to achieve without extensive testing. This website does not have extensive tests. I make sure that every page renders, but I don't write tests for individual UI components.
Template languages usually have so-called "filters", function calls which can be called in your template file during interpolation to act on the values you're passing in. But they only have pre-defined ones, or ones that you've registered yourself through some bespoke registration system.
Or maybe you forget all that and call your helper functions before you pass the values to the renderer. But how do you decide where to stop, and what if you decide to change it later? I'm a big fan of automated refactoring tools, and I've never heard of one that can extract a function call from a template file.
With JSX I know exactly where to call my helper functions and how to do it: in my component functions, using normal Typescript syntax. My helper functions are type-checked, and if the results are passed around as React props (i.e., arguments to components), they are type-checked as well.
Or, if you prefer:
Don't think you are. Know you are.
A normal web application is full of boundaries. The boundary between the client and the server (bridged by HTTP) is the big one, but there are important internal boundaries as well.
The boundary that we've been discussing so far is between the server and its own template files. This boundary is profoundly artificial: at the end of the day the server is going to ship some bytes somewhere, and it can generate them however it wants.
Template files seem to have arisen as a way to avoid explicitly doing string formatting inside your application code, or writing some new domain specific language that looks vaguely like HTML but is more pleasant to write in your language's normal syntax. Having now played with toy websites for a few years and worked with Helm's templated YAML, I have grown disenchanted with this separation (as have others).
JSX plows through the server-template boundary by adding an extra compilation step. It's string formatting, yes, but in a tightly-controlled, safe way that closely mimics real HTML syntax. Mixing Typescript and JSX code side-by-side is not merely possible, but pleasant.
The other important boundary is between the client-side Javascript and the HTML.
With templates, these are even more decoupled from each other than the HTML is from the server.
Stimulus requires you to coordinate things like attribute names blindly between template files and client code.
Typescript can't help you if you get an attribute name wrong in your Stimulus Controller
, and you'll get a runtime error.
Again, TSX does not have this problem. You can generally get away without referencing HTML attributes directly at all, since you're authoring the HTML from a higher level where you already have a reference to what you need.
This website has exactly zero lines of "HTML" in it. All the HTML, whether shipped to the client by the server, or rendered locally on the client, is generated by React.
Because React components are mixed directly with the Typescript code that forms the rest of the application, the distinction between the client and the server is actually largely erased for a simple website. If I had a lot of behavior in the client that needed to talk to the server dynamically (e.g., to submit forms or something) this wouldn't be the case. But, as mentioned earlier, this website is mostly a blog and some toys, so this isn't a concern.
Most importantly, rebuilding my website with React was a valuable learning experience. Hobby projects (and despite any appearances of non-hobby-ness, this is very much a hobby project) are great for learning new programming tools and techniques, and since I don't do any frontend work at my day job right now, this is the best way I have to get exposure to that world.
This Website Uses React | 2024‑06‑16 |
Adding Support for Inline DOT to Blahs | 2021‑11‑07 |
Adventures in GitHub Project Automation | 2020‑09‑05 |
Fluent Interfaces in Python and Ruby | 2020‑05‑25 |
My Favorite Software Materials | 2020‑03‑07 |