インフラ屋がNext.js × Supabaseに手を出したら、デプロイの沼で死にかけた話(開発者尊敬します...)
1. はじめに
開発の動機:なぜインフラ屋が今、手を動かすのか
普段、クラウドのコード化(IaC)や監視設定、ネットワークのルーティングに明け暮れている私ですが、ふと一つの疑問が湧きました。
「自分が運用しているインフラの上で、アプリはどう息づいているのか?」
これを理解するためには、実際にユーザーに価値を届けるフロントエンドからバックエンドまでを一気通貫で構築するのが近道です。そこで、私が普段から「技術書選び」で多大なる恩恵を受けている、ジャバ・ザ・ハットリさん(@jabba)の超有名サイト 「技術書ランキング」 の類似サイトを自作することを決意しました。
リスペクトと目標
ジャバ・ザ・ハットリさんのサイトは、情報の網羅性、直感的なUI、そして何より「エンジニアが本当に欲しい本がすぐ見つかる」という体験が素晴らしいです。今回は、その体験をNext.jsとSupabaseというモダンなスタックで再現し、あわよくば自分のインフラ的知見(デプロイフローの最適化や環境管理)を融合させることを目標としました。
完成したサイトがこちらです:
Engineer's Book Hub
2. 使用した技術(テックスタック)
「インフラエンジニアが作るなら、運用の手間が少なく、かつスケーラブルであるべき」という観点で選定しました。
フロントエンド:Next.js (App Router)
ReactフレームワークのデファクトスタンダードであるNext.jsを採用。
App Routerの活用: サーバーサイドレンダリング(SSR)とクライアントサイドレンダリング(CSR)を適切に使い分け、SEOとユーザー体験の両立を図りました。
TypeScript: 型定義による堅牢な開発。インフラ屋にとって「型」は「設計図」と同じくらい重要です。
Tailwind CSS: 直感的なスタイリング。CSSの沼にハマることなく、ロジックに集中できました。
バックエンド・データベース:Supabase
「FirebaseのPostgreSQL版」とも言われるBaaS(Backend as a Service)を採用。
PostgreSQL: インフラエンジニアにとって最も信頼のおけるデータベースの一つです。
Supabase Client: APIサーバーを自前で立てることなく、フロントエンドから直接セキュアにデータを操作できるため、開発スピードが爆速になりました。
ホスティング:Vercel
Next.jsとの親和性が最も高いプラットフォーム。
GitOps: GitHubへのプッシュをトリガーとした自動ビルド・デプロイ環境を構築。
Edge Functions: 低レイテンシなレスポンスを実現。
3. 主な機能
本家「技術書ランキング」の魂を継承しつつ、以下の機能を実装しました。
① Google Books API を活用した書籍データの取得
書籍情報は自前で持たず、Google Books APIを叩いて動的に取得しています。
コード スニペット
// Supabaseクライアントの初期化。ここがアプリの心臓部。
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
② カテゴリ別・トレンド別のランキング表示
エンジニアの興味関心(言語別、クラウド別など)に合わせたランキングを表示します。
データフロー:
ユーザーがページにアクセス。
Next.jsのServer ComponentがSupabaseから「いいね」数や「閲覧数」を取得。
APIから詳細な書籍情報をマージして表示。
③ レスポンシブUI
インフラエンジニアは移動中や隙間時間にスマホで技術情報をチェックすることが多いため、モバイルファーストで設計しました。Tailwind CSSの grid や flex を駆使し、どのデバイスでも崩れないレイアウトを構築しています。
④ デプロイ・パイプラインの自動化
ここがインフラ屋のこだわりポイントです。
GitHubのリポジトリとVercelを連携させ、mainブランチへマージされた瞬間に本番環境が更新されるCICDパイプラインを構築。
途中、「ブランチの切り替えミスでVercelが404を吐く」、 「環境変数の設定忘れでビルドが落ちる」 といった、開発者なら誰もが通る「洗礼」も受けましたが、それら全てが「アプリがどう動くか」を理解する貴重な糧となりました。
4. 苦労したポイント:デプロイという「最後の壁」
インフラエンジニアとして「環境構築はお手の物」と高を括っていましたが、モダンなフロントエンド開発のデプロイフローには独特の落とし穴がありました。
① GitHubブランチの「迷子」問題
GitHubにプッシュしたはずなのに、Vercel側で404エラーが出る……。この原因究明には時間がかかりました。
実は、ローカルのGit設定が複雑になっており、コードが入っていない空のブランチ(Engineer_Book_Hub)がデフォルト(default)になっていたのです。
インフラ屋として学んだ教訓は、 「プラットフォーム側がどのブランチを正(Source of Truth)と見なしているかを確認する重要性」 です。
最終的には、以下のコマンドで手元のブランチを整理し、GitHubの設定画面でデフォルトを main に切り替えることで解決しました。
PowerShell
# ブランチを強制的にmainへ統合し、GitHubの設定を上書き
git branch -M main
git push -u origin main --force
この「強制プッシュ(-f)」の重みは、本番環境を扱う人間として冷や汗をかく瞬間でしたが、不整合を断ち切るには必要な決断でした。
② 環境変数の「伝播」忘れ
次に立ちはだかったのが、supabaseUrl is required というビルドエラーです。
ローカルの .env.local に値を書けば動くのは当然ですが、 「ビルドパイプライン(Vercel)側にも同じ環境変数を注入しなければならない」 という、CI/CDの基本を改めて突きつけられました。
Vercelの管理画面で NEXT_PUBLIC_SUPABASE_URL を設定した瞬間にビルドが通った時の快感は、Terraformでリソースがプロビジョニングされた時の喜びに近いものがありました。
5. 開発を振り返って:インフラ屋がフロントエンドを触る意味
今回、ジャバ・ザ・ハットリさんのサイトをリスペクトして自作してみたことで、多くの「気づき」がありました。
アプリケーション視点でのリソース最適化
普段は「CPU使用率」や「メモリ使用量」ばかり見ていましたが、Next.jsのApp Routerを触ることで、 「いかにブラウザ側(クライアント)の負荷を減らし、サーバー側で計算を済ませるか(RSC)」 という、レイヤー7以上のパフォーマンス最適化の面白さを知りました。
「動くもの」を作るスピード感
BaaS(Supabase)とホスティング(Vercel)を組み合わせることで、インフラを1からプロビジョニングする時間の9割を、機能実装(ロジック)に充てることができました。
「運用負荷を下げるための抽象化」の真骨頂を体験し、今後の実務でもサーバーレス構成を提案する際の強力な裏付けになりました。
ジャバ・ザ・ハットリさんへのリスペクト
実際に手を動かして分かったのは、本家「技術書ランキング」のUIがいかに洗練されているかです。
情報の取捨選択、ボタンの配置、ページ遷移の滑らかさ。これらをゼロから設計する労力を想像すると、改めて先駆者への敬意が深まりました。
6. おわりに
「餅は餅屋」という言葉がありますが、今の時代のエンジニアには、自分の専門領域の隣にある壁を少しだけ越えてみる勇気が必要だと感じました。
インフラエンジニアがアプリを書く。アプリエンジニアがインフラを知る。
その越境地点にこそ、 「本当に壊れにくく、使いやすいサービス」 を作るヒントが隠されているはずです。
今回の開発を通して、私はただの「サーバー管理者」から、 「ユーザーに価値を届ける仕組み全体を俯瞰できるエンジニア」 へと一歩近づけた気がします。
最後になりますが、インスピレーションをくださったジャバ・ザ・ハットリさん、そしてデプロイの沼から救ってくれたAIの相棒(Gemini,ChatFPT)に感謝します。
さあ、あなたも「憧れのサイト」を自分なりに再構築することから、モダン開発の海へ飛び込んでみませんか?
また、今回作成したサイトでぜひ知識の幅を広げてみてください。
Engineer's Book Hub
Discussion