mcpField
T
tanstack-start

tanstack-start

github.com/tanstack-skills開発363.9k 回インストール39 週間前に更新
リポジトリ

tanstack-start について

TanStack Start は、サーバー描画アプリを開発するための、TanStack Router を基盤としたフルスタック React フレームワークです。ストリーミング SSR、型安全なサーバー関数、ミドルウェア、API ルートを備え、Nitro プリセットでデプロイできます。

主な機能

  1. 01サーバーサイドレンダリングとストリーミング
  2. 02型安全なサーバー RPC 関数
  3. 03合成可能なミドルウェア
  4. 04ファイルベースの API ルート
  5. 05Nitro プリセットによるデプロイ

活用シーン

  1. 01サーバー描画 React アプリの構築
  2. 02型安全なクライアント・サーバー間呼び出し
  3. 03ルートへの認証ミドルウェア追加
  4. 04アプリケーション API エンドポイントの作成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/tanstack-skills/tanstack-skills --skill tanstack-start

インストール後、Claude Code で/tanstack-startを入力して読み込まれたか確認します。

詳細

TanStack Start スキル

概要

TanStack Start は、TanStack Router をベースに構築され、Vite と Nitro(Vinxi 経由)で動作するフルスタック React フレームワークです。サーバーサイドレンダリング、ストリーミング、サーバー関数(RPC)、ミドルウェア、API ルートを提供し、Nitro プリセットを通じてあらゆるプラットフォームにデプロイできます。

パッケージ: @tanstack/react-start ルータープラグイン: @tanstack/router-plugin ビルドツール: Vinxi(Vite + Nitro) ステータス: RC(リリース候補) RSC サポート: React Server Components のサポートは現在活発に開発中で、後方互換性を保った v1.x の追加機能として提供される予定です。

インストールとプロジェクトのセットアップ

npx @tanstack/cli create my-app
# Or manually:
npm install @tanstack/react-start @tanstack/react-router react react-dom
npm install -D @tanstack/router-plugin typescript vite vite-tsconfig-paths
プロジェクト構成
my-app/
  app/
    routes/
      __root.tsx          # Root layout
      index.tsx           # / route
      posts.$postId.tsx   # /posts/:postId
      api/
        users.ts          # /api/users API route
    client.tsx            # Client entry
    router.tsx            # Router creation
    ssr.tsx               # SSR entry
    routeTree.gen.ts      # Auto-generated route tree
  app.config.ts           # TanStack Start config
  tsconfig.json
  package.json
設定(app.config.ts)
import { defineConfig } from '@tanstack/react-start/config'
import viteTsConfigPaths from 'vite-tsconfig-paths'

export default defineConfig({
  vite: {
    plugins: [
      viteTsConfigPaths({ projects: ['./tsconfig.json'] }),
    ],
  },
  server: {
    preset: 'node-server', // 'vercel' | 'netlify' | 'cloudflare-pages' | etc.
  },
  tsr: {
    appDirectory: './app',
    routesDirectory: './app/routes',
    generatedRouteTree: './app/routeTree.gen.ts',
  },
})

サーバー関数(createServerFn)

サーバー関数は、クライアントとサーバー間の型安全な RPC 呼び出しを実現します。

基本的なサーバー関数
import { createServerFn } from '@tanstack/react-start'

// GET (data fetching, cacheable)
const getUsers = createServerFn()
  .handler(async () => {
    const users = await db.query.users.findMany()
    return users
  })

// POST (mutations, side effects)
const createUser = createServerFn({ method: 'POST' })
  .validator((data: { name: string; email: string }) => data)
  .handler(async ({ data }) => {
    const user = await db.insert(users).values(data).returning()
    return user
  })
Zod による検証
import { z } from 'zod'

const updateUser = createServerFn({ method: 'POST' })
  .validator(
    z.object({
      id: z.string(),
      name: z.string().min(1),
      email: z.string().email(),
    })
  )
  .handler(async ({ data }) => {
    // data is fully typed: { id: string; name: string; email: string }
    return await db.update(users).set(data).where(eq(users.id, data.id))
  })

