HugoとClaudeCodeでブログ作ってみた

Featured image of post HugoとClaudeCodeでブログ作ってみた
目次

こんにちは、たひです。

Web/フロントエンドへの毛嫌い、馴染みの無さがあり作りたいとは思いつつブログを立ち上げるのを先延ばしていました。昨今AIコーディングエージェントサービスがある程度実用的なレベルになり、コーディングに対するコストが下がりました。これなら毛嫌いしていた領域にも手をつけやすくなるのではと思い立ち、このサイトを立ち上げました。

以降はこのサイト製作に使用したHugoとClaudeCodeで行ったことについてまとめます。

まずは開発環境選び

ブログ環境の候補としてWordPress、React、Next.js、Hugoなどを検討しました。最終的にHugoに決めた主な理由は以下のとおりです。

  • セキュリティとメンテナンスコストを考えて静的サイトであること
  • 記事をMarkdownで書けること
  • テーマ(テンプレート)が豊富であること

ディレクトリ構造とテンプレート階層を即座に把握できた

「layouts/とthemes/<theme>/layouts/の上書き優先順位(Lookup Order)はどうなってるの?」みたいな疑問に、ドキュメント該当箇所込みで答えてくれます。自分でHugoのLookup Orderを読み解いていたら、確実に半日は溶かしていました。

エラーメッセージの解読が速い

Hugoのerror: failed to render ...系のエラーは、テンプレート式の文脈に依存していて、初心者には原因が見えません。 ClaudeCodeに貼ると「これは.Site.Params.xxxの参照型が違う」のように切り分けてくれて、修正差分まで提示してくれます。組み込みでいう「LA当てなくても症状からバグの当たりが付く先輩」が常駐している感覚です。

やりたい見た目をテンプレート差分の形で出してくれる

「記事カードに公開日と更新日の両方を出したい」と頼むと、layouts/partials/article/components/details.htmlをテーマからコピーして上書きする差分を出してくれます。テーマ全体をフォークせず、必要なファイルだけパッチするという運用が成立するのが大きい。組み込みでいう「他人のミドルウェアに割込ハンドラだけ差し替える」感覚です。

Hugoの知識ゼロでもhugo.tomlを整えられる

hugo.tomlの各パラメータが何を意味するのか、SEOのOpenGraph設定はどう書くか、サイトマップやページネーションの設定値は何が妥当か、こういう「経験値で決める」ところをClaudeCodeが下書きしてくれました。あとは自分の好みに合わせて値を調整するだけで済んだので、ドキュメントを最初から読む必要がほぼなかったです。

Hugo Theme Stackのオーバーライドに苦戦

テーマ選定とカスタマイズの必要性

Hugo Theme Stackは、モダンでレスポンシブな優れたテーマです。

ただ、デフォルトのままだと自分のスタイルに合わなかったので、カスタマイズが必要でした。

オーバーライドの仕組みで苦労した点

1. テーマのオーバーライド階層の理解

Hugoではlayouts/ディレクトリに同名ファイルを配置すると、テーマのファイルを上書きできます。

でも、どのファイルをオーバーライドすればいいのか分からないんですよね。

テーマの構造を理解するのに時間がかかりましたし、一部だけ変更したいのにファイル全体をコピーする必要があって面倒でした。

実例:日付表示のカスタマイズ

記事の公開日と更新日を表示したかったんですが、デフォルトでは公開日のみ。

layouts/partials/article/components/details.htmlをオーバーライドして実装しました。

1
2
3
4
5
6
7
8
9
<!-- 更新日の表示を追加 -->
{{ if $showLastmod }}
    <div>
        {{ partial "helper/icon" "refresh" }}
        <time class="article-time--updated">
            {{ .Lastmod | time.Format "2006/01/02" }}に更新
        </time>
    </div>
{{ end }}

2. CSSのカスタマイズ

テーマのSCSSをオーバーライドして独自のカラーテーマを設定しました。

  • ダークモード対応のカラー変数を調整
  • アイコンと文字の間隔を調整(デフォルトでは広すぎる)
  • ピン留め記事のバッジカラーをカスタマイズ

例えば、日付表示のアイコンと文字の間隔が広すぎたので調整しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// assets/scss/custom.scss
.article-time {
    div {
        display: flex;
        align-items: center;
        gap: 0.35em; /* アイコンと文字の間隔を文字サイズに合わせる */

        svg {
            width: 16px;  /* デフォルトの20pxから縮小 */
            height: 16px;
            transform: translateY(0.5px); /* 微調整 */
        }
    }
}

3. パーシャルテンプレートの活用

ファビコンが表示されない問題にも直面しました。

layouts/partials/head/favicon.htmlを新規作成して解決しました。

