Astroモノレポ構成編 #1 全体像と環境準備
本連載は「複数の Astro サイト(ブログ、技術メモ、Web アプリ、Wiki など)を 1 リポジトリで運用する」構成を、最初からモノレポとしてセットアップする手順を扱う。1 リポジトリで 1 サイトだけ運用したい場合は別連載「Astroで個人サイトを作る」を参照されたい。シンプルさが欲しいなら単一プロジェクト編、最初から複数サイトを見据えるなら本連載、というのが選び方の目安になる。
連載初回となる本記事では、なぜモノレポ構成にするのか、どのツールを使うのか、最終的にどんなディレクトリ構造を目指すのかを整理する。実作業は次回から入る。
モノレポという言葉が指す範囲
モノレポ(monorepo)は「複数のプロジェクトを 1 つのリポジトリで管理する構成」を広く指す言葉である。歴史的には Google や Facebook の巨大な単一リポジトリが代表例として語られるが、現代の Web フロントエンド文脈で「モノレポ」と言うときは、もっと小さい規模を想定していることが多い。本連載で作るのは次のような構成である。
- 個人ブログ(雑記中心)
- 技術ブログ(プロジェクト紹介を兼ねる)
- Web アプリ本体(動的処理あり)
- 攻略 / Wiki 系サイト
これらをサブドメインごとに切り分け、共通のヘッダ・フッタ・SEO 用コンポーネントは 1 箇所にまとめて使い回す、という構成を目指す。
モノレポにする利点
複数サイトをひとつのリポジトリに置くと、次のような利点が出てくる。
- 横断的な変更がアトミックになる: 共通レイアウトに手を入れて全サイトを追従させるとき、1 つの PR で済む。
- 依存バージョンを揃えやすい: Astro やプラグインのバージョンを各サイトで揃えやすい。pnpm の
overridesを使えば、リポジトリ全体で特定パッケージのバージョンを強制することもできる。 - 共通コードを切り出しやすい: ヘッダ、フッタ、SEO まわりのコンポーネントを
packages/uiのような場所に置き、各アプリから参照できる。 - ツーリングの集約: ESLint、Prettier、TypeScript の設定をルートに置けるため、設定ファイルの重複が消える。
- デプロイの独立性: ホスティング側で「変更があったアプリだけビルド」を仕掛けると、ブログを更新したときに Wiki まで再ビルドされる無駄がなくなる。
pnpm workspace を選ぶ理由
JS モノレポを構成するツールには複数の選択肢がある。
- pnpm workspace: pnpm 本体に組み込まれた機能。
pnpm-workspace.yamlで対象を宣言する。 - Yarn workspaces: Yarn 1/2/Berry にそれぞれ存在。
- npm workspaces: npm 7 以降。最も素朴。
- Turborepo: pnpm/Yarn/npm の workspace に被せてタスクのキャッシュと並列実行を担う。
- Nx: タスクランナーに加え、ジェネレータや依存グラフ分析まで含む。
本連載では pnpm workspace を採用する。理由は次の三点である。
- ディスク使用量とインストール速度: pnpm はグローバルストアからハードリンクで参照する仕組みなので、同じ依存を複数アプリで重複保存しない。
- 厳格な依存解決:
package.jsonに書いた依存しか import できない(phantom dependency を防ぐ)。 - ワークスペースのサポート:
pnpm-workspace.yamlだけで複数パッケージを宣言でき、追加のメタフレームワークが不要。
タスクの並列実行が遅くなってきたら、上に Turborepo を被せて段階的に高速化する、というのが筋の良い拡張パスになる。
Node と pnpm のインストール
モノレポ構成では Node 22 系 LTS と pnpm v10 を使う。Node のバージョン管理は fnm を使うのが手軽である。
# macOS
brew install fnm
echo 'eval "$(fnm env --use-on-cd)"' >> ~/.zshrc
source ~/.zshrc
# Node のインストール
fnm install --lts
fnm use lts-latest
確認すると次のような表示になる。
$ node -v
v22.12.0
$ fnm --version
fnm 1.39.0
pnpm は Corepack 経由で入れるのが手早い。Corepack は Node に同梱されているので追加ダウンロードは不要である。
corepack enable
これだけで pnpm コマンドが使えるようになる(権限エラーが出る場合は sudo corepack enable)。後ほど pnpm init の初回実行時に、pnpm@10.x.x のバイナリが自動でダウンロードされる仕組みになっている。
想定する最終構成
本連載で作るリポジトリは、最終的に次のような構造を目指す。
my-project-monorepo/
├── apps/
│ ├── blog/ # 個人ブログ(blog.example.com)
│ ├── tech/ # 技術メモ・プロジェクト紹介(tech.example.com)
│ ├── app/ # Web アプリ本体(app.example.com)
│ └── wiki/ # 攻略・Wiki 系(wiki.example.com)
├── packages/
│ ├── ui/ # 共通コンポーネント
│ └── config/ # 共通設定(任意)
├── pnpm-workspace.yaml
├── package.json
└── .gitignore
apps/ 直下に各 Astro アプリ、共通コードが必要になったら packages/ 配下に切り出していく、というシンプルな分け方である。
サブドメインで分けるか、パスで分けるか
複数サイトを 1 ドメイン下に同居させる場合、次の 2 通りがある。
- サブドメイン分割:
blog.example.com,tech.example.com,app.example.com。ホスティング側のプロジェクト分割と素直に対応する。 - パス分割:
example.com/blog/,example.com/tech/,example.com/app/。SEO 上の集約効果はあるが、ホスティング層でルーティングを書く必要があり構成が複雑になる。
本連載では「ホスティング設定が直感的」「Astro の site 設定がアプリごとに完結する」という理由でサブドメイン分割を採用する。
ホスティング先
本連載でも Cloudflare Pages を採用する。理由は単一プロジェクト編と同じで、無料枠が広く、サブドメインごとに別 Pages プロジェクトを作って同じリポジトリを接続する、というモノレポ向きの運用がしやすいからである。各サイトの設定を「Root directory は /、Build command は pnpm --filter <app> build、Build output directory は apps/<app>/dist」と書けば済む。
次回に向けて
次回は実作業に入る。mkdir my-project-monorepo から始めて、pnpm init で workspace を初期化し、pnpm-workspace.yaml の作成までを行う。各種コマンドとその出力を逐一示しながら進める。