% cd ..

Next.js + Vercel で爆速でブログを作る

はじめに

AIでの翻訳の品質は年々レベルアップしていますので、日本語記事の英訳を作るのは本当に楽になっています。 なので、AIを活用した多言語対応のブログを簡単に作りたいなと思い立ちました。 このブログでは、ただAIで記事を翻訳するだけでは面白くないので、翻訳の品質をAIで自動検証する仕組みも組み込んでみようかと思います。(翻訳品質を検証する仕組みについては別記事で詳しく書いていきます。)

Jamstack(ジャムスタック)

このブログは Jamstack という比較的モダンなアーキテクチャで作っていきます。 JAM は以下の3つの頭文字です。

  • J (JavaScript): フロントエンドに React, Vue.js, Angularといった JavaScript フレームワークを用い、状態管理やDOM操作をクライアントサイドで完結
  • A (APIs): コンテンツはAPIを経由してバックエンドを担うヘッドレスCMSなどから取得する
  • M (Markup): Next.js, Hugo, Gatsbyなどの静的サイトジェネレーター(SSG)を使用し、あらかじめ静的なHTMLファイルを生成しCDNなどに配置する

WordPress のような従来のブログは、読者がアクセスするたびにサーバーが DB から記事を取得して動的に HTML を生成していました。 JAMstack は事前にサイト全体をプリレンダリング(HTML 生成)して CDN から配信することで、圧倒的な表示速度と強固なセキュリティを実現するモダンな設計手法です。 ビルド時にすべてのページを生成済みなので、サーバーは完成した HTML を返すだけです。表示が速く、サーバー管理も不要です。 フロントエンドをバックエンドやデータベースから切り離し、動的な機能はJavaScriptとAPIで補完するため、スケーラビリティに優れた効率的な運用が可能になります。

採用の決め手は Vercel が提供している「Markdown で書いて GitHub に push したら自動で公開される」というシンプルさです。記事は Git で管理するので差分も履歴も追えます。サーバーの面倒を見る必要もなく、Vercel が CI/CD を全部やってくれます。 もともとはヘッドレス CMS(Payload CMS)を使うことも考えていましたが、この運用フローだと CMS を通す理由が薄く、まずは Markdown ベースで始めることにしました。(厳密にはこの構成では API を使っていないので、Jamstack と呼ぶには J と M だけですが...まあ細かいことは気にしない方向で。)

技術スタック

具体的に決まった構成はこちらです。完全無料で始められそうです。

  • Next.js 16 (App Router) — フロントエンド
  • Markdown — frontmatter 付きで Git 管理
  • Vercel — GitHub push で自動ビルド・デプロイ
  • Supabase — PostgreSQL + pgvector で翻訳データ管理
  • Google Gemini API — 翻訳 + embedding(無料枠)
  • Tailwind CSS — スタイリング

設計上の考慮

CMS を使うかどうか

当初は Payload CMS を使う予定でした。WordPress 風のUIで記事を書けるのが魅力だったので。

ただ、GitHub push → Vercel 自動デプロイという運用フローだと、CMS を通す意味が薄くなります。結局「Markdown で書いて push するだけ」が一番シンプルという結論になりました。

Payload CMS は、いずれヘッドレス CMS を使ってみたいというのもあるので、後のフェーズで導入予定です。Markdown ベースで動くものを先に作っているので、CMS との違いを体感しながら進められそうです。

リポジトリ構成

非公開の単一リポジトリ dazy-blog で全部まとめて管理しています。

  • 記事 Markdown(posts/ja/posts/en/
  • Next.js フロントエンド(src/
  • 翻訳パイプライン・タグ付けスクリプト(scripts/
  • 設計ドキュメント(docs/
  • CMS 設定(keystatic.config.tsfrontmatter.json

git push すると Vercel が自動ビルド・デプロイされる、シンプルな構成です。スクリプトやドキュメントを編集しても、posts 配下を触らない限り翻訳パイプラインは動かないように workflow trigger を絞ってあるので、リポジトリが 1 つでも実験と本番更新を分けて運用できます。

ちなみに、posts 配下を編集してもどうしてもパイプラインを動かしたくない時(フォーマット整理だけのコミット等)は、コミットメッセージに [skip ci] を含めれば GitHub Actions がその push をスキップしてくれます。大文字小文字は無視されるので [Skip CI] でも OK。地味に便利です。

日英切替の実装

URL に言語プレフィックスをつける方式を採用しました。

/ja/posts/2026/04/hello-world  → 日本語版
/en/posts/2026/04/hello-world  → 英語版

/ にアクセスすると /ja にリダイレクトされます。ヘッダー右上の [JA] [EN] ボタンで切り替えられます。

タグの多言語対応

タグは ID(英小文字)で管理して、表示名は tags.json で言語別にマッピングする方式にしました。

{
  "tech": { "ja": "テック", "en": "Tech" },
  "anime": { "ja": "アニメ", "en": "Anime" }
}

frontmatter には ID を書くだけです。表示時に言語に応じて自動変換されます。将来もし中国語を足すとしても tags.json"zh" を追加するだけです。