diff --git a/Gemfile b/Gemfile
index 76ec2d4..2f2f390 100644
--- a/Gemfile
+++ b/Gemfile
@@ -12,3 +12,5 @@ gem "front_matter_parser", "~> 1.0"
gem 'phlex-markdown', git: 'https://github.com/phlex-ruby/phlex-markdown'
gem "tailwindcss-phlexite", "~> 0.1.0"
+
+gem "kramdown", "~> 2.5"
diff --git a/Gemfile.lock b/Gemfile.lock
index c781278..8dcc200 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -10,10 +10,13 @@ GEM
remote: https://rubygems.org/
specs:
front_matter_parser (1.0.1)
+ kramdown (2.5.1)
+ rexml (>= 3.3.9)
markly (0.12.1)
phlex (2.3.1)
zeitwerk (~> 2.7)
phlexite (0.1.3)
+ rexml (3.4.1)
tailwindcss-phlexite (0.1.0)
tailwindcss-ruby (~> 4.1)
tailwindcss-ruby (4.1.8)
@@ -30,6 +33,7 @@ PLATFORMS
DEPENDENCIES
front_matter_parser (~> 1.0)
+ kramdown (~> 2.5)
phlex (~> 2.3)
phlex-markdown!
phlexite (~> 0.1.3)
diff --git a/assets/blog-banners/cheetahmontage.png b/assets/blog-banners/cheetahmontage.png
new file mode 100644
index 0000000..6c82d2a
Binary files /dev/null and b/assets/blog-banners/cheetahmontage.png differ
diff --git a/build.rb b/build.rb
index 0dbd8d4..ffd3ef1 100644
--- a/build.rb
+++ b/build.rb
@@ -1,5 +1,5 @@
require "phlex"
-require "phlex/markdown"
+require "kramdown"
require "phlexite"
require "tailwindcss/phlexite"
require "front_matter_parser"
diff --git a/dev b/dev
new file mode 100755
index 0000000..ea2138f
--- /dev/null
+++ b/dev
@@ -0,0 +1,2 @@
+#!/bin/sh
+watchman-make -p '**/*.rb' '**/*.md' --run 'bundle exec ruby build.rb'
diff --git a/pages/layout.rb b/pages/layout.rb
index 6545ff4..aff7d96 100644
--- a/pages/layout.rb
+++ b/pages/layout.rb
@@ -2,14 +2,17 @@ module Pages
class Layout < ::Phlex::HTML
def pages = {
home: {
+ as: :home,
title: "Home",
url: "/"
},
blog: {
+ as: :blog,
title: "Blog",
url: "/blog"
},
about: {
+ as: :about,
title: "About",
url: "/about"
}
@@ -46,7 +49,7 @@ module Pages
header(class: "#{@banner ? 'fixed' : 'sticky'} top-0 w-screen bg-transparent pointer-events-none flex p-3 items-center justify-center") {
nav(class: 'flex gap-2 p-2 rounded-full border border-gray-300 bg-white/50 backdrop-blur-md pointer-events-auto') {
pages.each { |key, page|
- a(href: page[:url], class: "block rounded-full px-3 py-1 #{key == @page ? 'bg-gray-100/50' : ''}") { page[:title] }
+ a(href: page[:url], class: "block rounded-full px-3 py-1 #{key == @page_info[:as] ? 'bg-gray-100/50' : ''}") { page[:title] }
}
}
}
diff --git a/pages/post.rb b/pages/post.rb
index 5c8dc0a..c2c65f2 100644
--- a/pages/post.rb
+++ b/pages/post.rb
@@ -5,7 +5,7 @@ class Pages::Post < ::Phlex::HTML
end
def view_template
meta = @post[:data].front_matter
- render ::Pages::Layout.new({title: meta['title']}) {
+ render ::Pages::Layout.new({ as: :blog, title: meta['title'] }, banner: meta['banner'], meta: {title: meta['title']}) {
article(class: 'prose prose-lg m-auto') {
h1 { meta['title'] }
if meta['published_on']
@@ -19,7 +19,7 @@ class Pages::Post < ::Phlex::HTML
hr
- render ::Phlex::Markdown.new(@post[:data].content)
+ raw safe Kramdown::Document.new(@post[:data].content).to_html
}
}
end
diff --git a/posts/2025-02-13-go-module-imports.md b/posts/2025-02-13-go-module-imports.md
index a316370..db9cca2 100644
--- a/posts/2025-02-13-go-module-imports.md
+++ b/posts/2025-02-13-go-module-imports.md
@@ -5,23 +5,23 @@ published_on: '2025-02-13'
*Updated 6/4/2025: Replaced the demo page.*
-Go modules are great. URL-based imports, generally, are great. One of the things that makes them so great is that putting them on your own domain provides a good way of verifying ownership without going through a third party or a complicated review process. Plus, it looks cool.
+Go modules are great. URL-based imports, generally, are great. One of the things that makes them so great is that putting them on your own domain provides a good way of verifying ownership without going through a third party or a complicated review process. Plus, it looks cool.
So, how exactly does one accomplish such a thing? Well, it's [buried in the documentation](https://pkg.go.dev/cmd/go#hdr-Remote_import_paths), but it's really pretty simple. For each import path (e.g. `mysite.com/mypackage`), just put a page on your website with a `go-import` meta tag:
-```html
+~~~ html
-```
+~~~
_(`git` can be replaced with `bzr`, `fossil`, `hg`, or `svn` for different VCSs — see the docs page linked above.)_
This website, for instance, builds these pages from a hash in [`build.rb`](https://git.sr.ht/~aleksrutins/farthergate.com/tree/main/item/build.rb#L14):
-```ruby
+~~~ ruby
def go_modules = {
"farthergate.com/stack" => "https://git.farthergate.com/aleks/stack",
# ...
}
-```
+~~~
-See [farthergate.com/terminated](/terminated) for an example of a generated page. Look in the web inspector for the `meta` tag!
\ No newline at end of file
+See [farthergate.com/terminated](/terminated) for an example of a generated page. Look in the web inspector for the `meta` tag!
diff --git a/posts/2025-06-09-an-ode-to-simplicity.md b/posts/2025-06-09-an-ode-to-simplicity.md
deleted file mode 100644
index 1cadb3b..0000000
--- a/posts/2025-06-09-an-ode-to-simplicity.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-title: An ode to simplicity
----
-
-If there's one lesson that I take from developing — and, more importantly, later abandoning — [Cheetah](https://cheetah.farthergate.com), it's this: nothing can kill a good project, or even a middling-to-mediocre project, like scope creep.
-
-The first big mistake I made was to do everything myself. Now, this was an incredible learning experience, of course: I learned how to write functioning Rust code, for one (functioning, not clean; please mind your footing around the `Rc>>>>`), but by everything, I mean _everything_. Starting with the template engine. And it wouldn't just be a normal, text-based template engine: this template engine (in [one file](https://github.com/aleksrutins/cheetah/blob/master/src/template.rs), for those who don't value their sanity) worked on the DOM.
diff --git a/posts/2025-06-10-an-ode-to-simplicity.md b/posts/2025-06-10-an-ode-to-simplicity.md
new file mode 100644
index 0000000..17b9e43
--- /dev/null
+++ b/posts/2025-06-10-an-ode-to-simplicity.md
@@ -0,0 +1,37 @@
+---
+title: An ode to simplicity
+banner: /blog-banners/cheetahmontage.png
+published_on: '2025-06-10'
+---
+
+If there's one lesson that I take from developing — and, more importantly, later abandoning — [Cheetah](https://cheetah.farthergate.com), it's this: nothing can kill a good project, or even a middling-to-mediocre project, like scope creep.
+
+The first big mistake I made was to do everything myself. Now, this was an incredible learning experience, of course: I learned how to write functioning Rust code, for one (functioning, not clean; please mind your footing around the `Rc>>>>`), but by everything, I mean _everything_. Starting with the template engine. And it wouldn't just be a normal, text-based template engine: this template engine (in [one file](https://github.com/aleksrutins/cheetah/blob/master/src/template.rs), for those who don't value their sanity) worked on the DOM.
+
+The engine would have been complicated enough already with just that, but the cherry on top was a declarative-shadow-DOM-based hydrating component system that automatically extracted scripts from the page. And, of course, everything had to run _as fast as humanly possible 🚀_ (after all, this is Rust). Thus: pointers! Pointers everywhere! Except: this is Rust, so we wrap our pointers in seven layers of boxes, because we don't understand how they work and are more than a little scared of them.
+
+Don't even ask about the Nix-based DSL for generating the HTML-based DSL for generating the site, or the Nix- and Caddy-based container builder, or any number of other quarter-finished micro-initiatives that all fed into the leviathan that that project was.
+
+Suffice to say, it didn't work very well. Forcing everything to be in its own shadow DOM — as expected — broke styling. Sure, the generator itself was _blazingly fast 🚀_, but _blazingly fast 🚀_ isn't worth much when the recommended project template pulls the Rust-based project from Nix without a binary cache. Building the site took a nanosecond, but the full CI workflow ended up taking several minutes each time.
+
+The final nail in the coffin, though, was dependency hell. Cheetah had more dependencies than any self-respecting programmer could chuck a rubber duck at.[^1] The most important of these was `kuchiki`, an HTML traversing library, which, after a couple of years, became unmaintained. I only noticed this when I tried to package an RPM — Fedora only packages the latest version of Rust crates, and the latest versions of `kuchiki`'s dependencies were incompatible. There was more, too, but I won't put you through it. In short, `cheetah` became unmaintainable. I had built a massive, hulking project, and being able to maintain it depended on everything not breaking all at once. A couple of years out, once versions started to misalign, everything broke. All at once.
+
+---
+
+Sometimes, discretion is the better part of valor. So, I rewrote it. It took a bit to settle, but I eventually settled on Ruby, and created [Phlexite](https://git.farthergate.com/asr/phlexite).
+
+In all honesty, "static site generator" are three rather strong words to describe Phlexite. It's a glorified path generation library with a nice DSL. It happens to also be smart enough to call functions to make pages. It's meant to be used with Phlex, but it's not restricted to it — in fact, it has no dependencies at all. It's simple enough that I haven't needed to update it in several months. This site is running with the latest (at the time of writing) version of Phlex (a major version ahead of where Phlex was when I last updated Phlexite), and it works without a hitch. If Cheetah was overcomplicated, Phlexite is oversimplified. And, after using it for a few months, oversimplification is winning.
+
+Writing Rust feels, at times, like a constant battle for my sanity and soul. It builds character,[^2] sure, but it's not always enjoyable. Ruby is _fun_. In Ruby, the answer to "Can I do this?" is almost always "Yes, easily". I can write code without worrying about performance, and it'll end up _fast enough_. Sure, Phlexite doesn't build sites as fast as Cheetah, but you don't have to wait for the optimizing compiler to build _it_ — and thus, CI ends up taking 20 seconds, rather than five minutes.
+
+This site is built with Phlexite. It has Tailwind-based styling, a sensible build script, a tiny little dev script based on Watchman, draft post support — all things that the Cheetah version didn't have, because I was too busy fighting the tooling. When I want to add a new feature, I just... add it. It doesn't generally take that long. Instead of fighting tooling on my blog, I can get past that to actually _write_.[^3]
+
+Parallels elsewhere: more recently, I've been using vanilla GNOME with VS Code and Zed on all of my devices, and I've been incredibly productive. WM configuration is _cool_, and bspwm and COSMIC are _blazingly fast 🚀_. But what use is _cool_ and _blazingly fast 🚀_ if I can't get anything done?
+
+Tech should serve our productivity, not the other way around. That's why high-level, dynamically-typed languages were made in the first place — and why they're still just as relevant, no matter how interesting the latest statically-typed systems programming language may be.
+
+---
+
+[^1]: The great irony here, of course, is that I accrued all of these dependencies in the interest of doing everything myself.
+[^2]:
+[^3]: My past self would have trouble believing that this is what a blog is for, but I'm pretty sure that this is what a blog is, actually for.