ミドルウェア

ミドルウェアの作成
import { createMiddleware } from '@tanstack/react-start'

const loggingMiddleware = createMiddleware().handler(async ({ next }) => {
  console.log('Request started')
  const result = await next()
  console.log('Request completed')
  return result
})
コンテキストを使った認証ミドルウェア
const authMiddleware = createMiddleware().handler(async ({ next }) => {
  const request = getWebRequest()
  const session = await getSession(request)

  if (!session?.user) {
    throw redirect({ to: '/login' })
  }

  // Pass typed context to handler
  return next({ context: { user: session.user } })
})
ミドルウェアの連結
const adminMiddleware = createMiddleware()
  .middleware([authMiddleware])
  .handler(async ({ next, context }) => {
    // context.user is typed from authMiddleware
    if (context.user.role !== 'admin') {
      throw redirect({ to: '/unauthorized' })
    }
    return next({ context: { isAdmin: true } })
  })

// Usage
const adminAction = createServerFn({ method: 'POST' })
  .middleware([adminMiddleware])
  .handler(async ({ context }) => {
    // context: { user: User; isAdmin: boolean }
    return { success: true }
  })

API ルート(サーバールート)

// app/routes/api/users.ts
import { createAPIFileRoute } from '@tanstack/react-start/api'

export const APIRoute = createAPIFileRoute('/api/users')({
  GET: async ({ request }) => {
    const users = await db.query.users.findMany()
    return Response.json(users)
  },
  POST: async ({ request }) => {
    const body = await request.json()
    const user = await db.insert(users).values(body).returning()
    return new Response(JSON.stringify(user), { status: 201 })
  },
})

SSR 戦略

ストリーミング SSR(デフォルト)
export const Route = createFileRoute('/dashboard')({
  loader: async () => ({
    criticalData: await fetchCriticalData(),
    deferredData: defer(fetchSlowData()),
  }),
  component: Dashboard,
})

function Dashboard() {
  const { criticalData, deferredData } = Route.useLoaderData()
  return (
    <div>
      <CriticalSection data={criticalData} />
      <Suspense fallback={<Loading />}>
        <Await promise={deferredData}>
          {(data) => <SlowSection data={data} />}
        </Await>
      </Suspense>
    </div>
  )
}

デプロイ

対応プラットフォーム(Nitro プリセット)
// app.config.ts
export default defineConfig({
  server: {
    preset: 'node-server',        // Self-hosted Node.js
    // preset: 'vercel',          // Vercel
    // preset: 'netlify',         // Netlify
    // preset: 'cloudflare-pages', // Cloudflare Pages
    // preset: 'aws-lambda',      // AWS Lambda
    // preset: 'deno-server',     // Deno Deploy
    // preset: 'bun',             // Bun
  },
})

ベストプラクティス

  1. すべてのサーバー関数の入力にバリデーターを使用する - 実行時の安全性と TypeScript の型推論を確保します
  2. 認証、ロギング、レート制限などの横断的な関心事には、ミドルウェアを組み合わせます
  3. データ取得には createServerFn GET を使用します(キャッシュ可能で、事前ロードできます)
  4. ミューテーションや副作用には createServerFn POST を使用します
  5. ルートレベルの認証ガードには beforeLoad を使用します
  6. TTFB の改善には、重要でないデータに defer() を使用します
  7. 即時ナビゲーションを実現するため、ルーターに defaultPreload: 'intent' を設定します
  8. サーバー関数を、それを使用するルートと同じ場所に配置します

よくある落とし穴

  • サーバー関数はクライアント側の変数をクロージャーに取り込めません(別のバンドルに抽出されるためです)
  • サーバー関数から返すデータはシリアライズ可能でなければなりません
  • ローダーで await を忘れると、ストリーミングに問題が発生します
  • サーバー専用のコードをクライアントバンドルにインポートすると、ビルドエラーが発生します
  • declare module '@tanstack/react-router' を記述し忘れると、型安全性が失われます

コメント