From 53d22ab7f57b6f0722e115946b1ab1d9d2af54a5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 5 Mar 2026 01:10:17 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20Next.js=20/=20SPA=20=E6=8E=A8=E5=A5=A8?= =?UTF-8?q?=E3=83=A9=E3=82=A4=E3=83=96=E3=83=A9=E3=83=AA=E3=82=92=E6=8B=A1?= =?UTF-8?q?=E5=85=85=E3=83=BB=E7=B5=B1=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Next.js セットアップガイド (web-app-nextjs.md) - Zod セクションを追加(スキーマ定義・API バリデーション・Supabase 型との組み合わせ) - @t3-oss/env-nextjs セクションを追加(環境変数の型安全化・ビルド時検知) - react-hook-form + @hookform/resolvers セクションを追加(Zod 統合パターン) - @vercel/analytics + @vercel/speed-insights セクションを追加(layout.tsx に2行追加) ## SPA (React + Vite) セットアップガイド (spa-react-vite.md) - ESLint + Prettier を Biome に置き換え(Next.js ガイドと統一) - noConsole ルールを含む biome.json テンプレートを追加 - lint-staged 設定を Biome 用に更新 ## ツールカタログ (tool-catalog.md) - Next.js 依存リストに @vercel/analytics, @vercel/speed-insights, @t3-oss/env-nextjs, react-hook-form を追加 - SPA (React + Vite) 依存リストに Biome を追加 Co-Authored-By: Claude Sonnet 4.6 --- docs/setup/spa-react-vite.md | 77 +++++++++++++--- docs/setup/web-app-nextjs.md | 170 +++++++++++++++++++++++++++++++++++ docs/tool-catalog.md | 16 ++-- 3 files changed, 242 insertions(+), 21 deletions(-) diff --git a/docs/setup/spa-react-vite.md b/docs/setup/spa-react-vite.md index 1232a3e8..d63745b1 100644 --- a/docs/setup/spa-react-vite.md +++ b/docs/setup/spa-react-vite.md @@ -42,24 +42,74 @@ export default defineConfig({ } ``` -## ESLint + Prettier +## Biome(Lint + Format) + +ESLint + Prettier の代わりに **Biome を推奨**する。1 ツールで lint + format を高速に実行できる。 ```bash -npm install -D eslint @eslint/js typescript-eslint eslint-plugin-react-hooks eslint-plugin-react-refresh eslint-config-prettier -npm install -D prettier +npm install -D --save-exact @biomejs/biome +npx @biomejs/biome init ``` -**スクリプト**: +`biome.json`: + +```json +{ + "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "organizeImports": { + "enabled": true + }, + "formatter": { + "indentStyle": "space", + "indentWidth": 2, + "lineWidth": 100 + }, + "linter": { + "rules": { + "recommended": true, + "suspicious": { + "noConsole": { + "level": "error", + "options": { + "allow": ["error", "warn"] + } + } + } + } + }, + "files": { + "ignore": ["dist", "node_modules", "coverage"] + } +} +``` + +**推奨スクリプト**: ```json { - "lint": "eslint .", - "lint:fix": "eslint . --fix", - "format": "prettier --write .", - "format:check": "prettier --check ." + "check": "biome check .", + "check:fix": "biome check --write .", + "lint": "biome lint .", + "format": "biome format .", + "format:check": "biome format ." } ``` +> `biome check` は lint + format + import 整理を一括実行する。CI では `biome check .` を使う。 + +### 既存の ESLint + Prettier からの移行 + +```bash +npx @biomejs/biome migrate eslint +npx @biomejs/biome migrate prettier +``` + +移行後、不要になったパッケージと設定ファイルを削除する: + +- `eslint`, `eslint-config-*`, `eslint-plugin-*`, `@eslint/*`, `typescript-eslint` +- `prettier`, `eslint-config-prettier` +- `eslint.config.mjs` / `.eslintrc.*` / `.prettierrc*` + ## CI/CD ワークフロー **参考**: `/setup-ci` コマンドで雛形を生成可能。 @@ -74,11 +124,12 @@ Lint → Format Check → Test (with coverage) → Build ## lint-staged -```json -{ - "*.{ts,tsx}": ["eslint --fix", "prettier --write"], - "*.{json,md,yml}": ["prettier --write"] -} +```js +// lint-staged.config.js +module.exports = { + '*.{ts,tsx,js,jsx,json,css}': ['biome check --write --no-errors-on-unmatched'], + '*.{md,yml,yaml}': ['biome format --write --no-errors-on-unmatched'], +}; ``` ## CLAUDE.md diff --git a/docs/setup/web-app-nextjs.md b/docs/setup/web-app-nextjs.md index 5fac0b7c..5593f284 100644 --- a/docs/setup/web-app-nextjs.md +++ b/docs/setup/web-app-nextjs.md @@ -128,6 +128,144 @@ npx @biomejs/biome migrate prettier - `prettier`, `eslint-config-prettier` - `eslint.config.mjs` / `.eslintrc.*` / `.prettierrc*` +## バリデーション & 型安全 + +### Zod(スキーマバリデーション) + +```bash +npm install zod +``` + +API レスポンス・フォーム入力・環境変数の検証を一元化する。Supabase の型と組み合わせて使う。 + +**基本的な使い方**: + +```typescript +import { z } from 'zod'; + +// スキーマ定義 +const UserSchema = z.object({ + id: z.string().uuid(), + email: z.string().email(), + name: z.string().min(1).max(100), +}); + +type User = z.infer; + +// API Route でのバリデーション +export async function POST(req: Request) { + const body = await req.json(); + const result = UserSchema.safeParse(body); + + if (!result.success) { + return Response.json({ errors: result.error.flatten() }, { status: 400 }); + } + + // result.data は型安全 + const user = result.data; +} +``` + +**Supabase の型と組み合わせる**: + +```typescript +import { z } from 'zod'; +import type { Database } from '@/lib/supabase/types'; + +type Row = Database['public']['Tables']['users']['Row']; + +// DB の型から Zod スキーマを構築 +const UserInsertSchema = z.object({ + email: z.string().email(), + name: z.string().min(1), +}) satisfies z.ZodType>; +``` + +### @t3-oss/env-nextjs(環境変数の型安全化) + +```bash +npm install @t3-oss/env-nextjs zod +``` + +`.env` の未設定・型ミスをビルド時に検知する。`process.env.XXX` の生アクセスを禁止し、型付き `env` オブジェクト経由に統一する。 + +**`src/env.ts`**: + +```typescript +import { createEnv } from '@t3-oss/env-nextjs'; +import { z } from 'zod'; + +export const env = createEnv({ + server: { + SUPABASE_SERVICE_ROLE_KEY: z.string().min(1), + SENTRY_AUTH_TOKEN: z.string().optional(), + }, + client: { + NEXT_PUBLIC_SUPABASE_URL: z.string().url(), + NEXT_PUBLIC_SUPABASE_ANON_KEY: z.string().min(1), + NEXT_PUBLIC_SENTRY_DSN: z.string().url().optional(), + }, + runtimeEnv: { + SUPABASE_SERVICE_ROLE_KEY: process.env.SUPABASE_SERVICE_ROLE_KEY, + SENTRY_AUTH_TOKEN: process.env.SENTRY_AUTH_TOKEN, + NEXT_PUBLIC_SUPABASE_URL: process.env.NEXT_PUBLIC_SUPABASE_URL, + NEXT_PUBLIC_SUPABASE_ANON_KEY: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, + NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN, + }, +}); +``` + +> `next.config.ts` で `import './src/env'` を追加するとビルド時に検証が走る。 + +## フォーム管理(react-hook-form + Zod) + +```bash +npm install react-hook-form @hookform/resolvers zod +``` + +フォームバリデーションを Zod スキーマで統一し、型安全なフォームを実装する。 + +**基本的な使い方**: + +```typescript +'use client'; + +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { z } from 'zod'; + +const schema = z.object({ + email: z.string().email('有効なメールアドレスを入力してください'), + password: z.string().min(8, '8文字以上で入力してください'), +}); + +type FormValues = z.infer; + +export function LoginForm() { + const { + register, + handleSubmit, + formState: { errors, isSubmitting }, + } = useForm({ resolver: zodResolver(schema) }); + + const onSubmit = async (data: FormValues) => { + // data は型安全 + }; + + return ( +
+ + {errors.email &&

{errors.email.message}

} + + {errors.password &&

{errors.password.message}

} + +
+ ); +} +``` + ## Knip(未使用コード検出) 未使用の依存関係・ファイル・export を検出する **Knip を推奨**する。 @@ -358,6 +496,38 @@ export async function GET() { 詳細な設定は [Sentry セットアップガイド](../sentry-setup-guide.md) を参照。 +### @vercel/analytics + @vercel/speed-insights(アナリティクス) + +```bash +npm install @vercel/analytics @vercel/speed-insights +``` + +Vercel デプロイなら追加コスト・設定なしで Core Web Vitals とページビューを収集できる。 + +**`app/layout.tsx` に2行追加するだけ**: + +```typescript +import { Analytics } from '@vercel/analytics/react'; +import { SpeedInsights } from '@vercel/speed-insights/next'; + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + + {children} + + + + + ); +} +``` + +| コンポーネント | 収集データ | +| ------------------- | ------------------------------------------ | +| `` | ページビュー・ユニークビジター・リファラー | +| `` | LCP / FID / CLS 等の Core Web Vitals | + ### ロギング設計指針 | ツール | 用途 | 環境 | diff --git a/docs/tool-catalog.md b/docs/tool-catalog.md index 1a57e7fe..38e00803 100644 --- a/docs/tool-catalog.md +++ b/docs/tool-catalog.md @@ -126,14 +126,14 @@ Layer 1: ベースイメージ (ghcr.io/keito4/config-base) ### 4.2 主要な追加依存(注目ポイント) -| 種別 | 注目する依存 | -| --------------------- | ------------------------------------------------------------------------------------------------------------------ | -| 共通基盤 (config) | semantic-release, jest-junit, bats | -| Web アプリ (Next.js) | `@supabase/ssr`, `@vercel/logger`, `@sentry/nextjs`, Tailwind CSS 4, Zod 4, Testing Library, Playwright, LangSmith | -| npm ライブラリ (CLI) | `@notionhq/client`, commander, ts-jest, semantic-release | -| SPA (React + Vite) | `@google/genai`, D3.js, React 19 | -| デスクトップ拡張 (TS) | lint-staged, monorepo (pnpm workspaces) | -| モバイル (Flutter) | Riverpod, Drift (SQLite), Freezed, go_router | +| 種別 | 注目する依存 | +| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 共通基盤 (config) | semantic-release, jest-junit, bats | +| Web アプリ (Next.js) | `@supabase/ssr`, `@vercel/logger`, `@sentry/nextjs`, `@vercel/analytics`, `@vercel/speed-insights`, Zod 4, `@t3-oss/env-nextjs`, react-hook-form, Tailwind CSS 4, Testing Library, Playwright, LangSmith | +| npm ライブラリ (CLI) | `@notionhq/client`, commander, ts-jest, semantic-release | +| SPA (React + Vite) | `@google/genai`, D3.js, React 19, Biome | +| デスクトップ拡張 (TS) | lint-staged, monorepo (pnpm workspaces) | +| モバイル (Flutter) | Riverpod, Drift (SQLite), Freezed, go_router | ## 5. macOS ローカルツール(Brewfile)