From 471588c0e0a9db4ccc9065b9bc16b72abe0f51a0 Mon Sep 17 00:00:00 2001 From: Christine Dodrill Date: Thu, 16 Jul 2020 14:14:51 -0400 Subject: [PATCH] blog: add rewrite in rust post --- blog/site-update-2020-07-16.markdown | 117 +++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 blog/site-update-2020-07-16.markdown diff --git a/blog/site-update-2020-07-16.markdown b/blog/site-update-2020-07-16.markdown new file mode 100644 index 0000000..6b4c822 --- /dev/null +++ b/blog/site-update-2020-07-16.markdown @@ -0,0 +1,117 @@ +--- +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).