mcpField
D
deployment

deployment

github.com/tanstackクラウド・DevOps15.3k197 回インストール6 日前に更新
リポジトリ

deployment について

Vite と Nitro で構築するアプリ向けに、TanStack Start のデプロイとレンダリング設定を扱うスキルです。ホスティング、SSR、プリレンダリング、SEO メタデータの設定に役立ちます。

主な機能

  1. 01Vite と Nitro によるホスティング設定
  2. 02ルートごとの SSR 設定
  3. 03静的プリレンダリング
  4. 04メタタグと構造化データ
  5. 05動的なサイトマップルート

活用シーン

  1. 01ホスティング先へのデプロイ設定
  2. 02ルートごとのサーバー・クライアント描画の選択
  3. 03ビルド時の静的 HTML 生成
  4. 04ルート別 SEO メタデータの設定

インストール

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

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

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

詳細

デプロイとレンダリング

TanStack Start は Vite と Nitro を介して、あらゆるホスティングプロバイダーにデプロイできます。このスキルでは、ホスティングの設定、SSR の構成、プリレンダリング、SEO について説明します。

ホスティングプロバイダー

Cloudflare Workers
pnpm add -D @cloudflare/vite-plugin wrangler
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import { cloudflare } from '@cloudflare/vite-plugin'
import viteReact from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [
    cloudflare({ viteEnvironment: { name: 'ssr' } }),
    tanstackStart(),
    viteReact(),
  ],
})
// wrangler.jsonc
{
  "name": "my-app",
  "compatibility_date": "2025-09-02",
  "compatibility_flags": ["nodejs_compat"],
  "main": "@tanstack/react-start/server-entry",
}

デプロイ:npx wrangler login && pnpm run deploy

Worker の環境変数はリクエストごとに設定されます。 Cloudflare Workers はリクエスト時に環境変数を注入します。サーバー上であっても、モジュールスコープの process.env.X は undefined として評価されます。モジュールスコープを含め、環境変数を読み取る Cloudflare 公式の方法は、cloudflare:workers の env バインディングを使うことです。

import { env } from 'cloudflare:workers'
const apiHost = env.API_HOST

または、リクエストごとに .handler() 内またはミドルウェアの .server() 内で process.env.X を読み取ります。Cloudflare の環境変数に関するドキュメントと start-core/execution-model を参照してください。

Netlify
pnpm add -D @netlify/vite-plugin-tanstack-start
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import netlify from '@netlify/vite-plugin-tanstack-start'
import viteReact from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [tanstackStart(), netlify(), viteReact()],
})

デプロイ:npx netlify deploy

Nitro(Vercel、Railway、Node.js、Docker)
npm install nitro@npm:nitro-nightly@latest
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import { nitro } from 'nitro/vite'
import viteReact from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [tanstackStart(), nitro(), viteReact()],
})

ビルドと起動:npm run build && node .output/server/index.mjs

Bun

Bun へのデプロイには React 19 が必要です。React 18 の場合は、Node.js へのデプロイを使用してください。

// vite.config.ts — add bun preset to nitro
plugins: [tanstackStart(), nitro({ preset: 'bun' }), viteReact()]

選択的 SSR

ssr プロパティを使って、ルートごとに SSR を制御します。

ssr: true(デフォルト)

サーバーで beforeLoad と loader を実行し、コンポーネントをサーバーでレンダリングします。

export const Route = createFileRoute('/posts/$postId')({
  ssr: true, // default
  loader: () => fetchPost(), // runs on server during SSR
  component: PostPage, // rendered on server
})
ssr: false

beforeLoad/loader のサーバーでの実行と、サーバーでのレンダリングを無効にします。

export const Route = createFileRoute('/dashboard')({
  ssr: false,
  loader: () => fetchDashboard(), // runs on client only
  component: DashboardPage, // rendered on client only
})
ssr: 'data-only'

サーバーで beforeLoad/loader を実行しますが、コンポーネントはクライアントでのみレンダリングします。

export const Route = createFileRoute('/canvas')({
  ssr: 'data-only',
  loader: () => fetchCanvasData(), // runs on server
  component: CanvasPage, // rendered on client only
})
関数形式

パラメーターや検索条件に基づいて、実行時に SSR を決定します。

export const Route = createFileRoute('/docs/$docType/$docId')({
  ssr: ({ params }) => {
    if (params.status === 'success' && params.value.docType === 'sheet') {
      return false
    }
  },
})
SSR の継承

子ルートは親の SSR 設定を継承し、より制限的な設定のみ指定できます。

  • true → data-only または false(許可)
  • false → true(許可されません。親の false が優先されます)
デフォルトの SSR

src/start.ts ですべてのルートのデフォルトを変更します。

import { createStart } from '@tanstack/react-start'

export const startInstance = createStart(() => ({
  defaultSsr: false,
}))

静的プリレンダリング

ビルド時に静的 HTML を生成します。

// vite.config.ts
tanstackStart({
  prerender: {
    enabled: true,
    crawlLinks: true,
    concurrency: 14,
    failOnError: true,
  },
})

静的ルートは自動的に検出されます。動的ルート(例:/users/$userId)には、crawlLinks または明示的な pages 設定が必要です。

SEO とヘッド管理

基本的なメタタグ
export const Route = createFileRoute('/')({
  head: () => ({
    meta: [
      { title: 'My App - Home' },
      { name: 'description', content: 'Welcome to My App' },
    ],
  }),
})
ローダーデータからの動的なメタデータ
export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => fetchPost(params.postId),
  head: ({ loaderData }) => ({
    meta: [
      { title: loaderData.title },
      { name: 'description', content: loaderData.excerpt },
      { property: 'og:title', content: loaderData.title },
      { property: 'og:image', content: loaderData.coverImage },
    ],
  }),
})
構造化データ(JSON-LD)
head: ({ loaderData }) => ({
  scripts: [
    {
      type: 'application/ld+json',
      children: JSON.stringify({
        '@context': 'https://schema.org',
        '@type': 'Article',
        headline: loaderData.title,
      }),
    },
  ],
})
サーバールートを使った動的なサイトマップ
// src/routes/sitemap[.]xml.ts
export const Route = createFileRoute('/sitemap.xml')({
  server: {
    handlers: {
      GET: async () => {
        const posts = await fetchAllPosts()
        const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  ${posts.map((p) => `<url><loc>https://myapp.com/posts/${p.id}</loc></url>`).join('')}
</urlset>`
        return new Response(sitemap, {
          headers: { 'Content-Type': 'application/xml' },
        })
      },
    },
  },
})

よくある間違い

1. 重大:Cloudflare Workers の nodejs_compat フラグがない
// WRONG — Node.js APIs fail at runtime
{ "compatibility_flags": [] }

// CORRECT
{ "compatibility_flags": ["nodejs_compat"] }
2. 中程度:React 18 での Bun へのデプロイ

Bun 専用のデプロイは React 19 でのみ動作します。React 18 の場合は、Node.js へのデプロイを使用してください。

3. 中程度:子ルートで親の SSR 設定より制約を緩める
// Parent sets ssr: false
// WRONG — child cannot upgrade to ssr: true
const parentRoute = createFileRoute('/dashboard')({ ssr: false })
const childRoute = createFileRoute('/dashboard/stats')({
  ssr: true, // IGNORED — parent false wins
})

// CORRECT — children can only be MORE restrictive
const parentRoute = createFileRoute('/dashboard')({ ssr: 'data-only' })
const childRoute = createFileRoute('/dashboard/stats')({
  ssr: false, // OK — more restrictive than parent
})

関連項目

コメント