There are loads of ways of making websites and not all of them suit the problem or the person making the website. This post summarises my experience as someone who knew nothing about web development to someone who has a website. I hope readers can take away some ideas if they’re wanting to make a website.
First impressions matter. Before the end of 2023, I hadn’t done any web development, but I had a general idea of how to put together an application from my experience with developing an Android app. The main gaps in my knowledge lie around Javascript frameworks. I wanted to know why React had become the de facto standard, apparently, for developing user interfaces.
Since I’d never done any web development before, I haven’t got holdovers from before the proliferation of javascript frameworks such as React. I’ve never known anything apart from what is currently in vogue in the web development world. This affects my perception of how good certain tools are vs others since I haven’t fallen in love with and had my heart broken by any of these technologies yet. You could say my point of view is naïve, but I like to think of my view as fresh and objective.
I had no preconception of what should be easy and what things are complex. I later learned that managing the state of the application is essentially where the complexity lies within a project such as a website. Maybe something I should have guessed since out of each of the letters in REST, the S is the only abstract one which is therefore the only one you can mess up. RE is a verb, i.e. you need to write some JSON or HTML, and the T is also pretty much handled for you. You just need to work out what ‘state’ you are sending between your server and client. That’s not obvious when any API that sends JSON seems to be referred to as a REST API. This may sound like philosophical pondering, but I think it’s useful to have a broad view of a topic.
The project I had in mind was a personal website. Its requirements were to look nice, be easy for me to add documents with some formatting and pictures, be easy to deploy and be easy to maintain. If the ends justify the means, the best way to do this project would be to set up a WordPress blog, but I was primarily interested in learning some new skills.
This is a pretty simple project, but it would allow me to explore all of the fundamental components that websites are built with. I’d need to figure out how to set up a database and an API that lets me interface with it, how to make a user interface, and how to deploy it on my own hardware.
This website is my first impression of the world of web development. It took two goes to make it, or two and a half depending on how you count. My general feeling from this experiment is the go-to standard way of making front-ends, i.e. React or other heavy javascript frameworks, would have added needless complexity, and a good alternative to these frontend frameworks is combining server-side rendering with HTMX. This lets you keep the intelligence of a website in the backend and you can pick whatever language you like to render the webpage.
The first go
I needed to choose some technologies that let me write blog posts and let other people look at them. I didn’t want to be writing HTML documents to create a new post, so I thought it would be good if the website had a rich text editor which I could use to create documents.
I went for the following technologies:
- I wanted to use Rust to make the backend. I wanted to learn more Rust since I liked it’s safety features and the
Rocketframework looked pretty neat. - I wanted to use
Reactfor the front-end. I liked the sound of making components and the examples I’d seen on YouTube made it look pretty easy to get basic stuff working. - I wanted to use
Matertial UIto do all the styling. What I wanted was something that generated a nice set of shapes, colours, and various standard components that all websites have. I’d had good experience making the Android app, and that usedMaterial UI, so I didn’t think there was any better way to go. Later on in the project, I found myself to more than happy to scrap all myMaterial UIcode. - I decided to use
MySQLfor the database. I knew I had a pretty simple data persistence requirement, so this seemed like a good choice. To talk to this database, I usedSQLxwith Rust. I didn’t want to obfuscate the SQL queries behind an ORM since I wanted to brush up on my SLQ skills.
I got pretty far with this prototype. In a month or so, I had implemented most of a rich text editor with Lexical, and I was able to write documents which had pictures and a variety of fonts. I had set up the backend with a JWT log-in flow so that as an admin, I could open the text editor, save the new post, and publish it. The post would appear in a grid of other posts. The website had some ok-but-a-bit-developery-looking components, and overall the website felt reactive and modern.
About 80% of the work seemed to be done. However, despite the first 80% going relatively well, the remaining parts were becoming increasingly hard and less fun to work on. Our sage colleagues will tell us that despite finishing 80% of the work, there is still another 80% to go. I had some growing discomforts about the project, and it was time to confront them.
The rich text editor I had made serialised and deserialised documents into nodes which were in a non-standard format. The serialised version of it wasn’t pleasant to read, so the only way that I could view these documents was in the React component I’d built to show them. It’s not hard to imagine the world moving on from these technologies, and I think, most humbly, the value of my website would be various bits of writing I’d upload to it. Losing the writing would be a shame. I can imagine one day not wanting to support a website and getting a selection of my writing bound in a book. For instance, I’m sure my descendants will be thrilled to read musings on web technologies from the 2020s. I didn’t want to get locked into a technology and format which nobody would understand in the years to come.
Furthermore, while it was a bit of fun to learn how a rich text editor works, the one I made wasn’t going to be as polished as a more mature project, so writing wouldn’t be as pleasant an experience as it could be. I primarily wanted an easy way to create documents, and a rich text editor lets you do that. But less is more. I felt like I wanted something more basic because there would be less stuff to get in the way of writing.
I decided to scrap the rich text editor. Instead, one option would have been to write everything in HTML, but I felt like seeing tags all over the place would be distracting. The alternative, I felt, was markdown. I enjoyed the simplicity of writing markdown, and it is easy to read in the source file as well as in a dedicated viewer. It is ubiquitous and has been around for ages. I settled on the idea of making the server ingest markdown documents and produce HTML from them which could be displayed to the visitors of the website. With this new process of creating documents, the project became simpler. I just needed to make a HTML form with which I could upload a document, associated images, and metadata.
Once I got around to getting the server-generated pages into the client, I found myself writing this:
<div dangerouslySetInnerHTML={html} />
That looks a bit sketchy. I hadn’t spent much time thinking about what it meant to render a webpage until this point in the project. The change from the rich text editor to the server processing markdown was a significant pivot in how data flows through an application. Now, the server would do the work of turning a document into HTML rather than the client. When I created this div, I didn’t appreciate that I had fundamentally shifted how data flows through the application, and this meant that some of my design choices were no longer fitting the problem. The page gets rendered in two places with that div. Most of the website is rendered in the client by the React code, but the article is HTML which the server rendered and sent to the client. That just seems wrong.
On a slightly random-seeming tangent, I wanted to use an HTTP PUT in a <form> submit button, but for some reason, this isn’t possible without implementing a workaround in the front end or changing the back end. This seems like an obvious deficiency in HTML.
I chose React for, basically, no reason. I just thought it was the way you make websites. But what is React for? It is for managing the state of the application in the client and rendering it there. This makes sense for certain user interfaces that are highly interactive, but it is complete overkill for a website that is essentially showing static text to the user.
I didn’t like that the website looked like a “Material UI” website. I began customising some parts of it, but when I used it with the Android app, it let me make something that looked like native software. Along with a few other minor gripes, I couldn’t generate a set of harmonious colours without zero effort, and that was one of the reasons I wanted to use Material UI. I felt like I was about to start fighting with the framework, and that’s a good sign that you’re doing something wrong. The fundamental problem I had with Material UI was I couldn’t get it to give my website my own personal flair.
With these things in mind, it was time to try another approach which would deal with the flow of data through the application properly.
The second go.
HTMX is an interesting project which lets you do web development without needing to write much javascript. I’d basically had enough of writing React. HTMX solved the weird half-server half-client rendering of a simple webpage. It removed a huge stack of Javascript dependencies and this allayed my worry of Javascript packages becoming deprecated and becoming incompatible with future changes I’d want to make. It also made it possible to use an HTTP PUT in my form without any hackery. Basically, it gave my HTML superpowers.
HTMX is a fairly simple dependency. Not simple in the sense that it was easy for the authors to make; it is simple in the sense that as a user, I can get it to do what I want without much hassle. It’s about 4000 lines of self-contained Javascript that doesn’t rely on outside javascript packages. You don’t need to include a build phase to “compile” your front end, and that simplifies the deployment of the frontend code since you don’t need to rely on a build tool being configured correctly. You just stick a <script> in your webpage and you’re good to go.
I used Tera in Rust to render the website’s HTML. This still had the modular feel of the components which I liked from React, but it was nice to be writing Rust and HTML instead of javascript. I can see though that this will still be hard to manage as a project grows, and I found myself unsure where one template should start and where one should end. It’s probably something that becomes easier to get a sense of as you gain experience using them.
I was happy to replace the Material UI. Besides being incompatible with the other parts of my technology stack, using Material UI makes you miss out on some pretty basic parts of CSS which are handy to know about. After trying to write my own extensive CSS classes for about one day, I decided that I’d give Tailwind a chance. While Tailwind does require you to build some CSS classes from your HTML pages, the tools for Tailwind were easy to set up and use and they even offer it as a standalone CLI tool, so I was happy to include Tailwind in the project.
My knee-jerk reaction to Tailwind was it was overly verbose and made HTML look like a mess, but as I got used to it, I grew to enjoy using it. It solves one of the hardest problems in programming - naming things. You are saved from writing hundreds of utility classes and instead, you can focus on putting Tailwind’s classes together to get your page looking just the way you want.
Tailwind doesn’t force a style on you, which can be a good or bad thing. If you like designing stuff and are good at it, this makes it easier to create what you want. If you have no interest in designing a page and are bad at making creative choices, this slows you down. I personally enjoyed choosing colours, fonts, shapes and spacing, so I was happy to tinker with Tailwind.
I could write HTML which did what I wanted to the backend, I could easily personalise the website, and I didn’t have to manage much javascript. I was very happy with the combination of HTMX and Tailwind, and I’d recommend trying them out. The Rust backend was fun to make, and the Rocket framework is easy to use.
Deployment
So, I’ve done all the hard things? Well, creating a solid deployment flow is worth doing, and I found docker-compose to be ideal for this. I can quite happily spin up the server and the database with one command. Combine that with a decent readme, and I am able to develop and deploy the server without having IT issues.
The next problem to solve is how do I get this on the internet. I could rent a computer for a website that practically nobody will look at, but why should I do that? I have a spare PC with 500GB of free space and 8GB of RAM. It’s a bit old, and the screen is slightly damaged because it has the worst build quality ever. I haven’t used it for anything in years. In other words, it is perfect for being used to host my projects, so I put a new version of Linux on it, connected it up to my router in my house and deployed my code there. Great, that kind of hardware would cost me a few quid a month to rent.
I then set up NGINX to reverse proxy my website. It provided the SSL certificate, as well. I thought this would be great and that it would be feasible to host as many random projects on this computer and NGINX could handle all of them quite nicely.
But this only works on my home network. What about all the other computers in the world? Well, for that, I needed to acquire a static IP, and as far as I’m aware there’s no basically-free way of doing this. So I had to set up my router to talk to a DDNS service. I did manage to host it for no monthly payments in the end, but if I want to use HTTPS and have a better domain name, I’d have to fork out the price of a coffee every month, and that is completely unacceptable.
Closing Thoughts
The hardest part of this project was choosing the right technologies for me. But the other hardest part was making a decent backend, and I was happy with my choice of Rust and Rocket. If I wanted to learn more about Rust, I would go through the effort of writing my own web server to get an appreciation of how much these frameworks do for you. I am also keen to try out Go since it has a templating library that comes with the language.
I would stick with HTMX for my next web dev adventure. It is the easiest way I’ve experienced to create a frontend which covers all the types of interactions that I wanted to make. I now know why people rile against React, but I think it will solve certain problems which HTMX doesn’t solve as well - I don’t know what problems these are yet, but they’re probably to do with low latency user interaction or to reduce server-side CPU load.
Tailwind was great fun to use, and I’d never want to use Material UI again. People moan about Bootstrap, but I think if I wanted to quickly make a prototype of a website, it might be a good option. It can be used without any extra javascript written by me, and that is appealing.
Deploying the website onto the internet was a bit tedious and it felt kind of like doing admin. It didn’t seem well explained anywhere, and my expectations of what was possible were too high. It took several evenings of research to get this working properly. The world seems to be geared towards paying someone else to host your project, which does make sense if you have reliability requirements since it’s fairly likely that I will disconnect my router by accident while I’m hoovering my flat. Digital Ocean offers a simple and decent hosting platform known as “Droplets”, and that is a good alternative if you’re willing to pay a small monthly fee.
I consider this project to be a success. I got what I wanted: I learned how frontends and backends can work together, I learned a bit about React, I learned how to use templating to create web pages, some of the technology involved in running a website, and I got a website that I can ramble on out of it.