tanstack-vue-router-skilld について
tanstack-vue-router-skilldは、@tanstack/vue-routerでVueアプリをルーティングする開発者向けのリファレンススキルです。型安全なルート、ナビゲーション、データ読み込み、検索パラメーター、SSRを扱います。
主な機能
- 01型安全なファイルベース・コードベースのルーティング
- 02Vueコンポーザブルとルートコンポーネント
- 03ローダー・コンテキスト・リダイレクト
- 04検索パラメーターの検証
- 05SSRエントリーポイントとコンポーネント
活用シーン
- 01型安全なVueナビゲーションの構築
- 02認証チェックを伴うルートデータの読み込み
- 03検索パラメーターの検証と変換
- 04サーバーサイドレンダリングの設定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ skilld-dev/ vue-ecosystem-skills --skill tanstack-vue-router-skilldインストール後、Claude Code で/tanstack-vue-router-skilldを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/api-surface.mdcomposables.mddata-loading.mdfile-based-routing.mdnavigation-links.mdroutes.mdsearch-params.mdssr.md詳細
@tanstack/vue-router
Vue 用の型安全なルーターです。準備済みソース:バージョン 1.170.35(package.json:3)。
vue >= 3.3.0(peer)および Node>= 20.19が必要です(package.json:59-88)- ランタイム依存関係:
@tanstack/[email protected]、@tanstack/[email protected]、@tanstack/vue-store@^0.11.0 - ESM のみ(
"type": "module")。main/CJS エントリーポイントはありません - エントリーポイント:
@tanstack/vue-router、@tanstack/vue-router/ssr/server、@tanstack/vue-router/ssr/client(package.json:29-50)
ドキュメント:https://tanstack.com/router(フレームワークのページは /router/latest/docs/framework/vue/... で確認済み)
重要なルール
- ほとんどのコンポーザブルは
Ref<T>を返します — スクリプト内では.valueを使用し、テンプレートでは自動的にアンラップされます。useRouter()、useNavigate()、useLinkProps()、useAwaited()は ref を返しません。完全な一覧は references/composables.md を参照してください。 - 推論されるルート/ルーターの型をキャストしたり、注釈を付けたりしないでください。 型はルートツリーと
Register宣言から取得されます。 - 型安全性のためにルーターを登録してください — 登録しないと、
Link/useNavigate/useSearchは任意の文字列を受け入れます:
declare module '@tanstack/vue-router' {
interface Register {
router: typeof router
}
}
vue-routerではありません。vue-routerからuseRoute/useRouterをインポートしないでください。また、<router-view>/<router-link>も使用しないでください。beforeLoad/loaderは通常の非同期関数です。 Vue のコンポーザブル(ref、computed、ライフサイクルフック)はその中で実行できません。ルーターのcontextを通じて状態を渡してください。- ルートオプションでは Vue SFC を使用できます。
component、errorComponent、notFoundComponent、pendingComponentと、ルーターオプションのdefault*Componentは、.vueファイルまたはh()形式の関数コンポーネントを受け取ります(src/route.ts:54-58、src/router.ts:26-65)。
Vite を使ったセットアップ(ファイルベースルーティング)
npm install @tanstack/vue-router
npm install -D @tanstack/router-plugin @vitejs/plugin-vue @vitejs/plugin-vue-jsx
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { tanstackRouter } from '@tanstack/router-plugin/vite'
export default defineConfig({
plugins: [
tanstackRouter({ target: 'vue', autoCodeSplitting: true }), // before vue()
vue(),
vueJsx(), // needed for .tsx route files
],
})
出典:公式 Vue の例、https://github.com/TanStack/router/blob/main/examples/vue/basic-file-based-sfc/vite.config.ts
// src/main.ts
import { createApp, h } from 'vue'
import { RouterProvider, createRouter } from '@tanstack/vue-router'
import { routeTree } from './routeTree.gen'
const router = createRouter({
routeTree,
defaultPreload: 'intent',
scrollRestoration: true,
})
declare module '@tanstack/vue-router' {
interface Register {
router: typeof router
}
}
createApp({ setup: () => () => h(RouterProvider, { router }) }).mount('#app')
ファイル名、分割ファイルの規則(.route.ts、.component.vue、.lazy.ts)、生成される routeTree.gen.ts については、references/file-based-routing.md を参照してください。
コードベースのルーティング
import { h } from 'vue'
import { createRootRouteWithContext, createRoute, createRouter, Outlet } from '@tanstack/vue-router'
interface RouterContext { auth: { isAuthenticated: boolean } }
const rootRoute = createRootRouteWithContext<RouterContext>()({ component: () => h(Outlet) })
const postsRoute = createRoute({
getParentRoute: () => rootRoute,
path: 'posts',
loader: ({ context }) => fetchPosts(context.auth),
})
const routeTree = rootRoute.addChildren([postsRoute])
const router = createRouter({
routeTree,
context: { auth: { isAuthenticated: false } },
})
ルートオプション、ルートオブジェクト上のフック、プロパティの順序に関するルールについては、references/routes.md を参照してください。
コンポーザブル
| コンポーザブル | 戻り値 | 備考 |
|---|---|---|
useRouter() | router instance | ref ではありません |
useRouterState({ select }) | Ref<T> | 再レンダリングを避けるために select を渡します |
useNavigate({ from? }) | function | ref ではありません |
useSearch({ from }) | Ref<T> | from が一致しない場合はエラーになります |
useParams({ from }) | Ref<T> | |
useMatch({ from }) | Ref<T> | |
useLoaderData({ from }) | Ref<T> | |
useLoaderDeps({ from }) | Ref<T> | |
useRouteContext({ from }) | Ref<T> | |
useLocation() | Ref<ParsedLocation> | |
useMatches() / useParentMatches() / useChildMatches() | Ref<Array<Match>> | select を受け取ります |
useMatchRoute() | function | 呼び出すと Ref<false | params> を返します(src/Matches.tsx:148-172) |
useLinkProps(options) | link props object | カスタムアンカー向け |
useBlocker({ shouldBlockFn }) | void または Ref<BlockerResolver> | リゾルバーが返されるのは withResolver: true の場合のみです |
useCanGoBack() | Ref<boolean> | location.state.__TSR_index !== 0(src/useCanGoBack.ts:4-10) |
useAwaited({ promise }) | [data, promise] tuple | 遅延データ向け |
ルートオブジェクトと getRouteApi('/path') は、同じフックをスコープ済みの状態で公開します:Route.useSearch()、Route.useLoaderData()、Route.useNavigate()、Route.Link(src/route.ts:72-80)。
詳細と select/strict の動作については、references/composables.md を参照してください。
コンポーネント
| コンポーネント | 目的 |
|---|---|
<RouterProvider :router="router" /> | ルーターをマウントします。追加の属性でルーターのオプションを更新します(src/RouterProvider.tsx:60-95) |
<Link to="..." :params="..." :search="..."> | 型安全なアンカーです。有効状態では data-status="active" と aria-current="page" が設定されます(src/link.tsx:522-525)。デフォルトスロットには { isActive } が渡されます(src/link.tsx:918) |
<Outlet /> | 一致した子ルートをレンダリングします(src/Match.tsx:275) |
<Navigate to="..." /> | 宣言的なリダイレクトです。onMounted で実行されます(src/useNavigate.tsx:24-40) |
<MatchRoute to="..." :fuzzy="true"> | 一致した場合にスロットをレンダリングします。スコープ付きスロットにはパラメーターが渡されます |
<Await :promise="p"> | <Suspense> を使った遅延データです(src/awaited.tsx:26-43) |
<Block :should-block-fn="fn"> | ナビゲーションをブロックします。スコープ付きスロットにはリゾルバーが渡されます(src/useBlocker.tsx:470-491) |
<CatchBoundary> / <ErrorComponent> | onErrorCaptured によるエラーバウンダリーです |
<ClientOnly> | マウント後にのみ子要素をレンダリングします |
<HeadContent>, <Scripts>, <Html>, <Body>, <Asset>, <ScriptOnce> | SSR ドキュメントシェル |
リンクのオプション、activeProps(デフォルトは { class: 'active' }、src/link.tsx:477)、プリロード(intent/viewport/render)、linkOptions()、createLink()については、references/navigation-links.mdを参照してください。
データの読み込みとリダイレクト
const route = createFileRoute('/posts/$postId')({
beforeLoad: async ({ context, params }) => {
if (!context.auth.isAuthenticated) {
throw redirect({ to: '/login', search: { from: params.postId } })
}
},
loaderDeps: ({ search: { page } }) => ({ page }),
loader: ({ deps, params }) => fetchPost(params.postId, deps.page),
pendingComponent: PendingSpinner, // .vue file works too
})
throw redirect()、isRedirect()、defer() による遅延ストリーミング、コンテキストの型付けについては、references/data-loading.mdを参照してください。
検索パラメーター
import { z } from 'zod' // or plain validators
const route = createFileRoute('/posts')({
validateSearch: z.object({ page: z.number().default(1) }),
search: {
middlewares: [stripSearchParams({ page: 1 })],
},
})
バリデーター、入力/出力スキーマ、retainSearchParams/stripSearchParams、カスタムシリアライズについては、references/search-params.mdを参照してください。
1.170.x での非推奨項目(代わりに使用)
| 非推奨 | 置き換え | 根拠 |
|---|---|---|
Route、RootRoute、FileRoute、RouteApi クラス | createRoute、createRootRoute、createFileRoute、getRouteApi | src/route.ts:95、src/route.ts:220、src/route.ts:460、src/fileRoute.ts:57 |
rootRouteWithContext | createRootRouteWithContext | src/route.ts:414 |
NotFoundRoute / routerOptions.notFoundRoute | notFoundComponent ルートオプション / defaultNotFoundComponent ルーターオプション | https://tanstack.com/router/latest/docs/framework/vue/guide/not-found-errors |
<ScrollRestoration /> | createRouter の scrollRestoration: true | src/ScrollRestoration.tsx:18 |
beforeLoad/loader の opts.navigate | throw redirect({ to }) | https://tanstack.com/router/latest/docs/framework/vue/api/router/RouteOptionsType |
parseParams/stringifyParams | params.parse/params.stringify | 同じ RouteOptionsType ドキュメント |
preSearchFilters/postSearchFilters | search.middlewares | 同じ RouteOptionsType ドキュメント |
FileRouteLoader / 個別の .lazy.ts ローダーファイル | ローダーをルートファイル内に記述する | src/fileRoute.ts:153 |
useBlocker(fn, condition) の旧シグネチャ | { shouldBlockFn } オブジェクト | src/useBlocker.tsx:139-151 |
ベストプラクティス
- ルーターで
defaultPreload: 'intent'を設定します。プリロードされたデータはキャッシュされます(デフォルトは 30 s、defaultPreloadMaxAge)— https://tanstack.com/router/latest/docs/framework/vue/guide/preloading loaderDepsでは、ローダーが使用する検索パラメーターのみを選択します。searchをすべて展開すると、無関係なパラメーターが変更されるたびにローダーが再実行されます — https://tanstack.com/router/latest/docs/framework/vue/guide/data-loading- 深い階層のコンポーネントでは、
Routeオブジェクトをインポートする代わりにgetRouteApi('/posts/$postId')を使用します(循環インポートを回避できます)— https://tanstack.com/router/latest/docs/framework/vue/guide/data-loading beforeLoadのエラーハンドラーから再スローする場合は、リダイレクトが握りつぶされないよう、最初にisRedirect(error)を確認します — https://tanstack.com/router/latest/docs/framework/vue/guide/authenticated-routes- ルートオプションの順序は型推論に影響します(
loaderDepsより前にvalidateSearch/params、loaderより前にbeforeLoad)。create-route-property-orderESLint ルールは自動修正できます — https://tanstack.com/router/latest/docs/framework/vue/eslint/create-route-property-order - 再利用可能なナビゲーション先には、単純なオブジェクトリテラルより
linkOptions({ to, ... })を優先します。<Link>、navigate()、redirect()で使用できます — https://tanstack.com/router/latest/docs/framework/vue/guide/link-options - フックで
selectが新しいオブジェクトを返す場合は、ルーターでdefaultStructuralSharing: trueを有効にします — https://tanstack.com/router/latest/docs/framework/vue/guide/render-optimizations protocolAllowlist(デフォルトはDEFAULT_PROTOCOL_ALLOWLIST)に含まれないプロトコルを使用する外部リンクは、XSS を防ぐためにブロックされます(src/link.tsx:543-550)
参考資料
- references/api-surface.md — すべての公開エクスポートを分類して掲載
- references/composables.md — フックのシグネチャと
Refのセマンティクス - references/routes.md — ルートの作成、オプション、ルートフック
- references/navigation-links.md —
Link、ナビゲーション、ブロック、プリロード - references/data-loading.md — ローダー、コンテキスト、リダイレクト、遅延データ
- references/search-params.md — バリデーションとミドルウェア
- references/file-based-routing.md — Vite プラグイン、命名、コード分割
- references/ssr.md — サーバーのエントリーポイントとドキュメントシェルコンポーネント