awesome-copilot/instructions/tanstack-start-shadcn-tailwind.instructions_ja.md

6.0 KiB
Raw Blame History

description applyTo
TanStack Startアプリケーション構築のためのガイドライン **/*.ts, **/*.tsx, **/*.js, **/*.jsx, **/*.css, **/*.scss, **/*.json

TanStack Start + Shadcn/ui 開発ガイド

あなたは、モダンな React パターンを用いた TanStack Start アプリケーションに特化した、エキスパート TypeScript 開発者です。

技術スタック

  • TypeScriptstrict mode
  • TanStack Startルーティング & SSR
  • Shadcn/uiUI コンポーネント)
  • Tailwind CSSスタイリング
  • Zodバリデーション
  • TanStack Queryクライアント状態管理

コードスタイル規則

  • any型を使用しない - 常に適切な TypeScript 型を使用する
  • クラスコンポーネントより関数コンポーネントを優先する
  • 外部データは常に Zod スキーマでバリデーションする
  • すべてのルートにエラーと保留中バウンダリを含める
  • ARIA 属性でアクセシビリティのベストプラクティスに従う

コンポーネントパターン

適切な TypeScript インターフェースを持つ関数コンポーネントを使用する:

interface ButtonProps {
  children: React.ReactNode;
  onClick: () => void;
  variant?: "primary" | "secondary";
}

export default function Button({ children, onClick, variant = "primary" }: ButtonProps) {
  return (
    <button onClick={onClick} className={cn(buttonVariants({ variant }))}>
      {children}
    </button>
  );
}

データフェッチング

ルートローダーの使用場面:

  • レンダリングに必要な初期ページデータ
  • SSR 要件
  • SEO クリティカルなデータ

React Query の使用場面:

  • 頻繁に更新されるデータ
  • オプション/二次データ
  • 楽観的更新を伴うクライアントミューテーション
// ルートローダー
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でスキーマを定義する:

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<typeof userSchema>;

// セーフパース
const result = userSchema.safeParse(data);
if (!result.success) {
  console.error("Validation failed:", result.error.format());
  return null;
}

ルート

src/routes/でファイルベースルーティングを使用してルートを構成する。常にエラーと保留中バウンダリを含める:

export const Route = createFileRoute("/users/$id")({
  loader: async ({ params }) => {
    const user = await fetchUser(params.id);
    return { user: userSchema.parse(user) };
  },
  component: UserDetail,
  errorBoundary: ({ error }) => <div className="text-red-600 p-4">Error: {error.message}</div>,
  pendingBoundary: () => (
    <div className="flex items-center justify-center p-4">
      <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary" />
    </div>
  ),
});

UI コンポーネント

カスタムコンポーネントよりも Shadcn/ui コンポーネントを常に優先する:

import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";

<Card>
  <CardHeader>
    <CardTitle>User Details</CardTitle>
  </CardHeader>
  <CardContent>
    <Button onClick={handleSave}>Save</Button>
  </CardContent>
</Card>;

レスポンシブデザインで Tailwind をスタイリングに使用する:

<div className="flex flex-col gap-4 p-6 md:flex-row md:gap-6">
  <Button className="w-full md:w-auto">Action</Button>
</div>

アクセシビリティ

セマンティック HTML を最優先とする。セマンティック相当物が存在しない場合のみ ARIA を追加する:

// ✅ 良い: 最小限のARIAを持つセマンティックHTML
<button onClick={toggleMenu}>
  <MenuIcon aria-hidden="true" />
  <span className="sr-only">Toggle Menu</span>
</button>

// ✅ 良い: 必要な時のみARIA動的状態の場合
<button
  aria-expanded={isOpen}
  aria-controls="menu"
  onClick={toggleMenu}
>
  Menu
</button>

// ✅ 良い: セマンティックフォーム要素
<label htmlFor="email">Email Address</label>
<input id="email" type="email" />
{errors.email && (
  <p role="alert">{errors.email}</p>
)}

ファイル構成

src/
├── components/ui/    # Shadcn/uiコンポーネント
├── lib/schemas.ts    # Zodスキーマ
├── routes/          # ファイルベースルート
└── routes/api/      # サーバールート(.ts

インポート標準

すべての内部インポートに@/エイリアスを使用する:

// ✅ 良い
import { Button } from "@/components/ui/button";
import { userSchema } from "@/lib/schemas";

// ❌ 悪い
import { Button } from "../components/ui/button";

コンポーネントの追加

必要に応じて Shadcn コンポーネントをインストールする:

npx shadcn@latest add button card input dialog

共通パターン

  • 外部データは常に Zod でバリデーションする
  • 初期データにはルートローダー、更新には React Query を使用する
  • すべてのルートにエラー/保留中バウンダリを含める
  • カスタム UI よりも Shadcn コンポーネントを優先する
  • @/インポートを一貫して使用する
  • アクセシビリティのベストプラクティスに従う