Next.js → Astro 移行時のフォームページ実装戦略
概要
Next.js App Router + Firebase → Astro + CF Pages への移行時のフォーム実装パターン。reCAPTCHA v3、Firebase Cloud Functions、HubSpot 埋め込みをどう置き換えるか。
アーキテクチャ変更
| 要素 | Next.js | Astro |
|---|---|---|
| CAPTCHA | reCAPTCHA v3 | Cloudflare Turnstile |
| バックエンド | Firebase Cloud Functions | CF Pages Functions (/api/*) |
| フォーム送信 | Server Action + Firebase | CF API ルート |
| HubSpot | 埋め込み(SSR時にスキップ) | React Island化 |
実装フロー
1. Turnstile の統合
<!-- Astro コンポーネント -->
<div id="turnstile-container"></div>
<script>
import Turnstile from '@/components/Turnstile.tsx';
</script>
<Turnstile />
2. API ルートの実装
// src/pages/api/submit-form.ts
export async function POST({ request }) {
const formData = await request.json();
// Turnstile 検証
const verifyResponse = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
method: 'POST',
body: JSON.stringify({
secret: import.meta.env.TURNSTILE_SECRET_KEY,
response: formData.captchaToken
})
});
if (!verifyResponse.ok) {
return new Response(JSON.stringify({ error: 'Captcha failed' }), { status: 400 });
}
// メール送信等の処理
return new Response(JSON.stringify({ success: true }));
}
3. HubSpot 埋め込みの React Island化
// React コンポーネント
export default function HubSpotForm() {
useEffect(() => {
if (window.hbspt) {
window.hbspt.forms.create({
region: 'na1',
portalId: '...',
formId: '...',
target: '#hubspot-form'
});
}
}, []);
return <div id="hubspot-form" />;
}
Astro での使用:
<HubSpotForm client:load />
メリット
- CF Pages はサーバーレス、メンテナンス不要
- Turnstile は無料+プライバシー優先
- Astro + React Island で必要な部分のみインタラクティブ
検討点
- Firebase から CF Functions への認証情報移行
- メール送信ロジックの Durable Objects 利用の検討
- ログ保存先の決定(D1 / Firestore など)