Kuroco フロントエンド統合パターン
Kuroco HeadlessCMSとVite/Nuxt.js/Next.jsなどのフロントエンドフレームワークの統合パターン、および公開先の決定とデプロイ。
ドキュメント参照: /kuroco-docs スキルを使用してKuroco公式ドキュメントを検索・参照できます。
チュートリアル: フロントエンドのデプロイ手順やサンプルサイトの構築方法は Kurocoサンプルサイトチュートリアル を参照してください。
目次
- 公開先の決定
- サポートフレームワーク
- 環境設定
- API設定の前提条件
- 認証実装
- Nuxt.js統合 → 詳細は references/nuxt.md
- Next.js統合 → 詳細は references/nextjs.md
- KurocoFront統合 → 詳細は references/kuroco-front.md
公開先の決定
既定はKurocoFront。 ユーザーからの指定がない限り、質問せずKurocoFrontで進める。
| 状況 | 動作 |
|---|---|
| SSR / ISR が必要 | KurocoFrontは静的コンテンツホスティング(CDN)でサーバー実行ができないため動かない。Vercel等を提案する。ただし提案の前に下の「SSR/ISRが本当に必要か」で切り分ける |
| 新規構築(指定なし) | KurocoFrontで進める。公開先を選ばせる質問はしない |
| ユーザーがVercel / Netlify / Codex Sites / v0 / Lovable などを指定 | その公開先で進める。実装前に references/other-hosting.md の確認軸を埋める。Codex Sitesの場合は下の実行環境の制約を先に伝える |
| Codexで実行中の新規構築 | KurocoFrontを既定としつつ、Codex Sitesという選択肢があることを一度だけ提示してよい。指定が返らなければKurocoFrontで進める |
| ChatGPTの通常チャットで実行中 | Codex Sitesは提示しない(下の実行環境の制約)。KurocoFrontで進める |
| 既存サイトの変更 | 現在の公開先を維持する。明示的な移行依頼があったときだけ選び直す |
実行環境の制約(Codex Sites)
Codex Sites(chatgpt.site)は ChatGPT の通常チャットからは操作できない。
サイトの作成・更新は Work モード(ChatGPTのワークスペース)または Codex での実行が前提になる。
通常チャットで Kuroco の構築を進めていて Codex Sites を使いたい場合は、この制約を伝えたうえで Work モードか Codex で作業することを推奨する。切り替えないなら KurocoFront で進める。
SSR/ISRが本当に必要かの切り分け
「SSR/ISRが要る」という要望の動機はたいていSEOかOGPで、その多くはSSGで足りる。 安易にVercelへ出すと運用先が分散するため、動機で判定する。
| 動機 | 結論 |
|---|---|
| 検索流入・各ページのOGP | SSG(KurocoFront) で足りる。SPAは各ページ個別のOGPを持てないのでSSGにする |
| ページ数が多くSSGのビルドが現実的に回らない/更新頻度が高くビルド待ちが許容できない | SSR / ISR → Vercel等。KurocoFrontでは実現できない |
| 会員制・認証必須の画面 | SPA(KurocoFront)。SSR/ISRにしても利点が出ない(下記) |
| 公開ページ(OGP要)と会員ページが混在 | 公開側SSG+会員側SPAの混在構成。公開先はKurocoFrontのままでよい |
会員制サイトをSSR/ISRにしない理由: サーバー側fetchにはブラウザのセッションCookieが乗らないため、 認証付きコンテンツはどのみちクライアント側fetchで取ることになる。SSRにしてもサーバーレンダリングの 利点(初期表示のHTMLに中身が入る・OGP)が認証領域では得られず、構成だけが複雑になる。 会員制はSPAに寄せて認証をクライアント側に閉じる方が分離が効く。
フレームワーク・認証・CORS・XSS対策の実装パターンは公開先によらず共通(以下のセクション)。 公開先ごとに違うのは設定と公開手順だけなので、選んだ側のreferenceだけを読む。
- KurocoFront: references/kuroco-front.md
- それ以外: references/other-hosting.md
サポートフレームワーク
| フレームワーク | バージョン | 推奨ユースケース | KurocoFrontでの配信 |
|---|---|---|---|
| Vite + Vue 3 | Vue 3系 | シンプルなSPA(SEO不要のアプリ・ツール類)。最小構成で認証が素直 | vite build → dist/ をそのまま |
| Nuxt.js 3.x | Vue 3系 | SEOが必要なコンテンツサイト(SSGで静的HTML生成、推奨) | nuxt generate(SSG)。nuxt build のSSRは不可 |
| Nuxt.js 2.x | Vue 2系 | 既存プロジェクト | nuxt generate(SSG) |
| Next.js 13+ | React (App Router) | 新規Reactプロジェクト | output: 'export' の静的エクスポートのみ(下記の制約) |
| Next.js (Pages) | React (Pages Router) | 既存Reactプロジェクト | output: 'export' の静的エクスポートのみ |
KurocoFrontは静的コンテンツホスティング(CDN)なので、サーバー実行を伴う構成は動かない。 SSR / ISR が必要な場合は公開先の決定へ戻る。
Next.js を KurocoFront で配信する場合の制約
next.config.js に output: 'export' を設定し、out/ を配信する。
Next.js 16 時点で静的エクスポートでは以下が使えない(公式ドキュメント)。
| 使えない機能 | Kuroco構成での対処 |
|---|---|
cookies() |
認証はクライアント側で行う。Cookie認証も動的アクセストークンもブラウザから直接Kuroco APIを呼ぶ |
| Server Actions | フォーム送信はクライアントからKuroco APIへ直接POSTする |
next.config の Rewrites / Redirects / Headers |
kuroco_front.json の rewrites / redirects で設定する(references/kuroco-front.md) |
| ISR、Draft Mode、Intercepting Routes、Proxy | 代替なし。必要ならVercel等に公開先を変える |
| Request に依存する Route Handler | 静的化するなら export const dynamic = 'force-static'(GETのみ)。動的な読み取りが要るならKuroco API側で処理する |
dynamicParams: true / generateStaticParams() なしの動的ルート |
ビルド時に generateStaticParams() で全パスを列挙する。列挙できない量ならSPAに寄せる |
next/image のデフォルトloader |
カスタムloaderを指定するか、Kuroco Filesの画像URLを直接使う |
環境設定
環境変数
# .env.local
NUXT_PUBLIC_API_BASE=https://example.g.kuroco.app
NEXT_PUBLIC_API_BASE=https://example.g.kuroco.app
API_ID=1
プロジェクト構成
Nuxt.js:
pages/
├── news/
│ ├── index.vue # 一覧
│ └── [slug].vue # 詳細 (Nuxt3)
├── login.vue
└── profile.vue
composables/
├── useAuth.ts
└── useApi.ts
Next.js (App Router):
app/
├── news/
│ ├── page.tsx # 一覧
│ └── [slug]/page.tsx
├── login/page.tsx
└── profile/page.tsx
lib/
├── auth.ts
└── api.ts
API設定の前提条件
1. セキュリティ設定(Cookie認証)
- 管理画面 → API → セキュリティ → Cookieを選択
- フロントエンドとAPIドメインをサブドメイン違いに設定
- 例:
www.example.comとapi.example.com
- 例:
2. CORS設定
管理画面: [API] → [セキュリティ] → [CORS設定]
CORS_ALLOW_ORIGINS:
- http://localhost:3000
- https://your-frontend-domain.com
CORS_ALLOW_CREDENTIALS: true
CORS_ALLOW_METHODS:
- GET
- POST
認証実装
ログイン
interface LoginResponse {
grant_token: string
status: number
member_id: number
}
async function login(email: string, password: string): Promise<LoginResponse> {
const response = await fetch(
'https://example.g.kuroco.app/rcms-api/1/login',
{
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
}
)
if (!response.ok) {
const error = await response.json()
throw new Error(error.errors?.[0]?.message || 'ログインに失敗しました')
}
return response.json()
}
ログアウト
async function logout(): Promise<void> {
await fetch('https://example.g.kuroco.app/rcms-api/1/logout', {
method: 'POST',
credentials: 'include'
})
}
ログイン状態の確認
async function checkAuth(): Promise<ProfileResponse | null> {
try {
const response = await fetch(
'https://example.g.kuroco.app/rcms-api/1/profile',
{ credentials: 'include' }
)
if (!response.ok) return null
return response.json()
} catch {
return null
}
}
会員登録
async function signup(memberData: SignupData): Promise<void> {
const response = await fetch(
'https://example.g.kuroco.app/rcms-api/1/member/insert',
{
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(memberData)
}
)
if (!response.ok) {
const error = await response.json()
throw new Error(error.errors?.[0]?.message || '登録に失敗しました')
}
}
Nuxt.js統合
詳細な実装例: references/nuxt.md を参照
クイックスタート(Nuxt 3):
// composables/useKurocoApi.ts
export function useKurocoApi() {
const config = useRuntimeConfig()
async function get<T>(endpoint: string, params?: Record<string, any>): Promise<T> {
const query = params ? `?${new URLSearchParams(params)}` : ''
return await $fetch<T>(
`${config.public.apiBase}/rcms-api/${config.public.apiId}/${endpoint}${query}`,
{ credentials: 'include' }
)
}
return { get }
}
Next.js統合
詳細な実装例: references/nextjs.md を参照
クイックスタート(App Router):
// lib/api.ts
export async function apiGet<T>(endpoint: string): Promise<T> {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_BASE}/rcms-api/1/${endpoint}`,
{ credentials: 'include', cache: 'no-store' }
)
if (!response.ok) throw new Error(`API Error: ${response.status}`)
return response.json()
}
KurocoFront統合
KurocoFrontはKurocoが提供するフロントエンドホスティングサービス(静的ホスティング + CDN)。
SPA(History APIでのクライアントルーティング)を配信するなら、kuroco_front.json の
rewrites に {"source": ".*", "destination": "/index.html"} が必須(無いとリロード・URL直打ち・共有リンクが404になる)。
source を絞ると壊れる理由・error_page との関係を含めた推奨設定は
references/kuroco-front.md「SPA配信」にまとめてある。
kuroco_front.json の設定(rewrites / redirects / Basic認証 / IPアドレス制限)、
非公開デフォルト(ユーザーが公開を明示するまで robots.txt の Disallow: / + Basic認証/IP制限をかけてデプロイする既定)、GitHub連携デプロイ、
Admin MCPからの直接デプロイ(files-create_temp_upload_url → kuroco_front-deploy → kuroco_front-history)の
手順と制約は references/kuroco-front.md を参照。
注意事項
サードパーティCookie問題(SPAのCookie認証)
フロントエンドとAPIが別ドメイン(例: www.example.com と {site_key}.g.kuroco.app)の場合、
SafariのITP等によりクロスサイトCookieがブロックされ、Cookie認証が動作しません。回避策は2つ:
回避策1: 同一親ドメインに揃える(Cookie認証を続ける場合)
APIに独自ドメイン(例: api.example.com)を設定し、フロント(www.example.com)と親ドメインを揃えるとCookieがファーストパーティ扱いになります。
設定: 管理画面 [独自ドメイン/TLS証明書] でAPIドメインを登録 → [アカウント設定] でAPIベースURLを更新。
Safariの7日間Cookie上限に注意: 親ドメインを揃えても、SafariはCNAMEクローキング対策により この構成のCookie有効期限を7日に制限します。毎日使うツールでは実質問題ありませんが、 ログイン頻度が低いサイトではSafariユーザーが7日で再ログインになります。
回避策2: 動的アクセストークン認証に切り替える(SPAで確実な方法)
アクセストークンはCookieではなく X-RCMS-API-ACCESS-TOKEN リクエストヘッダーで送るため、
ITP・サードパーティCookie制限の対象外です。長期ログイン保持が必要なSPA・クロスドメイン構成ではこちらを推奨。
- APIセキュリティを「動的アクセストークン」に設定し、
tokenエンドポイント(Login::token)を作成 - ログイン:
login→grant_token取得 →tokenにPOSTしてaccess_token(+refresh_token)取得 - 以降のリクエストに
X-RCMS-API-ACCESS-TOKEN: {access_token}ヘッダーを付与 - 期限切れ時は
refresh_tokenをtokenエンドポイントに送って再発行(access_token_lifespan/refresh_token_lifespanで期間設定)
トークンをlocalStorageに保存する場合はXSS対策(後述のHTMLサニタイズ等)を徹底すること。
開発時(localhost): 開発サーバーのプロキシ(Viteの server.proxy 等)でAPIを同一オリジンに見せると、ブラウザのCookie制限を受けずに開発できます。
HTMLサニタイズ
v-html や dangerouslySetInnerHTML を使用する際はXSSに注意:
import DOMPurify from 'dompurify'
const sanitizedHtml = DOMPurify.sanitize(htmlContent)
関連スキル
/kuroco-api-content- API設計・認証パターン、コンテンツCRUD操作/kuroco-admin-mcp- Admin MCP経由の管理操作
関連ドキュメント
../kuroco-docs/docs/tutorials-frontend-1.md(integrate-kuroco-with-nuxt) - Nuxt.js統合../kuroco-docs/docs/tutorials-auth-member-2.md(integrate-login) - ログイン実装../kuroco-docs/docs/tutorials-auth-member-4.md(signup) - 会員登録../kuroco-docs/docs/tutorials-misc.md(beginners-guide) - ビギナーズガイド../kuroco-docs/docs/tutorials-frontend-1.md(corporate-sample-site-to-ssg) - SSG対応- Kurocoサンプルサイトチュートリアル - サンプルサイトの構築・デプロイ手順