--- title: Okay, fine, I'm using a static site generator now date: 2023-10-12 series: site-updates tags: - lume - dhall - typst - go hero: ai: SCMix file: si4-shed prompt: A green-haired woman in a hoodie and jeans leaning on a shed that looks like the Hanzi character for "four" --- Hey all! Xesite v4 is now complete and has been rolled out. I'd've liked to have this post out sooner, but this is genuinely a lot of stuff that's changed and I'm still working on some of it. Here's a quick overview of what's changed in Xesite v4: - [Lume](https://lume.land) is used to build pages - [Tailwind](https://tailwindcss.com) is used to style everything - The site can now automatically rebuild itself _in production_ to reflect changes to the site's configuration, patron membership, blog posts, or my resume. - The site is now hosted on [Fly.io](https://fly.io) - I use [MDX](https://mdxjs.com) to write blog posts now So for those of you that [really did think my blog was a static site](/talks/how-my-website-works/), you're right now. It is one. ## Why did I do this? At a high level, the architecture for Xesite v3 (the last version in Rust) was sufficient for my needs. I had extensibility via [lol\_html](https://github.com/cloudflare/lol-html) and defining my own custom HTML elements. Everything was compiled to native Rust code as much as possible, and I had exact control over the output. Arguably, I did have a static site generator, but it was just kinda halfassed and stored everything in memory. However, there were a few problems with this approach: I couldn't trigger updates to the website content without redeploying the entire server it was on, due to how it was implemented with NixOS. This is not a fault in how NixOS works, this was a fault in how I implemented it. To be fair, I tried adding dynamic updates to the mix, but I was running into issues involving state contention with how I designed things in Rust. I could've fixed this, but it would've required a lot of work. It probably would have ended in me rendering every page to the disk and serving that disk folder, but that's not really what I wanted. I wanted to adopt [Tailwind](https://tailwindcss.com) so that I could style my posts a lot more freely, but I wasn't really able to find a way to fit it in because the Tailwind parser couldn't understand the HTML templates I was using. I was using the proc macro [Maud](https://maud.lambda.xyz/) to write HTML, but the Tailwind parser can't handle reading class names out of Maud templates. Here's an example JSX component from my website that I wanted to port over: ```jsx export default function BlockQuote({ children }) { return (
> {children}
); } ``` In Maud, the template would look like this: ```rust use maud::Markup; pub fn blockquote(body: Markup) -> Markup { html! { ."mx-auto mt-4 mb-2 rounded-lg bg-bg-2 p-4 dark:bg-bgDark-2 md:max-w-lg xe-dont-newline" { "> " (body) } } } ``` This is all fine and dandy, but then the real trouble came in with passing this to lol\_html. lol\_html doesn't have the concept of getting the children of a component (because this is designed to do *streaming* replacement of HTML elements), so in order to make this work in lol\_html I can't use that template function. I have to write it like this: ```rust use lol_html::{element, RewriteStrSettings}; let mut html = magic_get_html_for_post!(); let html = rewrite_str( &html, RewriteStrSettings { element_content_handlers: vec![ // ... element!("xeblog-blockquote", |el| { el.before("
> "); el.after("
"); el.remove_and_keep_content(); }) // .. ], ..RewriteStrSettings::default() } ); ``` You can see how this would get fairly unmanintainable very quickly. At work I was exposed to a new technology called [MDX](https://mdxjs.com) that looks like it could really solve all these problems. It's a bit of an unholy combination of React and JSX with Markdown, but it's really cool. Instead of defining my components in bespoke syntaxes or in Rust, I can just write them in React and use them in my blog posts. This is really cool, and I'm excited to see what I can do with it. The biggest problem was the old format of these things: These little conversation snippets were a huge pain to move over! Previously they were done by [hacking up the markdown parser in a way that is known to cause cancer in the state of California](https://github.com/Xe/site/blob/cbdea8ba3fca9a663778af71f8df5965aeb6c090/lib/xesite_markdown/src/lib.rs#L50-L94), which made them look like this: ```markdown [Wow this is text that I am saying!](conversation://Mara/hacker) ``` With the lol\_html flow I had to explicitly namespace my HTML elements ad nauseum, so it looked like this: ```html Wow this is text I am saying! ``` But even this was annoying in practice because I could _not_ use newlines in the conversation snippets without breaking the hell out of everything in ways that were difficult to diagnose. I ended up using `
`, `