前回の記事で「WordPressからAstroに移行した」という話をしましたが、今回はその裏側。 「で、実際Gitリポジトリはどうなってるの?」というエンジニア向けのディープな話です。
結論から言うと、「コンテンツ(Markdown)」と「ガワ(Astro)」を別々のリポジトリに分け、Git Submoduleで合体させるという構成を取りました。 一見面倒くさいこの構成をなぜ選んだのか、その設計思想と現実のトレードオフについて語ります。
リポジトリ構成の全体像
百聞は一見に如かず。今の構成はこんな感じです。
- Content Repository: 記事のMarkdownファイルと画像のみを管理。Astroの設定ファイルなどは一切なし。
- System Repository: Astro本体、コンポーネント、CSSなどを管理。Content Repositoryを
src/contents配下にサブモジュールとしてマウント。
なぜ分けたのか?(推したいメリット)
普通に考えれば、1つのリポジトリに全部突っ込む(Monorepo)のが一番ラクです。 でも、あえて分けました。そこにはエンジニア独自の「こだわり」と、ソフトウェア設計的な「正当性」があります。
1. システムは変わるが、コンテンツは資産である
これが最大の理由です。 今の流行りはAstroですが、3年後には「SuperUltraNext.js」が覇権を握っているかもしれません。 その時、システムとコンテンツが密結合していると、「移行作業=リポジトリの解体と再構築」になります。
リポジトリを分けておけば、将来Astroを捨てて別のフレームワークに乗り換える際、System Repositoryを作り直して、Content Repositoryをサブモジュールとして読み込むだけで済みます(理想論)。 コンテンツという「資産」を、移ろいやすい「技術トレンド」から守るための防衛策です。
2. DDD(ドメイン駆動設計)的な役割分担
ちょっとこじつけてみると、これはDDD的なアーキテクチャの適用とも言えます。
- コンテンツ = ドメイン層:
- ブログの本質的な価値。技術選定に依存しない、純粋な情報。
- 「記事の書きやすさ」や「データの整合性」だけに集中する場所。
- システム = プレゼンテーション/インフラ層:
- コンテンツをどう見せるか(HTML化、スタイリング)を担当。
- ドメイン(コンテンツ)を参照するが、ドメインはシステムを知らなくていい。
この分離により、「記事を書くときは技術のことを考えなくていい」「デザインをいじるときは記事を壊す心配をしなくていい」という、責務の分離が実現できます。
コンテンツリポジトリには package.json すらありません。あるのは純粋なテキストと一部画像のみ。この潔さが心地いいのです。
3. デプロイのトリガー制御
コンテンツの修正(誤字訂正など)と、システムの修正(機能追加)はライフサイクルが違います。 リポジトリを分けておけば、コンテンツ更新のPushをトリガーにするワークフロー、システム更新をトリガーにするワークフローを明確に分離できます。 「CSSを1行直しただけなのに、全記事の再処理が走る」みたいな無駄を防ぎやすくもなります。
現実の厳しさ(トレードオフとデメリット)
と、良いことばかり書きましたが、現実は甘くありません。「分離の代償」は確実に存在します。
1. Git操作がシンプルに面倒くさい
これが最大のデメリットです。
記事を書いて公開するフローが、単一リポジトリなら git push 一発ですが、この構成だと…
Content Repoで記事を書いて Commit & Push。System Repoに移動して、サブモジュールの参照を更新 (git submodule update --remote)。System Repoで変更を Commit & Push。
2回Pushしないとデプロイされないわけです。 「記事書いたのに反映されてない!」→「あ、サブモジュールのポインタ更新忘れてた」という事故が多発します。 (GitHub Actionsで自動化もできますが、それはそれで構築コストがかかる…)
2. ローカル開発環境のセットアップが複雑
git clone しただけでは記事データが空っぽです。
git submodule init して update して…という手順を、cloneするたびにやる必要があります。
あと両方のリポジトリを意識しながら作業するのも、地味に面倒です。
Q. そもそもHeadless CMSを使えばいいのでは?
もっともなツッコミです。 microCMSやContentfulを使えば、非エンジニアでも更新できますし、画像管理も楽でしょう。 「コンテンツとシステムの分離」もAPIベースで綺麗に実現できます。
それでもあえてGitベース(Markdown管理)を選んだ理由は、以下のメリット・デメリットを天秤にかけた結果です。
Headless CMS vs Git管理
| 特徴 | Headless CMS (microCMS, Contentful) | Git管理 (Markdown) |
|---|---|---|
| 執筆体験 | Webブラウザ上のエディタ | VS Code / Vim (ローカル環境) |
| オフライン | 不可(ネット必須) | 可能(飛行機でも書ける) |
| 画像管理 | GUIでドラッグ&ドロップ (楽) | ファイルパスを手書き (苦) |
| バージョン管理 | サービスの履歴機能依存 | Gitの強力な機能がフルに使える |
| ベンダーロックイン | あり (サービス終了/値上げのリスク) | なし (テキストファイルは永遠) |
| 運用コスト | プランによる (無料枠制限あり) | 無料 |
要するに、「利便性(CMS)」よりも「自由と支配権(Git)」を取ったということです。 「サービスがサ終したので記事をエクスポートして…」という作業は二度としたくない。 Markdownファイルとして手元にあれば、GitHubがなくなってもGitLabに行けばいいとか思ってます。
Cloudflare Pagesへのデプロイ方法
Cloudflare PagesはGit Submoduleに対応しているので、基本的には設定さえ間違えなければ動きます。
1. .gitmodules の設定
System Repository にある .gitmodules ファイルで、コンテンツリポジトリのパスを指定します。
ここで注意なのが、公開リポジトリ(Public)ならHTTPSのURLで書くこと。SSH(git@github.com:...)だと、Cloudflareのビルド環境で権限エラーになります。
[submodule "src/contents"] path = src/contents url = https://github.com/your-name/your-content-repo.git相対パスでも大丈夫だったりします。
[submodule "src/contents"] path = src/contents url = ../your-content-repo.gitもしコンテンツリポジトリがPrivateだとしてもCloudflare側で認証していれば動くので、わざわざPublicにする必要はありません。(ブログ記事なら公開されて困るものもないでしょうが…)。
2. ビルドコマンド
git submodule update --init --recursive はCloudflare Pagesがビルド前に勝手にやってくれます(神)。
なので、通常のAstro同様、ビルドコマンドは npm run build、出力ディレクトリは dist を指定するだけでOKです。
まとめ
- メリット: コンテンツを技術的負債から切り離せる。DDD的にクリーンな構成。将来の移行が楽。
- デメリット: 日々の運用(Git操作)の手数が増える。
正直、「個人ブログでここまでやる必要ある?」と聞かれれば、「ない」と答えるでしょう。 ただ、エンジニアたるもの、「ロマンある構成」で飯を食いたい時があるのです。 「ただのブログ」を「設計されたコンテンツ配信システム」に昇華させたい方は、ぜひこの茨の道へ足を踏み入れてみてください。



