virtual-file-routes について
ファイルシステムの規約だけに頼らず、コードで TanStack Router のルートツリーを定義するスキルです。ルート構成を明示したい場合や、仮想ルートと物理ルートを組み合わせる場合に向け、プラグイン設定と変更後の確認方法も示します。
主な機能
- 01プログラムによるルートツリー定義
- 02ルート、インデックス、分岐、レイアウトの作成
- 03物理ルートディレクトリのマウント
- 04仮想サブツリーの定義
- 05Router プラグインの設定
- 06変更後のルートツリー監査
活用シーン
- 01ファイル規約外でのルート作成
- 02仮想ルートとファイルルートの併用
- 03ルートディレクトリの URL プレフィックスへのマウント
- 04再生成前のルートツリー確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tanstack/ router --skill virtual-file-routesインストール後、Claude Code で/virtual-file-routesを入力して読み込まれたか確認します。
詳細
仮想ファイルルート(@tanstack/virtual-file-routes)
ファイルシステムの規約に頼らず、プログラムでルートツリーを構築します。ルート構造を明示的に制御したい場合、仮想ルートと物理ルートを組み合わせる必要がある場合、またはファイルベースのルーティングディレクトリ内でルートサブツリーを定義したい場合に便利です。
このスキルは、プロジェクトの設定に virtualRouteConfig、仮想ルート設定ファイル、または __virtual.ts が含まれている場合にのみ使用してください。通常のファイルルートの変更は、Router Core と Router Plugin の対象です。
重大:型は完全に推論されます。キャストも、推論される値への型注釈も行わないでください。
インストール
npm install @tanstack/virtual-file-routes
API リファレンス
rootRoute(file, children?)
仮想ルートツリーのルートを作成します。
import { rootRoute, index, route } from '@tanstack/virtual-file-routes'
const routes = rootRoute('root.tsx', [
index('index.tsx'),
route('/about', 'about.tsx'),
])
index(file)
インデックスルートを作成します。親のパスが完全に一致したときにデフォルトでレンダリングされます。
import { index } from '@tanstack/virtual-file-routes'
index('home.tsx')
route(path, ...)
ルートノードを作成します。呼び出しシグネチャは 3 種類あります。
import { route, index } from '@tanstack/virtual-file-routes'
// Leaf route: path + file
route('/about', 'about.tsx')
// Branch route: path + file + children
route('/dashboard', 'dashboard.tsx', [
index('dashboard-index.tsx'),
route('/settings', 'settings.tsx'),
])
// Path prefix only (no file): groups children under a URL segment
route('/api', [route('/users', 'users.tsx'), route('/posts', 'posts.tsx')])
layout(file, children) または layout(id, file, children)
パスレスのレイアウトルートを作成します。URL セグメントを追加せずに子をラップします。
import { layout, route, index } from '@tanstack/virtual-file-routes'
// ID derived from filename
layout('authLayout.tsx', [
route('/dashboard', 'dashboard.tsx'),
route('/settings', 'settings.tsx'),
])
// Explicit ID
layout('admin-layout', 'adminLayout.tsx', [route('/admin', 'admin.tsx')])
physical(pathPrefix, directory) または physical(directory)
ファイルベースのルートディレクトリを URL プレフィックスにマウントします。そのディレクトリ内では、TanStack Router の標準的なファイルベースルーティング規約が使用されます。
import { physical } from '@tanstack/virtual-file-routes'
// Mount posts/ directory under /posts
physical('/posts', 'posts')
// Merge features/ directory at the current level
physical('features')
defineVirtualSubtreeConfig(config)
ファイルベースのルーティングディレクトリ内にある __virtual.ts ファイル用の型ヘルパーです。型推論を提供する恒等関数です。
// src/routes/admin/__virtual.ts
import {
defineVirtualSubtreeConfig,
index,
route,
} from '@tanstack/virtual-file-routes'
export default defineVirtualSubtreeConfig([
index('home.tsx'),
route('$id', 'details.tsx'),
])
Router Plugin との連携
仮想ルート設定を TanStack Router プラグインに渡します。
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackRouter } from '@tanstack/router-plugin/vite'
import { routes } from './routes'
export default defineConfig({
plugins: [
tanstackRouter({
target: 'react', // or 'solid', 'vue'
virtualRouteConfig: routes,
}),
// Add your framework's Vite plugin here
],
})
または、ファイルパスを指定します。
tanstackRouter({
target: 'react',
virtualRouteConfig: './routes.ts',
})
完全な例
// routes.ts
import {
rootRoute,
route,
index,
layout,
physical,
} from '@tanstack/virtual-file-routes'
export const routes = rootRoute('root.tsx', [
index('index.tsx'),
layout('authLayout.tsx', [
route('/dashboard', 'app/dashboard.tsx', [
index('app/dashboard-index.tsx'),
route('/invoices', 'app/dashboard-invoices.tsx', [
index('app/invoices-index.tsx'),
route('$id', 'app/invoice-detail.tsx'),
]),
]),
]),
// Mount file-based routing from posts/ directory
physical('/posts', 'posts'),
])
よくある間違い
1. 重大:ファイルパスが routesDirectory からの相対パスであることを忘れる
rootRoute、index、route、layout のファイルパスは、ルータープラグインで設定された routesDirectory(デフォルト:./src/routes)からの相対パスです。絶対パスやプロジェクトルートからの相対パスは使用しないでください。
// WRONG — absolute path
route('/about', '/src/routes/about.tsx')
// CORRECT — relative to routesDirectory
route('/about', 'about.tsx')
2. 中程度:ディレクトリ構造が一致しない状態で physical() を使用する
physical() に渡すディレクトリは routesDirectory 内に存在し、TanStack Router のファイルベースルーティング規約に従っている必要があります。
// WRONG — directory doesn't exist or wrong location
physical('/blog', 'src/blog')
// CORRECT — relative to routesDirectory
physical('/blog', 'blog')
// Expects: src/routes/blog/ (with route files inside)
3. 中程度:layout() と route() を混同する
layout() はパスレスのラッパーを作成し、URL セグメントは追加しません。URL セグメントには route() を使用してください。
// This does NOT create a /dashboard URL
layout('dashboardLayout.tsx', [route('/dashboard', 'dashboard.tsx')])
// The URL is /dashboard, and dashboardLayout.tsx wraps it
リファクタリング監査
仮想ツリーを変更した後は、次の点を確認してください。
rootRouteがちょうど 1 つであり、参照されているすべてのファイルがroutesDirectoryからの相対パスとして存在することを確認します。- 各
route、layout、physicalノードに、実効パスまたは ID の重複がないか確認します。 - 各
physical()ディレクトリが意図したパスプレフィックスに一度だけマウントされ、仮想の子と重複していないことを確認します。 routeTree.gen.tsを再生成し、親子関係、完全なパス、インポートを確認します。生成された出力は編集しないでください。- リンク、リダイレクト、パラメーター、
fromの絞り込みを更新し、ジェネレーターテスト、型テスト、本番ビルドを実行します。