最近、個人的なウェブサイトを完全にAIの力を活用して構築しました。このブログでは、このサイトの技術スタック、アーキテクチャ、そして実装プロセスについて詳しく解説します。AI主導の開発がどのように効率的で革新的なウェブ開発を可能にするかを紹介します。
技術スタックの選択
このサイトは次の技術スタックを使用して構築されています:
-
HonoX: Cloudflare WorkersとSSG(静的サイト生成)をサポートする軽量なWebフレームワーク。Honoをベースに拡張された特徴として、静的サイト生成の機能が追加されており、ビルド時にHTMLを生成することで高速なページロードを実現しています。また、JSXでのルート定義やアセットの最適化など、開発者体験を向上させる機能も備えています。
-
TypeScript: 型安全性のある開発環境を実現。大規模なプロジェクトでもコードの品質を維持し、リファクタリングを容易にします。このプロジェクトでは厳格な型チェックを有効にし、すべてのコンポーネント、ユーティリティ、データ構造に対して詳細な型定義を行っています。
-
MDX: ブログと「アイデア」セクションの両方のコンテンツ管理。Markdownの拡張としてJSXの機能を組み合わせることで、リッチなコンテンツを作成できます。フロントマターでメタデータを管理し、タグやカテゴリによるコンテンツの整理も実現しています。
-
TailwindCSS: ユーティリティファーストのCSSフレームワークで、スタイリングとレスポンシブデザインを効率的に実装。Typography pluginを使用してMDXコンテンツの見た目を美しく整えています。カスタムカラースキームやアニメーションも定義して、サイト全体での一貫したデザイン言語を確立しました。
-
Cloudflare Workers: グローバルに分散したエッジでコードを実行するサーバーレスプラットフォーム。低レイテンシー、高可用性、メンテナンスの手間が少ないのが特徴です。SSGと組み合わせることで、静的アセットの配信と動的な機能の両方を効率的に提供できます。
-
Vercel OG: 動的OG画像生成のためのサービス。各ページのメタデータに基づいてカスタマイズされたOG画像を生成し、SNSでシェアされた際の視覚的なアピールを高めています。タイトル、カテゴリ、言語などに応じたデザインの変更も自動化しています。
-
Vite: 最新のフロントエンドビルドツールで、高速な開発環境とプロダクションビルドを提供。HMR(Hot Module Replacement)によって開発中の変更がほぼ瞬時に反映され、効率的な開発ワークフローを実現しています。
これらの技術を選んだ主な理由は以下の通りです:
- パフォーマンス: SSGとCloudflare Workersの組み合わせにより、世界中どこからアクセスしても高速なページ読み込みを実現
- 開発の容易さ: TypeScriptとModern JSXによる快適な開発体験
- コンテンツ管理の柔軟性: MDXによるコンテンツとコードの統合
- 拡張性: 将来的な機能追加やスケーリングが容易なアーキテクチャ
- コスト効率: サーバーレスアーキテクチャによる運用コストの最適化
- 最新技術の探求: Jamstackアーキテクチャの可能性を最大限に活用
AIによる自立開発プロセス
このプロジェクトの最も注目すべき点は、ほぼ完全にAIを活用して開発されたことです。人間による介入を最小限に抑えながら、複雑なウェブサイトを構築するための全プロセスをAIが主導しました。以下のAIツールが活躍しました:
Claude Code
Claude CodeはAnthropicのCLIツールで、コーディングプロセスのほぼすべての側面を支援しました:
-
初期プロジェクト構造の設計: HonoXプロジェクトの適切なディレクトリ構造の設計、必要なファイルとフォルダの初期設定を行いました。MVCパターンに従いながら、モダンなJamstackアーキテクチャに適したファイル構成を提案しました。
-
HonoXの設定とルーティング: 複雑なルーティング設計(動的ルート、ネストされたルート、パラメータを含むルートなど)を含むHonoXの構成を実装。SSGパラメータの設定や、効率的なルートハンドラーの作成も行いました。
-
TypeScriptのインターフェースと型定義: 堅牢な型システムを構築し、コードの安全性と品質を確保。ブログやアイデアのフロントマターから、UIコンポーネントの型定義まで、すべての要素に対して厳密な型チェックを適用しました。
-
MDXの統合と処理パイプラインの構築: MDXファイルの読み込み、解析、レンダリングを行うための完全なパイプラインを構築。フロントマターの検証やコンテンツのソート、フィルタリングなどの機能も実装しました。
-
コンポーネント開発とスタイリング: 再利用可能なUIコンポーネントのライブラリを構築。TailwindCSSを活用した一貫したデザインシステムを確立し、レスポンシブデザインとアクセシビリティにも配慮しました。
-
国際化(i18n)の実装: 効率的な多言語サポートシステムを構築。ロケールに基づくルーティング、コンテンツの翻訳管理、日付や数値のフォーマットなど、包括的な国際化対応を実現しました。
-
SEO最適化: メタタグ、OG画像、構造化データ、カノニカルURLなど、SEOに関するベストプラクティスを適用。検索エンジンからの可視性を最大化する設計を行いました。
-
パフォーマンス最適化: 画像の最適化、CSSとJSの効率的な読み込み、キャッシング戦略など、ウェブパフォーマンスに関する様々な側面を改善しました。
Claude Codeは単に私の指示に従うだけでなく、最適なアーキテクチャの決定や実装の詳細に関する提案も積極的に行いました。例えば、国際化の実装方法では、ルートパラメータを使用したアプローチの利点と欠点を分析し、最も効率的なソリューションを提案してくれました。
// Claude Codeが実装したロケール管理の例
export const LOCALES = ["ja", "en"] as const;
export type Locale = (typeof LOCALES)[number];
// コンテンツのロケール化
export const content: Record<Locale, LocalizedContent> = {
en: {
title: "Welcome to Pluie Lab",
greeting: "Hello, welcome to Pluie Lab!",
subheading: "Creating Exciting Web Apps is My Greatest Joy",
// その他の英語翻訳...
},
ja: {
title: "Pluie Labへようこそ",
greeting: "こんにちは、Pluie Labへようこそ!",
subheading: "ワクワクするWebアプリを作るのが何よりも楽しい",
// その他の日本語翻訳...
},
};
// ロケールに基づいたメッセージ取得
export function getMessage(locale: Locale): LocalizedContent {
return content[locale] || content[defaultLocale];
}
// ロケールの検証
export const validateLocale = (locale: string): locale is Locale => {
return LOCALES.includes(locale as Locale);
};
OpenAI
画像関連の作業やUI設計では、OpenAIの様々なツールを活用しました:
-
OG画像のデザインアイデア生成: ソーシャルメディア共有用の魅力的なOG画像のデザインコンセプトを生成。カテゴリや言語に応じた動的デザインのバリエーションも提案しました。
-
アイコンやビジュアル要素の作成: サイトのロゴやアイコン、装飾的な要素など、視覚的アイデンティティを形成する要素をAIで生成しました。
-
UIデザインの提案: ユーザーインターフェースのレイアウト、色彩設計、タイポグラフィなど、デザイン面での提案を得ました。特にモバイルレスポンシブデザインの最適化には大きく貢献しました。
-
配色と視覚的一貫性: サイト全体の統一感のある配色スキームや、視覚的階層構造のデザイン提案を行いました。
アーキテクチャと実装の詳細
MDXコンテンツ管理
コンテンツはMDXファイルとして管理され、言語ごとにディレクトリが分けられています:
contents/
├── en/
│ ├── blogs/
│ │ └── *.mdx
│ └── ideas/
│ └── *.mdx
└── ja/
├── blogs/
│ └── *.mdx
└── ideas/
└── *.mdx
各MDXファイルにはフロントマターがあり、タイトル、説明、タグ、カテゴリなどのメタデータを含みます。
静的サイト生成(SSG)
パフォーマンスと検索エンジン最適化のために、このサイトはビルド時に静的HTMLを生成するSSGを活用しています。HonoXのssgParams
を使用して、各ルートのビルド時にHTMLを生成します。
// SSGを使用したルートの例
export default createRoute(
ssgParams(() => {
// ビルド時に生成するパスのパラメータを返す
return LOCALES.map((locale) => ({
locale,
}));
}),
(c) => {
const locale = c.req.param("locale");
// コンテンツの読み込みと処理
// SEO用のpropsを用意
const seo = createSeoProps(
locale,
{
description: localizedContent.description,
keywords: localizedContent.keywords,
ogImage: `/${locale}/blogs/og.webp`,
},
currentPath
);
return c.render(
<Layout locale={locale}>
<HomePage content={content} />
</Layout>,
seo
);
}
);
動的OG画像生成
Vercel OGを使用して、各ページに合わせた動的なOG画像を生成しています。これにより、SNSでシェアされた際に視覚的に魅力的なプレビューを表示できます。
OG画像の生成は特別なルートファイルで行われており、その命名規則として.webp.tsx
という拡張子を使用しています。これはビルド時にVercel OGが画像を生成し、その後WebP形式に変換するためのものです。
// OG画像生成の例(/app/routes/[locale]/blogs/[slug]/og.webp.tsx)
import { createRoute } from "honox/factory";
import { ImageResponse } from "@vercel/og";
import { getBlogBySlug } from "../../../../utils/blog";
import { OgImageLayout } from "../../../../utils/og";
// ブログ記事のOG画像を生成するルート
export default createRoute(async (c) => {
const { slug } = c.req.param();
const locale = c.req.param('locale');
// コンテンツデータの読み込み
const blog = await getBlogBySlug(slug, locale);
if (!blog) {
return c.notFound();
}
// IMPORTANT: WebP形式は直接サポートされていないため、PNGで生成後に変換
// Vercel OGを使用して画像を生成
return new ImageResponse(
// ReactコンポーネントをJSXで記述
<OgImageLayout
title={blog.title}
category={blog.category}
locale={locale}
type="blog"
// カスタムフォントや追加のメタデータも設定可能
/>,
{
width: 1200, // OG画像の標準サイズ
height: 630,
// 必要に応じてフォントやその他のオプションを設定
fonts: [
{
name: 'NotoSansJP',
data: await fetch(new URL('/public/fonts/NotoSansJP/NotoSansJP-Regular.ttf', import.meta.url)).then(res => res.arrayBuffer()),
weight: 400,
style: 'normal',
},
// 日本語太字フォントも読み込み
{
name: 'NotoSansJP',
data: await fetch(new URL('/public/fonts/NotoSansJP/NotoSansJP-Bold.ttf', import.meta.url)).then(res => res.arrayBuffer()),
weight: 700,
style: 'normal',
},
],
}
);
});
上記のコードでは、各ブログ記事に対して、そのタイトル、カテゴリ、言語などのメタデータを利用してカスタムOG画像を生成しています。これにより、SNSでシェアされた際にコンテンツの内容が視覚的に伝わりやすくなります。
また、Vercel OGの重要な特徴として、すべてのレンダリングがサーバーサイドで行われ、実際のブラウザDOMを使用せずにReactコンポーネントからPNG画像を生成している点が挙げられます。この方法により、クライアントサイドのリソースに依存せず、高品質な画像を効率的に提供できます。
生成されたOG画像は、ビルドプロセス中に自動的にWebP形式に変換され、ファイルサイズの最適化が行われます。これはscripts/convert-webp.js
スクリプトによって処理されています。
国際化
このサイトは日本語と英語の両方をサポートしています。ルートパラメータ[locale]
を使用して言語を識別し、それに基づいて適切なコンテンツを表示する包括的な国際化システムを構築しました。
国際化の実装には主に以下の要素が含まれています:
-
ルートベースの言語切り替え: すべてのURLは
/ja/...
または/en/...
のように言語識別子で始まります。これにより、サイト内のどのページでも言語を切り替えることが容易になります。 -
翻訳リソース管理: すべての翻訳テキストは中央の翻訳ファイルで管理され、型安全性が確保されています。
-
コンテンツの言語別整理: MDXコンテンツは言語ごとにディレクトリで分けられ、同じスラッグで異なる言語のコンテンツにアクセスできます。
-
言語切り替えコンポーネント: ユーザーが現在のページを維持したまま言語を切り替えられるコンポーネントを実装しています。
-
日付と時刻のローカライズ: 各言語に適した日付と時刻の表示形式を使用しています。
// ロケールの定義と型安全な管理
export const LOCALES = ["ja", "en"] as const;
export type Locale = (typeof LOCALES)[number];
// デフォルトロケールの設定
export const defaultLocale = "ja";
// ロケールに基づいたメッセージ取得(フォールバックメカニズム付き)
export function getMessage(locale: Locale): LocalizedContent {
return content[locale] || content[defaultLocale];
}
// ロケールの検証
export function assertValidLocale(locale: string): asserts locale is Locale {
if (!validateLocale(locale)) {
throw new LocaleValidationError(
`Invalid locale: ${locale}. Must be one of: ${LOCALES.join(", ")}.`
);
}
}
// 日付のフォーマット関数
export function formatDate(
locale: Locale,
date: string | Date,
options: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "long",
day: "numeric",
}
): string {
const dateObj = typeof date === "string" ? new Date(date) : date;
return dateObj.toLocaleDateString(getDateLocale(locale), options);
}
// 言語切り替えコンポーネントの例
export function LanguageSwitcher({
currentLocale,
currentPath
}: {
currentLocale: Locale;
currentPath: string
}) {
// 現在のロケールからターゲットロケールを取得
const targetLocale = currentLocale === "ja" ? "en" : "ja";
// 現在のパスからロケール部分を置き換えて新しいパスを作成
const newPath = currentPath.replace(`/${currentLocale}`, `/${targetLocale}`);
// 言語表示名を取得
const localizedContent = getMessage(currentLocale);
return (
<a href={newPath} className="language-switcher">
{localizedContent.languageSwitcher}
</a>
);
}
この国際化システムにより、サイト全体を通じて一貫した言語体験を提供し、ユーザーが好みの言語でコンテンツにアクセスできるようになっています。また、各言語バージョンのページには適切なhreflang
メタタグとカノニカルURLが設定されており、検索エンジンが最適なコンテンツを提供できるようにしています。
デプロイメントとホスティング
サイトはCloudflare Workersにデプロイされており、グローバルCDNネットワーク上で高速に配信されています。Jamstackアーキテクチャの利点を最大限に活かすため、複数のステップからなる洗練されたビルドパイプラインを構築しました。
ビルドプロセスの詳細
ビルドプロセスは以下の手順で実行されます:
-
クライアントサイドアセットのビルド:
- Viteを使用してJavaScriptとCSSをバンドル・最適化
- モダンブラウザ向けのES Modulesと下位互換性のためのレガシーバンドルを生成
- TailwindCSSの最適化(未使用クラスの削除)を実行
- アセットのフィンガープリントとキャッシュ最適化
-
静的HTMLの生成:
- HonoXのSSG機能を使用して全ルートをプリレンダリング
- ロケール、ブログ記事、アイデア、カテゴリ、タグなど、すべての動的ルートを静的ファイルとして生成
- メタデータとSEO情報を含むHTMLの最適化
-
画像の最適化:
- Vercel OGで生成されたPNG形式のOG画像をWebP形式に変換
- カスタムスクリプト(
scripts/convert-webp.js
)による変換プロセスの自動化 - ファイルサイズの最適化とブラウザ互換性の確保
-
アイコンとファビコンの生成:
- SVGソースからの複数サイズのアイコン生成
- WebP形式への変換とサイズ最適化
- マニフェストファイルとファビコンの自動生成
-
デプロイ前の最終チェック:
- TypeScript型チェックによるエラー検証
- ESLintによるコードスタイルとエラーチェック
- ビルド成果物の整合性検証
-
Cloudflare Workersへのデプロイ:
- Wranglerを使用したデプロイ処理
- グローバルCDNへの静的アセットの配布
- ワーカースクリプトと設定のアップロード
package.jsonのビルドスクリプト
プロジェクトのpackage.json
には、これらのプロセスを自動化するためのスクリプトが定義されています:
"scripts": {
"dev": "vite",
"build": "vite build --mode client && vite build && node scripts/convert-webp.js",
"format": "prettier --write . --ignore-path .gitignore",
"typecheck": "tsc --noEmit",
"claude": "claude",
"convert-webp": "node scripts/convert-webp.js",
"generate-icons": "node scripts/generate-icons.js",
"lint": "eslint . --max-warnings 0",
"lint:fix": "eslint . --fix --max-warnings 0",
"check": "npm run typecheck && npm run lint"
}
Cloudflare Workersの設定
Cloudflare Workersの設定はwrangler.jsonc
ファイルで管理されており、キャッシュルール、環境変数、ルーティング設定などが含まれています。以下は設定ファイルの例です:
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "homepage",
"compatibility_date": "2025-05-10",
"compatibility_flags": ["nodejs_compat"],
"assets": {
"directory": "./dist"
}
}
このデプロイメント構成により、高速なページロード、効率的なリソース管理、グローバルなコンテンツ配信が実現されています。また、Cloudflare Workersのサーバーレス環境は、スケーラビリティとコスト効率の面でも優れた選択肢となっています。
AIパワード開発の学びと洞察
AIを活用した開発プロセスは非常に実り多いものであり、多くの貴重な学びと洞察をもたらしました。これらの経験から得られた主なポイントを以下に詳しく紹介します:
1. 開発プロセスの変革
-
プロトタイピングの劇的な加速: AIのサポートにより、初期設計からプロトタイピングまでのプロセスが従来の方法と比較して5〜10倍速くなりました。特に、一般的なコンポーネントやユーティリティの実装においては、AIが提案するコードをベースに素早くイテレーションを重ねることができました。
-
イテレーションサイクルの短縮: 「アイデア → 実装 → テスト → 改善」のサイクルが大幅に短縮され、迅速なフィードバックループが実現しました。これにより、より多くの実験と改良が可能になりました。
-
複雑な実装の障壁低下: TypeScriptの高度な型システムやSSGの設定など、複雑な実装が必要な部分でもAIのガイダンスにより進めることができ、技術的な障壁が低くなりました。
2. 技術的な品質と最新性
-
最新のプラクティスの自動取り込み: AIは常に最新の開発プラクティスと設計パターンを提案してくれるため、モダンな実装手法を自然に学び、取り入れることができました。
-
コードの品質と一貫性: AIが提案するコードは一般的に高品質で一貫性があり、プロジェクト全体を通して統一された設計原則が維持されました。
-
エラーと問題の早期発見: AIは潜在的な問題やバグを開発の早い段階で指摘してくれるため、後になって発見される深刻な問題を未然に防ぐことができました。
3. 開発者体験の質的向上
-
ボイラープレートコードの削減: 繰り返しの多いボイラープレートコードの作成をAIに任せることで、より創造的で価値の高い作業に集中できました。
-
学習曲線の緩和: 新しい技術やライブラリの学習曲線がAIのサポートにより緩和され、短時間で新しいツールや手法を習得することができました。
-
意思決定プロセスの改善: AIが複数の選択肢と各選択肢のトレードオフを提示してくれるため、より情報に基づいた意思決定が可能になりました。
4. 人間とAIの協働モデル
-
バランスの取れた役割分担: AIは実装の詳細を担当し、人間は創造的な方向性や最終判断を行うという効果的な役割分担が自然に確立されました。
-
AIリテラシーの向上: AIとの協働を通じて、効果的なプロンプト作成や結果の評価など、AIツールを最大限に活用するためのスキルが向上しました。
-
人間の強みの再認識: AIと協働することで、人間特有の創造性、直感、文脈理解、審美眼などの価値がより明確になりました。
5. 課題と改善点
-
コンテキスト管理の重要性: AIとの効果的な協働には、プロジェクトのコンテキストを適切に共有し維持することが重要であることが明らかになりました。
-
AIの限界への対応: AIが苦手とする特定の問題や、誤った方向に進むケースへの対処方法を学ぶことができました。
-
ワークフローの最適化: AIとの効率的な協働のためには、従来の開発ワークフローを再考し、新しいツールやプロセスを取り入れる必要があることが分かりました。
まとめと今後の展望
このプロジェクトは、AIを活用した開発が現代のウェブ開発においていかに革命的であるかを実証しています。Claude CodeとOpenAIのツールを組み合わせることで、HonoX、TypeScript、MDX、TailwindCSSなどの最新技術スタックを活用した高性能で保守性の高いウェブサイトを短期間で構築することができました。
この経験から、AIは単なる「コード生成ツール」ではなく、開発プロセス全体を変革する真のパートナーとなり得ることが明らかになりました。人間の創造性とAIの効率性を組み合わせることで、これまで以上に複雑で洗練されたソフトウェアプロジェクトが実現可能になっています。
今後のウェブ開発において、AIを活用したアプローチはさらに進化し、標準的な開発手法となっていくでしょう。このプロジェクトはその可能性の一端を示したに過ぎず、AIと人間の創造的協働の新時代の始まりを象徴しています。
開発者として、これらのツールを使いこなし、AIとの効果的な協働方法を学ぶことは、今後ますます重要なスキルとなっていくでしょう。このプロジェクトの経験が、皆さんのAIを活用した開発の旅の参考になれば幸いです。