Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 64 additions & 13 deletions docs/setup/spa-react-vite.md
Original file line number Diff line number Diff line change
Expand Up @@ -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*`

Comment on lines +107 to +112

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

削除ガイダンスの適用スコープを明記してください

Line 107-112 は ESLint/Prettier 関連ファイルの削除を案内していますが、現状のリポジトリ運用(eslint.config.mjs / .prettierrc / .husky/pre-commit)と衝突します。
この手順が「アプリ側リポジトリ向け」なのか「この config リポジトリにも適用」なのかを明記してください。

🧰 Tools
🪛 LanguageTool

[typographical] ~109-~109: 2つの連続するコンマ
Context: ..., eslint-config-*, eslint-plugin-*, @eslint/*, typescript-eslint - prettier, `es...

(DOUBLE_PUNCTUATION)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/setup/spa-react-vite.md` around lines 107 - 112, 本文が ESLint/Prettier
関連ファイルの削除を案内していますが、リポジトリ運用(例: eslint.config.mjs / .prettierrc /
.husky/pre-commit)がある場合の扱いが不明瞭なので、該当箇所を「この手順はアプリケーション側リポジトリ向けのみ適用」と明記し、設定リポジトリや共有コンフィグを運用している場合は削除しない旨(例示:
eslint.config.mjs, .prettierrc, .husky/pre-commit
は残す/別途移行手順に従う)を追記してください。また「削除対象パッケージ一覧(eslint, eslint-plugin-*, prettier,
eslint-config-prettier, typescript-eslint 等)」を保持しつつ、config
リポジトリに対する例外とその判断基準を短く明示してください。

## CI/CD ワークフロー

**参考**: `/setup-ci` コマンドで雛形を生成可能。
Expand All @@ -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 = {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Make lint-staged sample ESM-compatible

The new snippet uses lint-staged.config.js with module.exports, but React+Vite projects commonly run with "type": "module"; in that setup this file is treated as ESM and throws ReferenceError: module is not defined, so npx lint-staged (and pre-commit hooks) fail immediately. Please either rename the sample file to lint-staged.config.cjs or use an ESM export form for .js.

Useful? React with 👍 / 👎.

'*.{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
Expand Down
170 changes: 170 additions & 0 deletions docs/setup/web-app-nextjs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof UserSchema>;

// 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<Partial<Row>>;
```

### @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<typeof schema>;

export function LoginForm() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<FormValues>({ resolver: zodResolver(schema) });

const onSubmit = async (data: FormValues) => {
// data は型安全
};

return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email')} />
{errors.email && <p>{errors.email.message}</p>}
<input type="password" {...register('password')} />
{errors.password && <p>{errors.password.message}</p>}
<button type="submit" disabled={isSubmitting}>
ログイン
</button>
</form>
);
}
```

## Knip(未使用コード検出)

未使用の依存関係・ファイル・export を検出する **Knip を推奨**する。
Expand Down Expand Up @@ -464,6 +602,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 (
<html lang="ja">
<body>
{children}
<Analytics />
<SpeedInsights />
</body>
</html>
);
}
```

| コンポーネント | 収集データ |
| ------------------- | ------------------------------------------ |
| `<Analytics />` | ページビュー・ユニークビジター・リファラー |
| `<SpeedInsights />` | LCP / FID / CLS 等の Core Web Vitals |

Comment on lines +632 to +636

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n docs/setup/web-app-nextjs.md | sed -n '520,535p'

Repository: keito4/config

Length of output: 692


🌐 Web query:

Core Web Vitals metrics 2024 2025 INP FID replacement

💡 Result:

  • FID → INP switch (Core Web Vitals): Interaction to Next Paint (INP) officially replaced First Input Delay (FID) as the Core Web Vitals “responsiveness” metric on March 12, 2024. (web.dev)
  • What CWV are in 2024–2025: The Core Web Vitals set is LCP + CLS + INP (FID is no longer part of the CWV trio). (web.dev)
  • INP thresholds (field guidance): A common target is “good” INP ≤ 200 ms (75th percentile). (web.dev)
  • Deprecation/removal timeline: Chrome tools/APIs deprecated FID after the March 12, 2024 switch, with a transition deadline of September 9, 2024 for consumers to move off FID to avoid breakage. (web.dev)
  • If you read CrUX / PSI / Lighthouse programmatically: Update from the old experimental INP fields to the stable ones (for example, experimental_interaction_to_next_paintinteraction_to_next_paint in CrUX / PSI APIs). (web.dev)

Citations:


Update Core Web Vitals metrics to current definition

Line 529 references LCP / FID / CLS as Core Web Vitals, but FID (First Input Delay) was officially replaced by INP (Interaction to Next Paint) on March 12, 2024. Update to LCP / INP / CLS to align with the current Core Web Vitals specification.

Reference: https://web.dev/blog/inp-cwv

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/setup/web-app-nextjs.md` around lines 526 - 530, Update the Core Web
Vitals label in the docs: change the `<SpeedInsights />` row’s collected data
text from "LCP / FID / CLS 等の Core Web Vitals" to "LCP / INP / CLS 等の Core Web
Vitals" so the documentation reflects the replacement of FID with INP per the
current spec.

### ロギング設計指針

| ツール | 用途 | 環境 |
Expand Down
16 changes: 8 additions & 8 deletions docs/tool-catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`, `@axe-core/playwright`, jest-axe, `@next/bundle-analyzer`, 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, `@axe-core/playwright`, jest-axe, `@next/bundle-analyzer`, 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)

Expand Down