Sukr: A minimal static site compiler in Rust with zero-JS output
28 points by nrdxp
28 points by nrdxp
Sukr is a minimal static site compiler written in Rust that focuses on moving traditionally client-side features to build-time. It uses Tree-sitter for syntax highlighting (with language injection support), KaTeX for MathML rendering, and Mermaid for inline SVG diagrams. The resulting static HTML contains zero bytes of JavaScript.
I built sukr because I wanted a static site generator that didn't just punt modern features (math, diagrams, highlighting) to the browser. Most SSGs require a heavy JavaScript runtime for these, but I wanted to see how far I could get with an "Interceptor Pipeline" architecture that handles everything at build-time.
Some technical highlights:
The compiler is written in Rust (2024 edition) and uses pulldown-cmark for the event stream. Happy to hear feedback on the "interceptor" pattern I used to swap out markdown events for highlighted spans and SVGs.
Project link: https://github.com/nrdxp/sukr
very nice. I wrote my own ssg for my blog, which works in a similar way. I tried to open source it as a library that encouraged you to add your own spice rather than just use some cli but after it didn’t really catch on I quit maintaining it and moved the code back over.
mine never supported latex or mermaid, which might both be useful features worth copying…
Yep, originally did this to revamp my blog (got tired of poor syntax highlighting), and added some features to make it suitable for technical documentation as well.
I considered breaking out a library component, I might do that if I decide to add more involved features in the future, to keep the core minimal, but for now this does the trick.
Sounds like something I have half-built and not yet published because the last few months have been messy. I'll have to see if it's possible to deduplicate any of that effort.
Granted, a few things do differ:
cmark-gfm would offer like <booklinks isbn="..."></booklinks> and I have more pressing changes to make first.dot via layout-rs with plans to add plotters and explore the viability of implementing something like matplotlib's xkcd-style graph renderer for it (because they're important. See also). (Also, thank you for drawing my attention to the "Rust bindings for mermaid" in mermaid-rs's README being misleading. I still thought it would emit JavaScript... though, given that it's literally bindings to run the JavaScript version in a headless chrome instance and I'm not up to porting an entire JavaScript project like mermaid to Rust, I think I'll continue to evaluate options such as Emscripten-ing tools like mscgen.)Overall, I think the three big differences are:
At the moment, I'm a little blocked on how bad wasmtime and wasm-bindgen are at documenting how to import shared APIs like percent_escape and html_escape into WebAssembly worlds and have a .wasm file implement one or more mutually independent worlds for things like CodeblockRendererPlugin and TagRendererPlugin without just taking out the macro_rules sledgehammer and duplicating more and more code under disjoint namespaces until it stops complaining. (At the moment, each plugin vendors its own copy of crates like html-escape.)
I do eventually plan to use mine for my blog... though one of the hold-ups is hunkering down, setting up a local instance of my existing WordPress in a VM, and spidering it to get a complete list of all the URLs I'm ideologically opposed to 404ing so I can migrate them over.
This is really cool.
I built my own SSG (for my website) as well called Alteza: https://github.com/arjun-menon/alteza
I built a tempting language for it as well called pypage: https://github.com/arjun-menon/pypage
I’d love to have a similar tree-sitter based highlighting support as well.
I’m wondering if I can use your highlighter, and just change the syntax / grammar definition to match mine. Is it a piece / module of sukr that’s reasonably easily separable?
Regarding https://sukr.io/comparison.html — do Zola and Hugo have built-in features that produce JS output and cannot work without client-side JS?
As a user of both hugo and zola (hopefully soon to migrate to zola-only, but currently I've got one static site with each), looking at my configs:
I can definitively confirm that zola does not require any js by default.
The theme I'm using for my hugo site uses a little bit of javascript for syntax highlighting. I don't see any other place where hugo would pull that in, if I hadn't chosen that theme.
Yeah so I was using zola, and hugo before that, for my blog as well. Part of my motivation for starting this was to get richer highlighting for languages which zola doesn't support too well (e.g. nix), and also because to get things like mermaid rendering and latex style math to mathml you typically have to rely on clientside javascript.
So really the distinction is that in order to reach feature parity, you'd likely need to add some js. As I said in my last comment, I pushed an update to clarify the language here.
That makes sense! I posted my answer before I saw yours, mostly because I'd loaded the page with @dmbaturin 's question and realized that I was probably well-positioned to check being in the middle of moving from one to the other. That took me a few minutes :) Static site generators that require or default to that cougheleventycough aren't unheardof, so I was curious to check as well.
Regarding https://sukr.io/comparison.html — do Zola and Hugo have built-in features that produce JS output and cannot work without client-side JS?
fair question, actually the distinction is moreso that in order to get feature parity (e.g. diagram and math rendering) you typically need to integrate some sort of clientside js. I pushed a minor doc update to clarify this just now.
I got tired of hugo updates breaking my stuff so I wrote my own ssg. It was honestly a breeze to assemble with go, goldmark and a-h/templ.