NAKASHIMA CRAFT で開発を担当している中島Dです。

このたび、当ブログを Rust で書いた自前の SSG (Static Site Generator) で構築しました。 Hugo や Zola、Astro のような完成度の高い既存ツールが多数ある中で、なぜわざわざ自前で実装したのか。 その理由と、実際の構成についてまとめます。

#既存 SSG を採用しなかった理由

率直に申し上げると、Hugo や Zola を使えば 半日で立ち上げられたはずです。 それでもあえて自作を選んだ理由は、大きく 3 つあります。

#1. 本体サイトと同じ「ブランドの空気感」を維持したい

NAKASHIMA CRAFT のメインサイトは Leptos + Tailwind v4 + daisyUI v5 で構築しています。 ブログだけを別のテーマシステム(Hugo の Go テンプレートや Zola の Tera 等)で組んでしまうと、

  • 配色や余白の単位がわずかにずれる
  • アップデートのたびに 2 箇所をメンテナンスする必要がある

といった地味な摩擦が積み上がっていきます。Tailwind の生成 CSS を共有するためには、ビューを生成する側もそれを前提とした実装にした方が結果的に早い、と判断しました。

#2. SSG の中身は思いのほかシンプル

実のところ、SSG の本質は驚くほどシンプルです。

  1. Markdown ファイルを読み込む
  2. フロントマターをパースする
  3. Markdown → HTML に変換する
  4. テンプレートで囲む
  5. ファイルに書き出す
  6. RSS / sitemap / OGP も生成する

これだけです。 Rust にはこの各ステップに対応する成熟したクレートがあります:

  • pulldown-cmark — Markdown パーサ
  • gray_matter — フロントマター抽出
  • maud — コンパイル時 HTML マクロ
  • syntect — シンタックスハイライト
  • resvg — SVG → PNG レンダリング (OGP 生成用)
  • rss — RSS フィード生成

これらを組み合わせるだけで、500 行程度のコアコードでブログ用 SSG が完成します。

#3. 「やりたいこと」と「フレームワークの想定」はいずれズレる

長く運用する個人・企業のサイトでは、必ず「フレームワークの想定外のこと」をやりたくなる場面が訪れます。

  • カテゴリ別の OGP 画像を自動生成したい
  • 関連記事を独自ロジック(同一カテゴリ +3、共通タグ +1)で並べたい
  • パンくずリストの構造化データを記事カテゴリと連動させたい

こうした要件は既存 SSG でもプラグインで対応できますが、プラグインを読み解くより自分のコードを読む方が早いという事実は、長期運用の生産性として決して無視できません。

#実際の構成

役割クレート / ツール
Markdown パーサpulldown-cmark 0.13
フロントマター(TOML)gray_matter 0.3
HTML テンプレートmaud 0.27
シンタックスハイライトsyntect 5.3
OGP 画像生成resvg 0.45 + usvg + tiny-skia
RSS フィードrss 2.0
ローカル開発サーバaxum 0.8 + tower-http
スタイルTailwind v4 + daisyUI v5
デプロイCloudflare Workers Assets

Rust edition は 2024、rustc は 1.85 を要求しています。

#自作して得られた手応え

実際に自作してみて、ひとつ強い実感を得ました。

「自分の手の届くサイズの道具を、自分で組み上げる」ことの手応えは、 やはり大きなものでした。

大規模サイトにはまず向かない選択ですが、個人や小規模事業のブログ規模であれば、自作はむしろ運用負荷を下げる方向に働きます。 コードの全責任を自分が持っているため、何か起きてもまず自分のコードを読めば原因にたどり着けます。この安心感は、長く運用するほど効いてくるはずです。

詳しい実装については、ブログ本体のソースコードを今後 GitHub で公開する予定です。 ご興味のある方は、公開時にあらためてご覧いただけますと幸いです。