1
2
<link rel="icon" type="image/x-icon" href="{{ .Site.BaseURL }}favicon.ico">
<link rel="shortcut icon" type="image/x-icon" href="{{ .Site.BaseURL }}favicon.ico">

ClaudeCodeの助けで、テーマの構造を理解しながらカスタマイズを進められました。

ただ、初見では難易度が高いと感じましたね。

開発環境はDockerに統一

最初はWindowsに直接Hugo Extendedを入れて運用していたんですが、後からWSL2 + Docker Desktopベースに切り替えました。

  • Hugo Extended・Node.js・Playwrightをまとめた1つのイメージにする
  • ローカルにHugoバイナリを置かない方針(バージョンずれや「自分の環境では動く」を防ぐ)
  • docker compose up -dで開発サーバー起動、docker compose downで停止
1
2
3
4
5
6
# 開発サーバー(http://localhost:1313、下書き含む)
docker compose up -d

# 単発コマンド(記事生成・本番ビルド等)
docker compose run --rm dev hugo new content/post/YYYY/MM/<slug>/index.md
docker compose run --rm dev hugo --minify

レイアウト変更時のスクリーンショット検証もPlaywrightをコンテナ内で動かしているので、Cloudflare Pages側のビルド環境と同じLinuxベースで挙動確認できるのが安心です。

Cloudflareでのデプロイとドメイン取得

Cloudflare Pagesを選んだ理由

ホスティングサービスは、Netlify、Vercel、GitHub Pagesなど選択肢がありますが、Cloudflare Pagesを選びました。

決め手となったポイントは以下の通りです。

  1. 無料枠が充実 - 無制限のビルド回数とトラフィック
  2. グローバルCDN標準装備 - 世界中で高速表示
  3. 独自ドメインの設定が簡単 - Cloudflareでドメイン管理も一元化
  4. 自動デプロイ - GitHubにプッシュすれば自動ビルド&デプロイ

無料でここまで使えるのは本当にありがたいです。

デプロイの手順

1. GitHubリポジトリの準備

1
2
3
4
5
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/username/repo.git
git push -u origin main

2. Cloudflare Pagesでプロジェクト作成

Cloudflareのダッシュボードから「Pages」を選択して、GitHubアカウントを連携します。

リポジトリを選択したら、ビルド設定を行います。

  • ビルドコマンド: hugo --minify
  • 出力ディレクトリ: public
  • 環境変数: HUGO_VERSION=0.152.2(Cloudflare側でHugo Extendedが必要な場合はHUGO_VERSION_EXTENDEDも同値で指定)

3. 独自ドメインの取得と設定

Cloudflareでドメインを取得して、Pagesに紐付けました。

  • Cloudflare Registrarでtahi314.workを取得
  • DNS設定は自動で完了
  • HTTPS証明書も自動発行

めちゃくちゃ楽でした。

注意したポイント

  • Hugoのバージョンを環境変数で明示的に指定しないと、古いバージョンでビルドされる
  • baseURLをhugo.tomlで正しく設定する必要がある
  • サブモジュール(テーマ)は自動で取得されるが、初回は手動でgit submodule update --initが必要
  • 増分ビルドでpublic/scss/style.min.<hash>.cssが蓄積する問題にはhugo.tomlにcleanDestinationDir = trueを入れて回避(毎ビルドでpublic/を掃除してくれる)

デプロイ後の運用

自動デプロイの快適さ

mainブランチにプッシュすると自動ビルドが走ります。

ビルド結果はCloudflareのダッシュボードで確認できますし、エラーがあればメール通知も来ます。

プレビューデプロイ

Pull Requestを作成すると、自動でプレビュー環境が生成されます。

本番環境に影響なくテストできるので便利ですね。

Cloudflare Pagesのおかげで、インフラ管理に時間を取られることなく、記事執筆に集中できています。

まとめ

Hugo + ClaudeCode + Cloudflare Pagesの組み合わせは、「Web/フロントエンドが本職じゃないエンジニアでも、自分の道具として運用できるブログ環境」だと感じました。

組み込みエンジニア視点での感想

  • Hugoは「静的ファイルを吐くだけのビルドツール」なので、ファームウェア感覚で挙動を予測できる
  • ClaudeCodeがGoテンプレート/SCSS/Cloudflareの “方言” を翻訳してくれるので、初見でも詰まらない
  • Cloudflare Pagesの自動デプロイで、インフラ管理ではなく記事執筆に時間を使える

苦労した点

  • テーマのオーバーライド構造(Lookup Order)の理解に時間がかかった
  • 細かいCSSの差分調整は結局自分で試行錯誤が必要

これから組み込み技術に関する記事を書き溜めていきます。

「組み込み出身だけど技術ブログを持ちたい」という人の参考になれば幸いです。

参考リンク

Hugo で構築されています。
テーマ Stack は Jimmy によって設計されています。