kouno.log

chira-ura.netの技術スタック

chira-ura.netの技術スタック

「綺麗すぎるインターネット」へのアンチテーゼとして作った個人サイトプラットフォーム chira-ura.pages.dev を公開した。オタクが好きなことを好きなだけ書き殴れる、牧歌的な空間を目指している。

この記事では技術選定の理由と全体構成を解説する。

構成図

[Browser]

    │ HTTPS

[Cloudflare Pages]

    ├── Static Assets(/_nuxt/*)

    └── Workers Function(Nitro サーバーバンドル)

            ├── Pages / SSR(Nuxt ページレンダリング)

            └── Nitro Middleware


               [Hono Router](/api/*)


            [Supabase Cloud]
            ├── PostgreSQL
            └── Auth(Google OAuth)

すべて Cloudflare Pages の1デプロイに収まっている。ホスティングから SSR、API まで一気通貫な構成だ。

技術スタック

技術 バージョン 用途
Nuxt 4.x フルスタックフレームワーク
Vue 3.x UI レイヤー
TypeScript 5.x 型システム
Hono 4.x API ルーティング・バリデーション
TipTap 2.x WYSIWYG エディタ
Tailwind CSS 4.x スタイリング
Supabase 2.x DB (PostgreSQL) + Auth (Google OAuth)
Cloudflare Pages - ホスティング・Workers ランタイム
pnpm 9.x パッケージ管理

本番ランタイムは Cloudflare Workers(V8 isolates)。Node.js はローカル開発専用で、本番は一切使わない。

各技術の選定理由

Nuxt 4

フルスタックフレームワークとして採用。nitro: { preset: 'cloudflare-pages' } を指定するだけで Cloudflare Pages にネイティブ対応できる。

Nuxt 4 の app/ / server/ / shared/ のディレクトリ分離が今回のアーキテクチャとうまく噛み合っている。shared/ で API の型定義をフロント・サーバー間で共有できるのも大きい。

Vue のテンプレート構文は HTML に近く、チラ裏の「ちょっと装飾的な個人サイト感」を出す UI を書くのに自然にマッチした。

Hono(Nitro ミドルウェア統合)

API レイヤーとして Nuxt の server/api/*.ts ではなく Hono を採用した。

server/middleware/hono.ts で Hono アプリを Nitro イベントハンドラとして登録する構成にしている。toWebHandler(app) を使って H3 の受信イベントを Web API 標準の Request オブジェクトにブリッジする。

DBアクセスを Hono に閉じ込める

この構成の核心は「Supabase への直接アクセスをクライアントから排除する」という思想だ。

Supabase は RLS(Row Level Security)でデータアクセスを制御できる。anon key をブラウザに公開しても RLS がある限り他人のデータは取れない——それ自体は正しい。ただし、それだけだと RLS のポリシーミスが即座に本番障害につながる。

そこで Hono をデータアクセスの唯一の入口として設計した。クライアント(Vue)は Hono の API エンドポイントとだけ通信し、Supabase の存在を意識しない。

[Browser]


[Hono] ← バリデーション・認証チェック・ビジネスロジック


[Supabase]

これにより多層防御が成立する:

  • 第1層 — Hono: リクエストバリデーション(Zod)、認証トークン検証、ビジネスロジック
  • 第2層 — Supabase RLS: データベース側でも認証ユーザーのアクセス範囲を制限

RLS を「保険」として機能させつつ、実態としては Hono 側で制御する。RLS に単独で頼らない設計なので、ポリシーのバグが即座に穴になるリスクを下げられる。

また Hono にアクセスを集約することで、将来的なビジネスロジックの変更(レート制限・監査ログ・サービス移行)もすべて Hono 側で吸収できる。

DX 面の採用理由

  • zValidator によるルートレベルのリクエストバリデーション(Zod ベース)
  • hono/client による型安全な RPC クライアントが Vue composables からそのまま使える

Edge ランタイム設計で Node.js 依存ゼロなので、Cloudflare Workers との相性も抜群。

TipTap 2.x

WYSIWYG エディタとして採用。Extension ベースのアーキテクチャなので、Bold / Color / FontSize / Underline だけロードしてバンドルサイズを抑えられる。

データフローはシンプルに「HTML 文字列を出力 → Supabase に保存 → v-html で表示」。Quill と比較して開発が活発でカスタマイズ性も高い。

ただし TipTap は SSR 非対応なので <ClientOnly> ラッパーで囲む必要がある。

Tailwind CSS v4

CSS ファースト設定方式で tailwind.config.js が不要になった。@nuxtjs/tailwindcss モジュールで統合している。

Supabase

PostgreSQL + Row Level Security(RLS)の組み合わせが強力。認証連動のデータアクセス制御をデータベース側で完結できる。

Supabase Auth が Google OAuth のトークン交換を処理してくれるので、認証実装コードを最小限に抑えられた。セッション管理は @supabase/ssr パッケージで Cookie ベースに統一している。

DB へのアクセスはすべて Hono 経由に統一している。クライアント(Vue)は Supabase を直接叩かず、Hono の API エンドポイントとだけ通信する。Hono 内では service role key を使って Supabase にアクセスし、この key はクライアントに絶対に露出させない。

RLS はあくまで「第2層の保険」として機能させる設計で、実際のアクセス制御の主体は Hono 側に置いている。

Cloudflare Pages

  • コールドスタートなし: Workers の V8 isolates で即レスポンス
  • 無料枠が潤沢: 100,000 リクエスト/日
  • Nitro の cloudflare-pages プリセットが _worker.js + 静的アセットを出力し、CF Pages の期待する形式にそのまま一致

Vercel と比べてエッジネットワークの低レイテンシと関数実行時間の制限なしが優位だった。

ディレクトリ構造

Nuxt 4 の app/ / server/ / shared/ 分離に準拠している。

chira-ura/
├── app/                     ← クライアントサイド
│   ├── components/
│   │   └── editor/
│   │       └── TipTapEditor.vue
│   ├── composables/
│   │   ├── useSupabase.ts
│   │   └── useAuth.ts
│   ├── pages/
│   │   ├── index.vue        ← トップ(ランダムジャンプボタン)
│   │   ├── login.vue
│   │   └── [username]/
│   │       ├── index.vue    ← ユーザー日記一覧
│   │       └── [postId].vue ← 個別投稿表示
│   └── stores/
│       └── auth.ts

├── server/                  ← サーバーサイド
│   ├── middleware/
│   │   └── hono.ts          ← Hono → Nitro ブリッジ
│   └── routes/
│       └── hono/
│           ├── posts.ts
│           ├── auth.ts
│           └── links.ts

└── shared/                  ← フロント・サーバー共有
    └── types/
        └── api.ts           ← Hono RPC 用型定義

まとめ

個人サイトプラットフォームとしては少し重厚な構成かもしれないが、全部入りで1デプロイに収まる気持ちよさがある。型安全な API(Hono RPC)、認証込みのデータ層(Supabase)、エッジで動く SSR(Cloudflare Workers)——この3つが噛み合うと開発体験がかなり良い。