--- title: "Site Update: Rewrite in Rust" date: 2020-07-16 tags: - rust --- # Site Update: Rewrite in Rust Hello there! You are reading this post thanks to a lot of effort, research and consultation that has resulted in a complete from-scratch rewrite of this website in [Rust](https://rust-lang.org). The original implementation in Go is available [here](https://github.com/Xe/site/releases/tag/v1.5.0) should anyone want to reference that for any reason. If you find any issues with the [RSS feed](/blog.rss), [Atom feed](/blog.atom) or [JSONFeed](/blog.json), please let me know as soon as possible so I can fix them. This website stands on the shoulder of giants. Here are just a few of those and how they add up into this whole package. ## comrak All of my posts are written in [markdown](https://github.com/Xe/site/blob/master/blog/all-there-is-is-now-2019-05-25.markdown). [comrak](https://github.com/kivikakk/comrak) is a markdown parser written by a friend of mine that is as fast and as correct as possible. comrak does the job of turning all of that markdown (over 150 files at the time of writing this post) into the HTML that you are reading right now. It also supports a lot of common markdown extensions, which I use heavily in my posts. ## warp [warp](https://github.com/seanmonstar/warp) is the web framework I use for Rust. It gives users a set of filters that add up into entire web applications. For an example, see this example from its readme: ```rust use warp::Filter; #[tokio::main] async fn main() { // GET /hello/warp => 200 OK with body "Hello, warp!" let hello = warp::path!("hello" / String) .map(|name| format!("Hello, {}!", name)); warp::serve(hello) .run(([127, 0, 0, 1], 3030)) .await; } ``` This can then be built up into something like this: ```rust let site = index .or(contact.or(feeds).or(resume.or(signalboost)).or(patrons)) .or(blog_index.or(series.or(series_view).or(post_view))) .or(gallery_index.or(gallery_post_view)) .or(talk_index.or(talk_post_view)) .or(jsonfeed.or(atom).or(rss.or(sitemap))) .or(files.or(css).or(favicon).or(sw.or(robots))) .or(healthcheck.or(metrics_endpoint).or(go_vanity_jsonfeed)) // ... ``` which is the actual routing setup for this website! ## ructe In the previous version of this site, I used Go's [html/template](https://godoc.org/html/template). Rust does not have an equivalent of html/template in its standard library. After some research, I settled on [ructe](https://github.com/kaj/ructe) for the HTML templates. ructe works by preprocessing templates using a little domain-specific language that compiles down to Rust source code. This makes the templates become optimized with the rest of the program and enables my website to render most pages in less than 100 microseconds. Here is an example template (the one for [/patrons](/patrons)): ```html @use patreon::Users; @use super::{header_html, footer_html}; @(users: Users) @:header_html(Some("Patrons"), None)

Patrons

These awesome people donate to me on Patreon. If you would like to show up in this list, please donate to me on Patreon. This is refreshed every time the site is deployed.

@:footer_html() ``` The templates compile down to Rust, which lets me include other parts of the program into the templates. Here I use that to take a list of users from the incredibly hacky Patreon API client I wrote for this website and iterate over it, making a list of every patron by name. --- These are the biggest giants that my website now sits on. The code for this rewrite is still a bit messy. I'm working on making it better, but my goal is to have this website's code shine as an example of how to best write this kind of website in Rust. Check out the code [here](https://github.com/Xe/site).