ryu.com
三つの週末で、ブログ用静的ジェネレーターを書いた 表紙画像
コード

三つの週末で、ブログ用静的ジェネレーターを書いた

2026年7月11日 · 約13分で読める

こういう経緯だ:ブログの再構築が必要になった。GCP 停止のあと、二度とバックエンドに依存しないと決めた。しかし何十本もの記事を手書き HTML で管理するのは明らかに非現実的だ。ツールが必要だった。

既存の選択肢はどれも重すぎた——Hugo、Jekyll、Astro、Next.js。良いツールではあるが、ブログ一本のために200MB の node_modules を引き込みたくはなかった。必要なのは三つだけ:Markdown を HTML に変換する、テンプレートを被せる、RSS を生成する。

というわけで三つの週末を使って、200行未満の Node スクリプトを書いた。

一週目の週末:「作らないこと」を決める

ほとんどのツールの問題は機能が少なすぎることではなく、多すぎることだ。最初の週末は「不要リスト」の作成に使った:

この「減算」のプロセスは、コードを書くことより重要だった。ブログに本当に必要なものが見えた:コンテンツ + 組版 + リンク。他はすべてノイズだ。

二週目の週末:コードを書く

核心のロジックはシンプルだ:

const fs = require('fs');
const path = require('path');
const { marked } = require('marked');

// 全 Markdown ファイルを読む
const posts = fs.readdirSync('content')
  .filter(f => f.endsWith('.md'))
  .map(f => parsePost(f))
  .sort((a, b) => b.date - a.date);

// 各記事の HTML を生成
for (const post of posts) {
  const html = applyTemplate(post);
  fs.writeFileSync(`dist/${post.slug}.html`, html);
}

// インデックスページを生成
const indexHTML = applyIndexTemplate(posts);
fs.writeFileSync('dist/index.html', indexHTML);

// RSS を生成
const rss = generateRSS(posts);
fs.writeFileSync('dist/rss.xml', rss);

実際のコードはもう少し長い——frontmatter 処理、URL 正規化、相対パス、シンタックスハイライト。でも核心の発想はこの三ステップ:読んで、変換して、出力する。

三週目の週末:全部消して書き直す

二週目が終わったあと、旧記事20本を取り込んでみた。いくつか問題が出た:

三週目の週末、スクリプト全体を消して書き直した。今度はもっとシンプルに——Markdown の自動変換を諦めて、HTML を直接手書きすることにした。後退に聞こえるかもしれないが、実際には:

最終的にこの「静的ジェネレーター」は50行のスクリプトまで退化した。やっていることはただ一つ:posts/ ディレクトリの HTML ファイルを走査し、タイトルと日付を抽出して、ホームのリストを生成する。

Less is actually more

この経験で「道具」の意味を考え直した。最高の道具は機能が一番多いものではなく、ちょうど足りるものだ。個人ブログにとって、テキストエディタと HTML ファイルこそが最高の CMS だ。

あなたもブログを始めたいなら、私からの提案はこうだ:まず書け。道具はそのあとで考える。中身を書き出し、HTML ファイルに入れ、静的ファイルをホストできるどこかにアップロードする。手動管理が苦痛になってきたら、そのとき自動化を検討すればいい。しかし大半の場合、手動管理の苦痛は複雑なフレームワークを学ぶ苦痛よりずっと小さい。


このサイトのソースは GitHub にある。ビルド工程なし。clone すればそのまま動く。

続きを読む