---
description: "TanStack Startアプリケーション構築のためのガイドライン"
applyTo: "**/*.ts, **/*.tsx, **/*.js, **/*.jsx, **/*.css, **/*.scss, **/*.json"
---
# TanStack Start + Shadcn/ui 開発ガイド
あなたは、モダンな React パターンを用いた TanStack Start アプリケーションに特化した、エキスパート TypeScript 開発者です。
## 技術スタック
- TypeScript(strict mode)
- TanStack Start(ルーティング & SSR)
- Shadcn/ui(UI コンポーネント)
- Tailwind CSS(スタイリング)
- Zod(バリデーション)
- TanStack Query(クライアント状態管理)
## コードスタイル規則
- `any`型を使用しない - 常に適切な TypeScript 型を使用する
- クラスコンポーネントより関数コンポーネントを優先する
- 外部データは常に Zod スキーマでバリデーションする
- すべてのルートにエラーと保留中バウンダリを含める
- ARIA 属性でアクセシビリティのベストプラクティスに従う
## コンポーネントパターン
適切な TypeScript インターフェースを持つ関数コンポーネントを使用する:
```typescript
interface ButtonProps {
children: React.ReactNode;
onClick: () => void;
variant?: "primary" | "secondary";
}
export default function Button({ children, onClick, variant = "primary" }: ButtonProps) {
return (
);
}
```
## データフェッチング
ルートローダーの使用場面:
- レンダリングに必要な初期ページデータ
- SSR 要件
- SEO クリティカルなデータ
React Query の使用場面:
- 頻繁に更新されるデータ
- オプション/二次データ
- 楽観的更新を伴うクライアントミューテーション
```typescript
// ルートローダー
export const Route = createFileRoute("/users")({
loader: async () => {
const users = await fetchUsers();
return { users: userListSchema.parse(users) };
},
component: UserList,
});
// React Query
const { data: stats } = useQuery({
queryKey: ["user-stats", userId],
queryFn: () => fetchUserStats(userId),
refetchInterval: 30000,
});
```
## Zod バリデーション
外部データは常にバリデーションする。`src/lib/schemas.ts`でスキーマを定義する:
```typescript
export const userSchema = z.object({
id: z.string(),
name: z.string().min(1).max(100),
email: z.string().email().optional(),
role: z.enum(["admin", "user"]).default("user"),
});
export type User = z.infer;
// セーフパース
const result = userSchema.safeParse(data);
if (!result.success) {
console.error("Validation failed:", result.error.format());
return null;
}
```
## ルート
`src/routes/`でファイルベースルーティングを使用してルートを構成する。常にエラーと保留中バウンダリを含める:
```typescript
export const Route = createFileRoute("/users/$id")({
loader: async ({ params }) => {
const user = await fetchUser(params.id);
return { user: userSchema.parse(user) };
},
component: UserDetail,
errorBoundary: ({ error }) => Error: {error.message}
,
pendingBoundary: () => (
),
});
```
## UI コンポーネント
カスタムコンポーネントよりも Shadcn/ui コンポーネントを常に優先する:
```typescript
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
User Details
;
```
レスポンシブデザインで Tailwind をスタイリングに使用する:
```typescript
```
## アクセシビリティ
セマンティック HTML を最優先とする。セマンティック相当物が存在しない場合のみ ARIA を追加する:
```typescript
// ✅ 良い: 最小限のARIAを持つセマンティックHTML
// ✅ 良い: 必要な時のみARIA(動的状態の場合)
// ✅ 良い: セマンティックフォーム要素
{errors.email && (
{errors.email}
)}
```
## ファイル構成
```
src/
├── components/ui/ # Shadcn/uiコンポーネント
├── lib/schemas.ts # Zodスキーマ
├── routes/ # ファイルベースルート
└── routes/api/ # サーバールート(.ts)
```
## インポート標準
すべての内部インポートに`@/`エイリアスを使用する:
```typescript
// ✅ 良い
import { Button } from "@/components/ui/button";
import { userSchema } from "@/lib/schemas";
// ❌ 悪い
import { Button } from "../components/ui/button";
```
## コンポーネントの追加
必要に応じて Shadcn コンポーネントをインストールする:
```bash
npx shadcn@latest add button card input dialog
```
## 共通パターン
- 外部データは常に Zod でバリデーションする
- 初期データにはルートローダー、更新には React Query を使用する
- すべてのルートにエラー/保留中バウンダリを含める
- カスタム UI よりも Shadcn コンポーネントを優先する
- `@/`インポートを一貫して使用する
- アクセシビリティのベストプラクティスに従う