>('https://jsonplaceholder.typicode.com/posts')
+ .then((r) => r.data.slice(0, 10))
+}
diff --git a/examples/react/basic-virtual-file-based/src/routeTree.gen.ts b/examples/react/basic-virtual-file-based/src/routeTree.gen.ts
new file mode 100644
index 0000000000..0b6af24d47
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routeTree.gen.ts
@@ -0,0 +1,277 @@
+/* prettier-ignore-start */
+
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file is auto-generated by TanStack Router
+
+// Import Routes
+
+import { Route as rootRoute } from './routes/root'
+import { Route as postsPostsImport } from './routes/posts/posts'
+import { Route as layoutFirstLayoutImport } from './routes/layout/first-layout'
+import { Route as homeImport } from './routes/home'
+import { Route as postsPostsDetailImport } from './routes/posts/posts-detail'
+import { Route as layoutSecondLayoutImport } from './routes/layout/second-layout'
+import { Route as postsPostsHomeImport } from './routes/posts/posts-home'
+import { Route as ClassicHelloRouteImport } from './routes/file-based-subtree/hello/route'
+import { Route as ClassicHelloIndexImport } from './routes/file-based-subtree/hello/index'
+import { Route as ClassicHelloWorldImport } from './routes/file-based-subtree/hello/world'
+import { Route as ClassicHelloUniverseImport } from './routes/file-based-subtree/hello/universe'
+import { Route as bImport } from './routes/b'
+import { Route as aImport } from './routes/a'
+
+// Create/Update Routes
+
+const postsPostsRoute = postsPostsImport.update({
+ path: '/posts',
+ getParentRoute: () => rootRoute,
+} as any)
+
+const layoutFirstLayoutRoute = layoutFirstLayoutImport.update({
+ id: '/_first',
+ getParentRoute: () => rootRoute,
+} as any)
+
+const homeRoute = homeImport.update({
+ path: '/',
+ getParentRoute: () => rootRoute,
+} as any)
+
+const postsPostsDetailRoute = postsPostsDetailImport.update({
+ path: '/$postId',
+ getParentRoute: () => postsPostsRoute,
+} as any)
+
+const layoutSecondLayoutRoute = layoutSecondLayoutImport.update({
+ id: '/_second',
+ getParentRoute: () => layoutFirstLayoutRoute,
+} as any)
+
+const postsPostsHomeRoute = postsPostsHomeImport.update({
+ path: '/',
+ getParentRoute: () => postsPostsRoute,
+} as any)
+
+const ClassicHelloRouteRoute = ClassicHelloRouteImport.update({
+ path: '/classic/hello',
+ getParentRoute: () => rootRoute,
+} as any)
+
+const ClassicHelloIndexRoute = ClassicHelloIndexImport.update({
+ path: '/',
+ getParentRoute: () => ClassicHelloRouteRoute,
+} as any)
+
+const ClassicHelloWorldRoute = ClassicHelloWorldImport.update({
+ path: '/world',
+ getParentRoute: () => ClassicHelloRouteRoute,
+} as any)
+
+const ClassicHelloUniverseRoute = ClassicHelloUniverseImport.update({
+ path: '/universe',
+ getParentRoute: () => ClassicHelloRouteRoute,
+} as any)
+
+const bRoute = bImport.update({
+ path: '/layout-b',
+ getParentRoute: () => layoutSecondLayoutRoute,
+} as any)
+
+const aRoute = aImport.update({
+ path: '/layout-a',
+ getParentRoute: () => layoutSecondLayoutRoute,
+} as any)
+
+// Populate the FileRoutesByPath interface
+
+declare module '@tanstack/react-router' {
+ interface FileRoutesByPath {
+ '/': {
+ id: '/'
+ path: '/'
+ fullPath: '/'
+ preLoaderRoute: typeof homeImport
+ parentRoute: typeof rootRoute
+ }
+ '/_first': {
+ id: '/_first'
+ path: ''
+ fullPath: ''
+ preLoaderRoute: typeof layoutFirstLayoutImport
+ parentRoute: typeof rootRoute
+ }
+ '/posts': {
+ id: '/posts'
+ path: '/posts'
+ fullPath: '/posts'
+ preLoaderRoute: typeof postsPostsImport
+ parentRoute: typeof rootRoute
+ }
+ '/classic/hello': {
+ id: '/classic/hello'
+ path: '/classic/hello'
+ fullPath: '/classic/hello'
+ preLoaderRoute: typeof ClassicHelloRouteImport
+ parentRoute: typeof rootRoute
+ }
+ '/posts/': {
+ id: '/posts/'
+ path: '/'
+ fullPath: '/posts/'
+ preLoaderRoute: typeof postsPostsHomeImport
+ parentRoute: typeof postsPostsImport
+ }
+ '/_first/_second': {
+ id: '/_first/_second'
+ path: ''
+ fullPath: ''
+ preLoaderRoute: typeof layoutSecondLayoutImport
+ parentRoute: typeof layoutFirstLayoutImport
+ }
+ '/posts/$postId': {
+ id: '/posts/$postId'
+ path: '/$postId'
+ fullPath: '/posts/$postId'
+ preLoaderRoute: typeof postsPostsDetailImport
+ parentRoute: typeof postsPostsImport
+ }
+ '/_first/_second/layout-a': {
+ id: '/_first/_second/layout-a'
+ path: '/layout-a'
+ fullPath: '/layout-a'
+ preLoaderRoute: typeof aImport
+ parentRoute: typeof layoutSecondLayoutImport
+ }
+ '/_first/_second/layout-b': {
+ id: '/_first/_second/layout-b'
+ path: '/layout-b'
+ fullPath: '/layout-b'
+ preLoaderRoute: typeof bImport
+ parentRoute: typeof layoutSecondLayoutImport
+ }
+ '/classic/hello/universe': {
+ id: '/classic/hello/universe'
+ path: '/universe'
+ fullPath: '/classic/hello/universe'
+ preLoaderRoute: typeof ClassicHelloUniverseImport
+ parentRoute: typeof ClassicHelloRouteImport
+ }
+ '/classic/hello/world': {
+ id: '/classic/hello/world'
+ path: '/world'
+ fullPath: '/classic/hello/world'
+ preLoaderRoute: typeof ClassicHelloWorldImport
+ parentRoute: typeof ClassicHelloRouteImport
+ }
+ '/classic/hello/': {
+ id: '/classic/hello/'
+ path: '/'
+ fullPath: '/classic/hello/'
+ preLoaderRoute: typeof ClassicHelloIndexImport
+ parentRoute: typeof ClassicHelloRouteImport
+ }
+ }
+}
+
+// Create and export the route tree
+
+export const routeTree = rootRoute.addChildren({
+ homeRoute,
+ layoutFirstLayoutRoute: layoutFirstLayoutRoute.addChildren({
+ layoutSecondLayoutRoute: layoutSecondLayoutRoute.addChildren({
+ aRoute,
+ bRoute,
+ }),
+ }),
+ postsPostsRoute: postsPostsRoute.addChildren({
+ postsPostsHomeRoute,
+ postsPostsDetailRoute,
+ }),
+ ClassicHelloRouteRoute: ClassicHelloRouteRoute.addChildren({
+ ClassicHelloUniverseRoute,
+ ClassicHelloWorldRoute,
+ ClassicHelloIndexRoute,
+ }),
+})
+
+/* prettier-ignore-end */
+
+/* ROUTE_MANIFEST_START
+{
+ "routes": {
+ "__root__": {
+ "filePath": "root.tsx",
+ "children": [
+ "/",
+ "/_first",
+ "/posts",
+ "/classic/hello"
+ ]
+ },
+ "/": {
+ "filePath": "home.tsx"
+ },
+ "/_first": {
+ "filePath": "layout/first-layout.tsx",
+ "children": [
+ "/_first/_second"
+ ]
+ },
+ "/posts": {
+ "filePath": "posts/posts.tsx",
+ "children": [
+ "/posts/",
+ "/posts/$postId"
+ ]
+ },
+ "/classic/hello": {
+ "filePath": "file-based-subtree/hello/route.tsx",
+ "children": [
+ "/classic/hello/universe",
+ "/classic/hello/world",
+ "/classic/hello/"
+ ]
+ },
+ "/posts/": {
+ "filePath": "posts/posts-home.tsx",
+ "parent": "/posts"
+ },
+ "/_first/_second": {
+ "filePath": "layout/second-layout.tsx",
+ "parent": "/_first",
+ "children": [
+ "/_first/_second/layout-a",
+ "/_first/_second/layout-b"
+ ]
+ },
+ "/posts/$postId": {
+ "filePath": "posts/posts-detail.tsx",
+ "parent": "/posts"
+ },
+ "/_first/_second/layout-a": {
+ "filePath": "a.tsx",
+ "parent": "/_first/_second"
+ },
+ "/_first/_second/layout-b": {
+ "filePath": "b.tsx",
+ "parent": "/_first/_second"
+ },
+ "/classic/hello/universe": {
+ "filePath": "file-based-subtree/hello/universe.tsx",
+ "parent": "/classic/hello"
+ },
+ "/classic/hello/world": {
+ "filePath": "file-based-subtree/hello/world.tsx",
+ "parent": "/classic/hello"
+ },
+ "/classic/hello/": {
+ "filePath": "file-based-subtree/hello/index.tsx",
+ "parent": "/classic/hello"
+ }
+ }
+}
+ROUTE_MANIFEST_END */
diff --git a/examples/react/basic-virtual-file-based/src/routes/a.tsx b/examples/react/basic-virtual-file-based/src/routes/a.tsx
new file mode 100644
index 0000000000..6cccd02950
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routes/a.tsx
@@ -0,0 +1,9 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_first/_second/layout-a')({
+ component: LayoutAComponent,
+})
+
+function LayoutAComponent() {
+ return I'm layout A!
+}
diff --git a/examples/react/basic-virtual-file-based/src/routes/b.tsx b/examples/react/basic-virtual-file-based/src/routes/b.tsx
new file mode 100644
index 0000000000..98bb842612
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routes/b.tsx
@@ -0,0 +1,9 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_first/_second/layout-b')({
+ component: LayoutBComponent,
+})
+
+function LayoutBComponent() {
+ return I'm layout B!
+}
diff --git a/examples/react/basic-virtual-file-based/src/routes/file-based-subtree/hello/index.tsx b/examples/react/basic-virtual-file-based/src/routes/file-based-subtree/hello/index.tsx
new file mode 100644
index 0000000000..7a6d5e3bd3
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routes/file-based-subtree/hello/index.tsx
@@ -0,0 +1,5 @@
+import { Link, createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/classic/hello/')({
+ component: () => This is the index
,
+})
diff --git a/examples/react/basic-virtual-file-based/src/routes/file-based-subtree/hello/route.tsx b/examples/react/basic-virtual-file-based/src/routes/file-based-subtree/hello/route.tsx
new file mode 100644
index 0000000000..566efc8777
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routes/file-based-subtree/hello/route.tsx
@@ -0,0 +1,27 @@
+import { Link, Outlet, createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/classic/hello')({
+ component: () => (
+
+ Hello!
+ {' '}
+
+ say hello to the universe
+ {' '}
+
+ say hello to the world
+
+
+
+ ),
+})
diff --git a/examples/react/basic-virtual-file-based/src/routes/file-based-subtree/hello/universe.tsx b/examples/react/basic-virtual-file-based/src/routes/file-based-subtree/hello/universe.tsx
new file mode 100644
index 0000000000..e00c47d74b
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routes/file-based-subtree/hello/universe.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/classic/hello/universe')({
+ component: () => Hello /classic/hello/universe!
,
+})
diff --git a/examples/react/basic-virtual-file-based/src/routes/file-based-subtree/hello/world.tsx b/examples/react/basic-virtual-file-based/src/routes/file-based-subtree/hello/world.tsx
new file mode 100644
index 0000000000..9783557342
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routes/file-based-subtree/hello/world.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/classic/hello/world')({
+ component: () => Hello /classic/hello/world!
,
+})
diff --git a/examples/react/basic-virtual-file-based/src/routes/home.tsx b/examples/react/basic-virtual-file-based/src/routes/home.tsx
new file mode 100644
index 0000000000..eac82a9174
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routes/home.tsx
@@ -0,0 +1,14 @@
+import * as React from 'react'
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/')({
+ component: Home,
+})
+
+function Home() {
+ return (
+
+
Welcome Home!
+
+ )
+}
diff --git a/examples/react/basic-virtual-file-based/src/routes/layout/first-layout.tsx b/examples/react/basic-virtual-file-based/src/routes/layout/first-layout.tsx
new file mode 100644
index 0000000000..d39e206f2d
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routes/layout/first-layout.tsx
@@ -0,0 +1,16 @@
+import { Outlet, createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_first')({
+ component: LayoutComponent,
+})
+
+function LayoutComponent() {
+ return (
+
+ )
+}
diff --git a/examples/react/basic-virtual-file-based/src/routes/layout/second-layout.tsx b/examples/react/basic-virtual-file-based/src/routes/layout/second-layout.tsx
new file mode 100644
index 0000000000..ef178a6e16
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routes/layout/second-layout.tsx
@@ -0,0 +1,34 @@
+import { Link, Outlet, createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_first/_second')({
+ component: LayoutComponent,
+})
+
+function LayoutComponent() {
+ return (
+
+
I'm a nested layout
+
+
+ Layout A
+
+
+ Layout B
+
+
+
+
+
+
+ )
+}
diff --git a/examples/react/basic-virtual-file-based/src/routes/posts/posts-detail.tsx b/examples/react/basic-virtual-file-based/src/routes/posts/posts-detail.tsx
new file mode 100644
index 0000000000..948d52d6d6
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routes/posts/posts-detail.tsx
@@ -0,0 +1,28 @@
+import * as React from 'react'
+import { ErrorComponent, createFileRoute } from '@tanstack/react-router'
+import { fetchPost } from '../../posts'
+import type { ErrorComponentProps } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/posts/$postId')({
+ loader: async ({ params: { postId } }) => fetchPost(postId),
+ errorComponent: PostErrorComponent as any,
+ notFoundComponent: () => {
+ return Post not found
+ },
+ component: PostComponent,
+})
+
+export function PostErrorComponent({ error }: ErrorComponentProps) {
+ return
+}
+
+function PostComponent() {
+ const post = Route.useLoaderData()
+
+ return (
+
+
{post.title}
+
{post.body}
+
+ )
+}
diff --git a/examples/react/basic-virtual-file-based/src/routes/posts/posts-home.tsx b/examples/react/basic-virtual-file-based/src/routes/posts/posts-home.tsx
new file mode 100644
index 0000000000..056433ca0a
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routes/posts/posts-home.tsx
@@ -0,0 +1,10 @@
+import * as React from 'react'
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/posts/')({
+ component: PostsIndexComponent,
+})
+
+function PostsIndexComponent() {
+ return Select a post.
+}
diff --git a/examples/react/basic-virtual-file-based/src/routes/posts/posts.tsx b/examples/react/basic-virtual-file-based/src/routes/posts/posts.tsx
new file mode 100644
index 0000000000..a2ab1ee388
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routes/posts/posts.tsx
@@ -0,0 +1,39 @@
+import * as React from 'react'
+import { Link, Outlet, createFileRoute } from '@tanstack/react-router'
+import { fetchPosts } from '../../posts'
+
+export const Route = createFileRoute('/posts')({
+ loader: fetchPosts,
+ component: PostsComponent,
+})
+
+function PostsComponent() {
+ const posts = Route.useLoaderData()
+
+ return (
+
+ )
+}
diff --git a/examples/react/basic-virtual-file-based/src/routes/root.tsx b/examples/react/basic-virtual-file-based/src/routes/root.tsx
new file mode 100644
index 0000000000..bd82cdf6a5
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/src/routes/root.tsx
@@ -0,0 +1,70 @@
+import * as React from 'react'
+import { Link, Outlet, createRootRoute } from '@tanstack/react-router'
+import { TanStackRouterDevtools } from '@tanstack/router-devtools'
+
+export const Route = createRootRoute({
+ component: RootComponent,
+ notFoundComponent: () => {
+ return (
+
+
This is the notFoundComponent configured on root route
+
Start Over
+
+ )
+ },
+})
+
+function RootComponent() {
+ return (
+ <>
+
+
+ Home
+ {' '}
+
+ Posts
+ {' '}
+
+ Layout
+ {' '}
+
+ Subtree
+ {' '}
+
+ This Route Does Not Exist
+
+
+
+
+ {/* Start rendering router matches */}
+
+ >
+ )
+}
diff --git a/examples/react/basic-virtual-file-based/tests/app.spec.ts b/examples/react/basic-virtual-file-based/tests/app.spec.ts
new file mode 100644
index 0000000000..f19a88b569
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/tests/app.spec.ts
@@ -0,0 +1,34 @@
+import { expect, test } from '@playwright/test'
+
+test.beforeEach(async ({ page }) => {
+ await page.goto('/')
+})
+
+test('Navigating to a post page', async ({ page }) => {
+ await page.getByRole('link', { name: 'Posts' }).click()
+ await page.getByRole('link', { name: 'sunt aut facere repe' }).click()
+ await expect(page.getByRole('heading')).toContainText('sunt aut facere')
+})
+
+test('Navigating nested layouts', async ({ page }) => {
+ await page.goto('/')
+ await page.getByRole('link', { name: 'Layout', exact: true }).click()
+
+ await expect(page.locator('#app')).toContainText("I'm a layout")
+ await expect(page.locator('#app')).toContainText("I'm a nested layout")
+
+ await page.getByRole('link', { name: 'Layout A' }).click()
+ await expect(page.locator('#app')).toContainText("I'm layout A!")
+
+ await page.getByRole('link', { name: 'Layout B' }).click()
+ await expect(page.locator('#app')).toContainText("I'm layout B!")
+})
+
+test('Navigating to a not-found route', async ({ page }) => {
+ await page.getByRole('link', { name: 'This Route Does Not Exist' }).click()
+ await expect(page.getByRole('paragraph')).toContainText(
+ 'This is the notFoundComponent configured on root route',
+ )
+ await page.getByRole('link', { name: 'Start Over' }).click()
+ await expect(page.getByRole('heading')).toContainText('Welcome Home!')
+})
diff --git a/examples/react/basic-virtual-file-based/tsconfig.dev.json b/examples/react/basic-virtual-file-based/tsconfig.dev.json
new file mode 100644
index 0000000000..285a09b0dc
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/tsconfig.dev.json
@@ -0,0 +1,10 @@
+{
+ "composite": true,
+ "extends": "../../../tsconfig.base.json",
+
+ "files": ["src/main.tsx"],
+ "include": [
+ "src"
+ // "__tests__/**/*.test.*"
+ ]
+}
diff --git a/examples/react/basic-virtual-file-based/tsconfig.json b/examples/react/basic-virtual-file-based/tsconfig.json
new file mode 100644
index 0000000000..e2241c355e
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions": {
+ "strict": true,
+ "esModuleInterop": true,
+ "jsx": "react-jsx",
+ "module": "Preserve",
+ "moduleResolution": "Bundler"
+ }
+}
diff --git a/examples/react/basic-virtual-file-based/vite.config.ts b/examples/react/basic-virtual-file-based/vite.config.ts
new file mode 100644
index 0000000000..c1b8574783
--- /dev/null
+++ b/examples/react/basic-virtual-file-based/vite.config.ts
@@ -0,0 +1,9 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
+import { routes } from './routes'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [TanStackRouterVite({ virtualRouteConfig: routes }), react()],
+})
diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/foo/bar.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/foo/bar.tsx
new file mode 100644
index 0000000000..aa5920563e
--- /dev/null
+++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/foo/bar.tsx
@@ -0,0 +1,7 @@
+import { createFileRoute } from '@tanstack/react-router'
+import { z } from 'zod'
+
+export const Route = createFileRoute('/foo/bar')({
+ component: () => {JSON.stringify(Route.useSearch())}
,
+ validateSearch: z.object({ asdf: z.string() }),
+})
diff --git a/package.json b/package.json
index 44b3571145..9365571e39 100644
--- a/package.json
+++ b/package.json
@@ -70,6 +70,7 @@
"@tanstack/router-cli": "workspace:*",
"@tanstack/router-devtools": "workspace:*",
"@tanstack/router-generator": "workspace:*",
+ "@tanstack/virtual-file-routes": "workspace:*",
"@tanstack/router-plugin": "workspace:*",
"@tanstack/router-vite-plugin": "workspace:*",
"@tanstack/react-router-with-query": "workspace:*",
diff --git a/packages/router-generator/package.json b/packages/router-generator/package.json
index bb07408d5f..74c58cd950 100644
--- a/packages/router-generator/package.json
+++ b/packages/router-generator/package.json
@@ -64,6 +64,7 @@
},
"dependencies": {
"prettier": "^3.3.3",
- "zod": "^3.23.8"
+ "zod": "^3.23.8",
+ "@tanstack/virtual-file-routes": "workspace:^"
}
}
diff --git a/packages/router-generator/src/config.ts b/packages/router-generator/src/config.ts
index 0f36cf3cbc..b39fc63896 100644
--- a/packages/router-generator/src/config.ts
+++ b/packages/router-generator/src/config.ts
@@ -1,8 +1,10 @@
import path from 'node:path'
import { existsSync, readFileSync } from 'node:fs'
import { z } from 'zod'
+import { virtualRootRouteSchema } from './filesystem/virtual/config'
export const configSchema = z.object({
+ virtualRouteConfig: virtualRootRouteSchema.optional(),
routeFilePrefix: z.string().optional(),
routeFileIgnorePrefix: z.string().optional().default('-'),
routeFileIgnorePattern: z.string().optional(),
diff --git a/packages/router-generator/src/filesystem/physical/getRouteNodes.ts b/packages/router-generator/src/filesystem/physical/getRouteNodes.ts
new file mode 100644
index 0000000000..a2d3e26f23
--- /dev/null
+++ b/packages/router-generator/src/filesystem/physical/getRouteNodes.ts
@@ -0,0 +1,151 @@
+import path from 'node:path'
+import * as fsp from 'node:fs/promises'
+import {
+ determineInitialRoutePath,
+ logging,
+ removeExt,
+ removeTrailingSlash,
+ replaceBackslash,
+ routePathToVariable,
+} from '../../utils'
+import { rootPathId } from './rootPathId'
+import type { GetRouteNodesResult, RouteNode } from '../../types'
+import type { Config } from '../../config'
+
+const disallowedRouteGroupConfiguration = /\(([^)]+)\).(ts|js|tsx|jsx)/
+
+export async function getRouteNodes(
+ config: Config,
+): Promise {
+ const { routeFilePrefix, routeFileIgnorePrefix, routeFileIgnorePattern } =
+ config
+ const logger = logging({ disabled: config.disableLogging })
+ const routeFileIgnoreRegExp = new RegExp(routeFileIgnorePattern ?? '', 'g')
+
+ const routeNodes: Array = []
+
+ async function recurse(dir: string) {
+ const fullDir = path.resolve(config.routesDirectory, dir)
+ let dirList = await fsp.readdir(fullDir, { withFileTypes: true })
+
+ dirList = dirList.filter((d) => {
+ if (
+ d.name.startsWith('.') ||
+ (routeFileIgnorePrefix && d.name.startsWith(routeFileIgnorePrefix))
+ ) {
+ return false
+ }
+
+ if (routeFilePrefix) {
+ return d.name.startsWith(routeFilePrefix)
+ }
+
+ if (routeFileIgnorePattern) {
+ return !d.name.match(routeFileIgnoreRegExp)
+ }
+
+ return true
+ })
+
+ await Promise.all(
+ dirList.map(async (dirent) => {
+ const fullPath = path.join(fullDir, dirent.name)
+ const relativePath = path.join(dir, dirent.name)
+
+ if (dirent.isDirectory()) {
+ await recurse(relativePath)
+ } else if (fullPath.match(/\.(tsx|ts|jsx|js)$/)) {
+ const filePath = replaceBackslash(path.join(dir, dirent.name))
+ const filePathNoExt = removeExt(filePath)
+ let routePath = determineInitialRoutePath(filePathNoExt)
+
+ if (routeFilePrefix) {
+ routePath = routePath.replaceAll(routeFilePrefix, '')
+ }
+
+ if (disallowedRouteGroupConfiguration.test(dirent.name)) {
+ const errorMessage = `A route configuration for a route group was found at \`${filePath}\`. This is not supported. Did you mean to use a layout/pathless route instead?`
+ logger.error(`ERROR: ${errorMessage}`)
+ throw new Error(errorMessage)
+ }
+
+ const variableName = routePathToVariable(routePath)
+
+ const isLazy = routePath.endsWith('/lazy')
+
+ if (isLazy) {
+ routePath = routePath.replace(/\/lazy$/, '')
+ }
+
+ const isRoute = routePath.endsWith(`/${config.routeToken}`)
+ const isComponent = routePath.endsWith('/component')
+ const isErrorComponent = routePath.endsWith('/errorComponent')
+ const isPendingComponent = routePath.endsWith('/pendingComponent')
+ const isLoader = routePath.endsWith('/loader')
+ const isAPIRoute = routePath.startsWith(
+ `${removeTrailingSlash(config.apiBase)}/`,
+ )
+
+ const segments = routePath.split('/')
+ const lastRouteSegment = segments[segments.length - 1]
+ const isLayout =
+ (lastRouteSegment !== config.indexToken &&
+ lastRouteSegment !== config.routeToken &&
+ lastRouteSegment?.startsWith('_')) ||
+ false
+
+ ;(
+ [
+ [isComponent, 'component'],
+ [isErrorComponent, 'errorComponent'],
+ [isPendingComponent, 'pendingComponent'],
+ [isLoader, 'loader'],
+ ] as const
+ ).forEach(([isType, type]) => {
+ if (isType) {
+ logger.warn(
+ `WARNING: The \`.${type}.tsx\` suffix used for the ${filePath} file is deprecated. Use the new \`.lazy.tsx\` suffix instead.`,
+ )
+ }
+ })
+
+ routePath = routePath.replace(
+ new RegExp(
+ `/(component|errorComponent|pendingComponent|loader|${config.routeToken}|lazy)$`,
+ ),
+ '',
+ )
+
+ if (routePath === config.indexToken) {
+ routePath = '/'
+ }
+
+ routePath =
+ routePath.replace(new RegExp(`/${config.indexToken}$`), '/') || '/'
+
+ routeNodes.push({
+ filePath,
+ fullPath,
+ routePath,
+ variableName,
+ isRoute,
+ isComponent,
+ isErrorComponent,
+ isPendingComponent,
+ isLoader,
+ isLazy,
+ isLayout,
+ isAPIRoute,
+ })
+ }
+ }),
+ )
+
+ return routeNodes
+ }
+
+ await recurse('./')
+
+ const rootRouteNode = routeNodes.find((d) => d.routePath === `/${rootPathId}`)
+ return { rootRouteNode, routeNodes }
+}
diff --git a/packages/router-generator/src/filesystem/physical/rootPathId.ts b/packages/router-generator/src/filesystem/physical/rootPathId.ts
new file mode 100644
index 0000000000..bb97d05ce6
--- /dev/null
+++ b/packages/router-generator/src/filesystem/physical/rootPathId.ts
@@ -0,0 +1 @@
+export const rootPathId = '__root'
diff --git a/packages/router-generator/src/filesystem/virtual/config.ts b/packages/router-generator/src/filesystem/virtual/config.ts
new file mode 100644
index 0000000000..db54aa6611
--- /dev/null
+++ b/packages/router-generator/src/filesystem/virtual/config.ts
@@ -0,0 +1,45 @@
+import { z } from 'zod'
+import type {
+ LayoutRoute,
+ PhysicalSubtree,
+ Route,
+ VirtualRootRoute,
+} from '@tanstack/virtual-file-routes'
+
+const indexRouteSchema = z.object({
+ type: z.literal('index'),
+ file: z.string(),
+})
+
+const layoutRouteSchema: z.ZodType = z.object({
+ type: z.literal('layout'),
+ id: z.string(),
+ file: z.string(),
+ children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional(),
+})
+
+const routeSchema: z.ZodType = z.object({
+ type: z.literal('route'),
+ file: z.string(),
+ path: z.string(),
+ children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional(),
+})
+
+const physicalSubTreeSchema: z.ZodType = z.object({
+ type: z.literal('physical'),
+ directory: z.string(),
+ pathPrefix: z.string(),
+})
+
+const virtualRouteNodeSchema = z.union([
+ indexRouteSchema,
+ layoutRouteSchema,
+ routeSchema,
+ physicalSubTreeSchema,
+])
+
+export const virtualRootRouteSchema: z.ZodType = z.object({
+ type: z.literal('root'),
+ file: z.string(),
+ children: z.array(virtualRouteNodeSchema).optional(),
+})
diff --git a/packages/router-generator/src/filesystem/virtual/getRouteNodes.ts b/packages/router-generator/src/filesystem/virtual/getRouteNodes.ts
new file mode 100644
index 0000000000..acb5687cce
--- /dev/null
+++ b/packages/router-generator/src/filesystem/virtual/getRouteNodes.ts
@@ -0,0 +1,141 @@
+import { join, resolve } from 'node:path'
+import {
+ removeExt,
+ removeLeadingSlash,
+ removeTrailingSlash,
+ routePathToVariable,
+} from '../../utils'
+import { getRouteNodes as getRouteNodesPhysical } from '../physical/getRouteNodes'
+import type { VirtualRouteNode } from '@tanstack/virtual-file-routes'
+import type { GetRouteNodesResult, RouteNode } from '../../types'
+import type { Config } from '../../config'
+
+function ensureLeadingUnderScore(id: string) {
+ if (id.startsWith('_')) {
+ return id
+ }
+ return `_${id}`
+}
+
+function flattenTree(node: RouteNode): Array {
+ const result = [node]
+
+ if (node.children) {
+ for (const child of node.children) {
+ result.push(...flattenTree(child))
+ }
+ }
+ delete node.children
+
+ return result
+}
+
+export async function getRouteNodes(
+ tsrConfig: Config,
+): Promise {
+ const fullDir = resolve(tsrConfig.routesDirectory)
+ if (tsrConfig.virtualRouteConfig === undefined) {
+ throw new Error(`virtualRouteConfig is undefined`)
+ }
+ const children = await getRouteNodesRecursive(
+ tsrConfig,
+ fullDir,
+ tsrConfig.virtualRouteConfig.children,
+ )
+ const allNodes = flattenTree({
+ children,
+ filePath: tsrConfig.virtualRouteConfig.file,
+ fullPath: join(fullDir, tsrConfig.virtualRouteConfig.file),
+ variableName: 'rootRoute',
+ routePath: '/',
+ isRoot: true,
+ })
+
+ const rootRouteNode = allNodes[0]
+ const routeNodes = allNodes.slice(1)
+
+ return { rootRouteNode, routeNodes }
+}
+
+export async function getRouteNodesRecursive(
+ tsrConfig: Config,
+ fullDir: string,
+ nodes?: Array,
+ parent?: RouteNode,
+): Promise> {
+ if (nodes === undefined) {
+ return []
+ }
+ const children = await Promise.all(
+ nodes.map(async (node) => {
+ if (node.type === 'physical') {
+ const { routeNodes } = await getRouteNodesPhysical({
+ ...tsrConfig,
+ routesDirectory: resolve(fullDir, node.directory),
+ })
+ routeNodes.forEach((subtreeNode) => {
+ subtreeNode.variableName = routePathToVariable(
+ `${node.pathPrefix}/${removeExt(subtreeNode.filePath)}`,
+ )
+ subtreeNode.routePath = `${parent?.routePath ?? ''}${node.pathPrefix}${subtreeNode.routePath}`
+ subtreeNode.filePath = `${node.directory}/${subtreeNode.filePath}`
+ })
+ return routeNodes
+ }
+
+ const filePath = node.file
+ const variableName = routePathToVariable(removeExt(filePath))
+ const fullPath = join(fullDir, filePath)
+ const parentRoutePath = removeTrailingSlash(parent?.routePath ?? '/')
+ const isLayout = node.type === 'layout'
+ switch (node.type) {
+ case 'index': {
+ const routePath = `${parentRoutePath}/`
+ return {
+ filePath,
+ fullPath,
+ variableName,
+ routePath,
+ isLayout,
+ } satisfies RouteNode
+ }
+
+ case 'route':
+ case 'layout': {
+ let lastSegment: string
+ if (node.type === 'layout') {
+ if (node.id !== undefined) {
+ node.id = ensureLeadingUnderScore(node.id)
+ } else {
+ node.id = '_layout'
+ }
+ lastSegment = node.id
+ } else {
+ lastSegment = node.path
+ }
+ const routePath = `${parentRoutePath}/${removeLeadingSlash(lastSegment)}`
+
+ const routeNode: RouteNode = {
+ fullPath,
+ isLayout,
+ filePath,
+ variableName,
+ routePath,
+ }
+
+ if (node.children !== undefined) {
+ const children = await getRouteNodesRecursive(
+ tsrConfig,
+ fullDir,
+ node.children,
+ routeNode,
+ )
+ routeNode.children = children
+ }
+ return routeNode
+ }
+ }
+ }),
+ )
+ return children.flat()
+}
diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts
index 02ed118930..d91e561a13 100644
--- a/packages/router-generator/src/generator.ts
+++ b/packages/router-generator/src/generator.ts
@@ -2,175 +2,25 @@ import path from 'node:path'
import * as fs from 'node:fs'
import * as fsp from 'node:fs/promises'
import * as prettier from 'prettier'
-import { cleanPath, logging, trimPathLeft } from './utils'
+import {
+ determineInitialRoutePath,
+ logging,
+ removeExt,
+ removeTrailingSlash,
+ removeUnderscores,
+ replaceBackslash,
+ routePathToVariable,
+ trimPathLeft,
+} from './utils'
+import { getRouteNodes as physicalGetRouteNodes } from './filesystem/physical/getRouteNodes'
+import { getRouteNodes as virtualGetRouteNodes } from './filesystem/virtual/getRouteNodes'
+import { rootPathId } from './filesystem/physical/rootPathId'
+import type { GetRouteNodesResult, RouteNode } from './types'
import type { Config } from './config'
let latestTask = 0
-export const rootPathId = '__root'
const routeGroupPatternRegex = /\(.+\)/g
const possiblyNestedRouteGroupPatternRegex = /\([^/]+\)\/?/g
-const disallowedRouteGroupConfiguration = /\(([^)]+)\).(ts|js|tsx|jsx)/
-
-export type RouteNode = {
- filePath: string
- fullPath: string
- variableName: string
- routePath?: string
- cleanedPath?: string
- path?: string
- isNonPath?: boolean
- isNonLayout?: boolean
- isLayout?: boolean
- isVirtualParentRequired?: boolean
- isVirtualParentRoute?: boolean
- isRoute?: boolean
- isAPIRoute?: boolean
- isLoader?: boolean
- isComponent?: boolean
- isErrorComponent?: boolean
- isPendingComponent?: boolean
- isVirtual?: boolean
- isLazy?: boolean
- isRoot?: boolean
- children?: Array
- parent?: RouteNode
-}
-
-async function getRouteNodes(config: Config) {
- const { routeFilePrefix, routeFileIgnorePrefix, routeFileIgnorePattern } =
- config
- const logger = logging({ disabled: config.disableLogging })
- const routeFileIgnoreRegExp = new RegExp(routeFileIgnorePattern ?? '', 'g')
-
- const routeNodes: Array = []
-
- async function recurse(dir: string) {
- const fullDir = path.resolve(config.routesDirectory, dir)
- let dirList = await fsp.readdir(fullDir, { withFileTypes: true })
-
- dirList = dirList.filter((d) => {
- if (
- d.name.startsWith('.') ||
- (routeFileIgnorePrefix && d.name.startsWith(routeFileIgnorePrefix))
- ) {
- return false
- }
-
- if (routeFilePrefix) {
- return d.name.startsWith(routeFilePrefix)
- }
-
- if (routeFileIgnorePattern) {
- return !d.name.match(routeFileIgnoreRegExp)
- }
-
- return true
- })
-
- await Promise.all(
- dirList.map(async (dirent) => {
- const fullPath = path.join(fullDir, dirent.name)
- const relativePath = path.join(dir, dirent.name)
-
- if (dirent.isDirectory()) {
- await recurse(relativePath)
- } else if (fullPath.match(/\.(tsx|ts|jsx|js)$/)) {
- const filePath = replaceBackslash(path.join(dir, dirent.name))
- const filePathNoExt = removeExt(filePath)
- let routePath = determineInitialRoutePath(filePathNoExt)
-
- if (routeFilePrefix) {
- routePath = routePath.replaceAll(routeFilePrefix, '')
- }
-
- if (disallowedRouteGroupConfiguration.test(dirent.name)) {
- const errorMessage = `A route configuration for a route group was found at \`${filePath}\`. This is not supported. Did you mean to use a layout/pathless route instead?`
- logger.error(`ERROR: ${errorMessage}`)
- throw new Error(errorMessage)
- }
-
- const variableName = routePathToVariable(routePath)
-
- // Remove the index from the route path and
- // if the route path is empty, use `/'
-
- const isLazy = routePath.endsWith('/lazy')
-
- if (isLazy) {
- routePath = routePath.replace(/\/lazy$/, '')
- }
-
- const isRoute = routePath.endsWith(`/${config.routeToken}`)
- const isComponent = routePath.endsWith('/component')
- const isErrorComponent = routePath.endsWith('/errorComponent')
- const isPendingComponent = routePath.endsWith('/pendingComponent')
- const isLoader = routePath.endsWith('/loader')
- const isAPIRoute = routePath.startsWith(
- `${removeTrailingSlash(config.apiBase)}/`,
- )
-
- const segments = routePath.split('/')
- const lastRouteSegment = segments[segments.length - 1]
- const isLayout =
- (lastRouteSegment !== config.indexToken &&
- lastRouteSegment !== config.routeToken &&
- lastRouteSegment?.startsWith('_')) ||
- false
-
- ;(
- [
- [isComponent, 'component'],
- [isErrorComponent, 'errorComponent'],
- [isPendingComponent, 'pendingComponent'],
- [isLoader, 'loader'],
- ] as const
- ).forEach(([isType, type]) => {
- if (isType) {
- logger.warn(
- `WARNING: The \`.${type}.tsx\` suffix used for the ${filePath} file is deprecated. Use the new \`.lazy.tsx\` suffix instead.`,
- )
- }
- })
-
- routePath = routePath.replace(
- new RegExp(
- `/(component|errorComponent|pendingComponent|loader|${config.routeToken}|lazy)$`,
- ),
- '',
- )
-
- if (routePath === config.indexToken) {
- routePath = '/'
- }
-
- routePath =
- routePath.replace(new RegExp(`/${config.indexToken}$`), '/') || '/'
-
- routeNodes.push({
- filePath,
- fullPath,
- routePath,
- variableName,
- isRoute,
- isComponent,
- isErrorComponent,
- isPendingComponent,
- isLoader,
- isLazy,
- isLayout,
- isAPIRoute,
- })
- }
- }),
- )
-
- return routeNodes
- }
-
- await recurse('./')
-
- return routeNodes
-}
let isFirst = false
let skipMessage = false
@@ -216,12 +66,18 @@ export async function generator(config: Config) {
parser: 'typescript',
}
- const routePathIdPrefix = config.routeFilePrefix ?? ''
- const beforeRouteNodes = await getRouteNodes(config)
- const rootRouteNode = beforeRouteNodes.find(
- (d) => d.routePath === `/${rootPathId}`,
- )
+ let getRouteNodesResult: GetRouteNodesResult
+
+ if (config.virtualRouteConfig) {
+ getRouteNodesResult = await virtualGetRouteNodes(config)
+ } else {
+ getRouteNodesResult = await physicalGetRouteNodes(config)
+ }
+ const { rootRouteNode, routeNodes: beforeRouteNodes } = getRouteNodesResult
+ if (rootRouteNode === undefined) {
+ throw new Error(`rootRouteNode must not be undefined`)
+ }
const preRouteNodes = multiSortBy(beforeRouteNodes, [
(d) => (d.routePath === '/' ? -1 : 1),
(d) => d.routePath?.split('/').length,
@@ -307,13 +163,11 @@ export const Route = createRootRoute({
const trimmedPath = trimPathLeft(node.path ?? '')
const split = trimmedPath.split('/')
- const first = split[0] ?? trimmedPath
const lastRouteSegment = split[split.length - 1] ?? trimmedPath
node.isNonPath =
lastRouteSegment.startsWith('_') ||
routeGroupPatternRegex.test(lastRouteSegment)
- node.isNonLayout = first.endsWith('_')
node.cleanedPath = removeGroups(
removeUnderscores(removeLayoutSegments(node.path)) ?? '',
@@ -571,11 +425,18 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
.map((d) => d[0])
const virtualRouteNodes = sortedRouteNodes.filter((d) => d.isVirtual)
- const rootPathIdExtension =
- config.addExtensions && rootRouteNode
- ? path.extname(rootRouteNode.filePath)
- : ''
+ function getImportPath(node: RouteNode) {
+ return replaceBackslash(
+ removeExt(
+ path.relative(
+ path.dirname(config.generatedRouteTree),
+ path.resolve(config.routesDirectory, node.filePath),
+ ),
+ config.addExtensions,
+ ),
+ )
+ }
const routeImports = [
...config.routeTreeFileHeader,
'// This file is auto-generated by TanStack Router',
@@ -584,29 +445,13 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
: '',
'// Import Routes',
[
- `import { Route as rootRoute } from './${replaceBackslash(
- path.relative(
- path.dirname(config.generatedRouteTree),
- path.resolve(
- config.routesDirectory,
- `${routePathIdPrefix}${rootPathId}${rootPathIdExtension}`,
- ),
- ),
- )}'`,
+ `import { Route as rootRoute } from './${getImportPath(rootRouteNode)}'`,
...sortedRouteNodes
.filter((d) => !d.isVirtual)
.map((node) => {
return `import { Route as ${
node.variableName
- }Import } from './${replaceBackslash(
- removeExt(
- path.relative(
- path.dirname(config.generatedRouteTree),
- path.resolve(config.routesDirectory, node.filePath),
- ),
- config.addExtensions,
- ),
- )}'`
+ }Import } from './${getImportPath(node)}'`
}),
].join('\n'),
virtualRouteNodes.length ? '// Create Virtual Routes' : '',
@@ -704,7 +549,7 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
${routeNodes
.map((routeNode) => {
const [filePathId, routeId] = getFilePathIdAndRouteIdFromPath(
- routeNode.routePath!,
+ routeNode.routePath,
)
return `'${filePathId}': {
@@ -735,14 +580,14 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
const createRouteManifest = () => {
const routesManifest = {
__root__: {
- filePath: rootRouteNode?.filePath,
+ filePath: rootRouteNode.filePath,
children: routeTree.map(
- (d) => getFilePathIdAndRouteIdFromPath(d.routePath!)[1],
+ (d) => getFilePathIdAndRouteIdFromPath(d.routePath)[1],
),
},
...Object.fromEntries(
routeNodes.map((d) => {
- const [_, routeId] = getFilePathIdAndRouteIdFromPath(d.routePath!)
+ const [_, routeId] = getFilePathIdAndRouteIdFromPath(d.routePath)
return [
routeId,
@@ -753,7 +598,7 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
: undefined,
children: d.children?.map(
(childRoute) =>
- getFilePathIdAndRouteIdFromPath(childRoute.routePath!)[1],
+ getFilePathIdAndRouteIdFromPath(childRoute.routePath)[1],
),
},
]
@@ -820,24 +665,6 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
)
}
-function routePathToVariable(routePath: string): string {
- return (
- removeUnderscores(routePath)
- ?.replace(/\/\$\//g, '/splat/')
- .replace(/\$$/g, 'splat')
- .replace(/\$/g, '')
- .split(/[/-]/g)
- .map((d, i) => (i > 0 ? capitalize(d) : d))
- .join('')
- .replace(/([^a-zA-Z0-9]|[.])/gm, '')
- .replace(/^(\d)/g, 'R$1') ?? ''
- )
-}
-
-export function removeExt(d: string, keepExtension: boolean = false) {
- return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d
-}
-
function spaces(d: number): string {
return Array.from({ length: d })
.map(() => ' ')
@@ -874,35 +701,14 @@ export function multiSortBy(
.map(([d]) => d)
}
-function capitalize(s: string) {
- if (typeof s !== 'string') return ''
- return s.charAt(0).toUpperCase() + s.slice(1)
-}
-
-function removeUnderscores(s?: string) {
- return s?.replaceAll(/(^_|_$)/gi, '').replaceAll(/(\/_|_\/)/gi, '/')
-}
-
function removeTrailingUnderscores(s?: string) {
return s?.replaceAll(/(_$)/gi, '').replaceAll(/(_\/)/gi, '/')
}
-function replaceBackslash(s: string) {
- return s.replaceAll(/\\/gi, '/')
-}
-
function removeGroups(s: string) {
return s.replace(possiblyNestedRouteGroupPatternRegex, '')
}
-function removeTrailingSlash(s: string) {
- return s.replace(/\/$/, '')
-}
-
-function determineInitialRoutePath(routePath: string) {
- return cleanPath(`/${routePath.split('.').join('/')}`) || ''
-}
-
/**
* The `node.path` is used as the `id` in the route definition.
* This function checks if the given node has a parent and if so, it determines the correct path for the given node.
@@ -911,7 +717,7 @@ function determineInitialRoutePath(routePath: string) {
*/
function determineNodePath(node: RouteNode) {
return (node.path = node.parent
- ? node.routePath?.replace(node.parent.routePath!, '') || '/'
+ ? node.routePath?.replace(node.parent.routePath ?? '', '') || '/'
: node.routePath)
}
@@ -995,7 +801,7 @@ export const inferPath = (routeNode: RouteNode): string => {
: (routeNode.cleanedPath?.replace(/\/$/, '') ?? '')
}
-function getFilePathIdAndRouteIdFromPath(pathname: string) {
+function getFilePathIdAndRouteIdFromPath(pathname?: string) {
const filePathId = removeTrailingUnderscores(pathname)
const id = removeGroups(filePathId ?? '')
diff --git a/packages/router-generator/src/types.ts b/packages/router-generator/src/types.ts
new file mode 100644
index 0000000000..cf1b7ee9e2
--- /dev/null
+++ b/packages/router-generator/src/types.ts
@@ -0,0 +1,28 @@
+export type RouteNode = {
+ filePath: string
+ fullPath: string
+ variableName: string
+ routePath?: string
+ cleanedPath?: string
+ path?: string
+ isNonPath?: boolean
+ isLayout?: boolean
+ isVirtualParentRequired?: boolean
+ isVirtualParentRoute?: boolean
+ isRoute?: boolean
+ isAPIRoute?: boolean
+ isLoader?: boolean
+ isComponent?: boolean
+ isErrorComponent?: boolean
+ isPendingComponent?: boolean
+ isVirtual?: boolean
+ isLazy?: boolean
+ isRoot?: boolean
+ children?: Array
+ parent?: RouteNode
+}
+
+export interface GetRouteNodesResult {
+ rootRouteNode?: RouteNode
+ routeNodes: Array
+}
diff --git a/packages/router-generator/src/utils.ts b/packages/router-generator/src/utils.ts
index 5a57168353..ffcac863fa 100644
--- a/packages/router-generator/src/utils.ts
+++ b/packages/router-generator/src/utils.ts
@@ -26,3 +26,46 @@ export function logging(config: { disabled: boolean }) {
},
}
}
+
+export function removeLeadingSlash(path: string): string {
+ return path.replace(/^\//, '')
+}
+
+export function removeTrailingSlash(s: string) {
+ return s.replace(/\/$/, '')
+}
+
+export function determineInitialRoutePath(routePath: string) {
+ return cleanPath(`/${routePath.split('.').join('/')}`) || ''
+}
+
+export function replaceBackslash(s: string) {
+ return s.replaceAll(/\\/gi, '/')
+}
+
+export function routePathToVariable(routePath: string): string {
+ return (
+ removeUnderscores(routePath)
+ ?.replace(/\/\$\//g, '/splat/')
+ .replace(/\$$/g, 'splat')
+ .replace(/\$/g, '')
+ .split(/[/-]/g)
+ .map((d, i) => (i > 0 ? capitalize(d) : d))
+ .join('')
+ .replace(/([^a-zA-Z0-9]|[.])/gm, '')
+ .replace(/^(\d)/g, 'R$1') ?? ''
+ )
+}
+
+export function removeUnderscores(s?: string) {
+ return s?.replaceAll(/(^_|_$)/gi, '').replaceAll(/(\/_|_\/)/gi, '/')
+}
+
+export function capitalize(s: string) {
+ if (typeof s !== 'string') return ''
+ return s.charAt(0).toUpperCase() + s.slice(1)
+}
+
+export function removeExt(d: string, keepExtension: boolean = false) {
+ return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d
+}
diff --git a/packages/router-generator/tests/generator.test.ts b/packages/router-generator/tests/generator.test.ts
index a0cc942745..b16745e174 100644
--- a/packages/router-generator/tests/generator.test.ts
+++ b/packages/router-generator/tests/generator.test.ts
@@ -2,6 +2,13 @@ import fs from 'node:fs/promises'
import { join } from 'node:path'
import { describe, expect, it } from 'vitest'
+import {
+ index,
+ layout,
+ physical,
+ rootRoute,
+ route,
+} from '@tanstack/virtual-file-routes'
import { generator, getConfig } from '../src'
import type { Config } from '../src'
@@ -51,6 +58,24 @@ function rewriteConfigByFolderName(folderName: string, config: Config) {
config.indexToken = '_1nd3x'
config.routeToken = '_r0ut3_'
break
+ case 'virtual':
+ {
+ const virtualRouteConfig = rootRoute('root.tsx', [
+ index('index.tsx'),
+ layout('layout.tsx', [
+ route('/dashboard', 'db/dashboard.tsx', [
+ index('db/dashboard-index.tsx'),
+ route('/invoices', 'db/dashboard-invoices.tsx', [
+ index('db/invoices-index.tsx'),
+ route('$id', 'db/invoice-detail.tsx'),
+ ]),
+ ]),
+ physical('/hello', 'subtree'),
+ ]),
+ ])
+ config.virtualRouteConfig = virtualRouteConfig
+ }
+ break
default:
break
}
diff --git a/packages/router-generator/tests/generator/virtual/routeTree.snapshot.ts b/packages/router-generator/tests/generator/virtual/routeTree.snapshot.ts
new file mode 100644
index 0000000000..cbc5660e20
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual/routeTree.snapshot.ts
@@ -0,0 +1,238 @@
+/* prettier-ignore-start */
+
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file is auto-generated by TanStack Router
+
+// Import Routes
+
+import { Route as rootRoute } from './routes/root'
+import { Route as layoutImport } from './routes/layout'
+import { Route as indexImport } from './routes/index'
+import { Route as dbDashboardImport } from './routes/db/dashboard'
+import { Route as HelloIndexImport } from './routes/subtree/index'
+import { Route as dbDashboardInvoicesImport } from './routes/db/dashboard-invoices'
+import { Route as dbDashboardIndexImport } from './routes/db/dashboard-index'
+import { Route as HelloFooIndexImport } from './routes/subtree/foo/index'
+import { Route as HelloFooIdImport } from './routes/subtree/foo/$id'
+import { Route as dbInvoiceDetailImport } from './routes/db/invoice-detail'
+import { Route as dbInvoicesIndexImport } from './routes/db/invoices-index'
+
+// Create/Update Routes
+
+const layoutRoute = layoutImport.update({
+ id: '/_layout',
+ getParentRoute: () => rootRoute,
+} as any)
+
+const indexRoute = indexImport.update({
+ path: '/',
+ getParentRoute: () => rootRoute,
+} as any)
+
+const dbDashboardRoute = dbDashboardImport.update({
+ path: '/dashboard',
+ getParentRoute: () => layoutRoute,
+} as any)
+
+const HelloIndexRoute = HelloIndexImport.update({
+ path: '/hello/',
+ getParentRoute: () => layoutRoute,
+} as any)
+
+const dbDashboardInvoicesRoute = dbDashboardInvoicesImport.update({
+ path: '/invoices',
+ getParentRoute: () => dbDashboardRoute,
+} as any)
+
+const dbDashboardIndexRoute = dbDashboardIndexImport.update({
+ path: '/',
+ getParentRoute: () => dbDashboardRoute,
+} as any)
+
+const HelloFooIndexRoute = HelloFooIndexImport.update({
+ path: '/hello/foo/',
+ getParentRoute: () => layoutRoute,
+} as any)
+
+const HelloFooIdRoute = HelloFooIdImport.update({
+ path: '/hello/foo/$id',
+ getParentRoute: () => layoutRoute,
+} as any)
+
+const dbInvoiceDetailRoute = dbInvoiceDetailImport.update({
+ path: '/$id',
+ getParentRoute: () => dbDashboardInvoicesRoute,
+} as any)
+
+const dbInvoicesIndexRoute = dbInvoicesIndexImport.update({
+ path: '/',
+ getParentRoute: () => dbDashboardInvoicesRoute,
+} as any)
+
+// Populate the FileRoutesByPath interface
+
+declare module '@tanstack/react-router' {
+ interface FileRoutesByPath {
+ '/': {
+ id: '/'
+ path: '/'
+ fullPath: '/'
+ preLoaderRoute: typeof indexImport
+ parentRoute: typeof rootRoute
+ }
+ '/_layout': {
+ id: '/_layout'
+ path: ''
+ fullPath: ''
+ preLoaderRoute: typeof layoutImport
+ parentRoute: typeof rootRoute
+ }
+ '/_layout/dashboard': {
+ id: '/_layout/dashboard'
+ path: '/dashboard'
+ fullPath: '/dashboard'
+ preLoaderRoute: typeof dbDashboardImport
+ parentRoute: typeof layoutImport
+ }
+ '/_layout/dashboard/': {
+ id: '/_layout/dashboard/'
+ path: '/'
+ fullPath: '/dashboard/'
+ preLoaderRoute: typeof dbDashboardIndexImport
+ parentRoute: typeof dbDashboardImport
+ }
+ '/_layout/dashboard/invoices': {
+ id: '/_layout/dashboard/invoices'
+ path: '/invoices'
+ fullPath: '/dashboard/invoices'
+ preLoaderRoute: typeof dbDashboardInvoicesImport
+ parentRoute: typeof dbDashboardImport
+ }
+ '/_layout/hello/': {
+ id: '/_layout/hello/'
+ path: '/hello'
+ fullPath: '/hello'
+ preLoaderRoute: typeof HelloIndexImport
+ parentRoute: typeof layoutImport
+ }
+ '/_layout/dashboard/invoices/': {
+ id: '/_layout/dashboard/invoices/'
+ path: '/'
+ fullPath: '/dashboard/invoices/'
+ preLoaderRoute: typeof dbInvoicesIndexImport
+ parentRoute: typeof dbDashboardInvoicesImport
+ }
+ '/_layout/dashboard/invoices/$id': {
+ id: '/_layout/dashboard/invoices/$id'
+ path: '/$id'
+ fullPath: '/dashboard/invoices/$id'
+ preLoaderRoute: typeof dbInvoiceDetailImport
+ parentRoute: typeof dbDashboardInvoicesImport
+ }
+ '/_layout/hello/foo/$id': {
+ id: '/_layout/hello/foo/$id'
+ path: '/hello/foo/$id'
+ fullPath: '/hello/foo/$id'
+ preLoaderRoute: typeof HelloFooIdImport
+ parentRoute: typeof layoutImport
+ }
+ '/_layout/hello/foo/': {
+ id: '/_layout/hello/foo/'
+ path: '/hello/foo'
+ fullPath: '/hello/foo'
+ preLoaderRoute: typeof HelloFooIndexImport
+ parentRoute: typeof layoutImport
+ }
+ }
+}
+
+// Create and export the route tree
+
+export const routeTree = rootRoute.addChildren({
+ indexRoute,
+ layoutRoute: layoutRoute.addChildren({
+ dbDashboardRoute: dbDashboardRoute.addChildren({
+ dbDashboardIndexRoute,
+ dbDashboardInvoicesRoute: dbDashboardInvoicesRoute.addChildren({
+ dbInvoicesIndexRoute,
+ dbInvoiceDetailRoute,
+ }),
+ }),
+ HelloIndexRoute,
+ HelloFooIdRoute,
+ HelloFooIndexRoute,
+ }),
+})
+
+/* prettier-ignore-end */
+
+/* ROUTE_MANIFEST_START
+{
+ "routes": {
+ "__root__": {
+ "filePath": "root.tsx",
+ "children": [
+ "/",
+ "/_layout"
+ ]
+ },
+ "/": {
+ "filePath": "index.tsx"
+ },
+ "/_layout": {
+ "filePath": "layout.tsx",
+ "children": [
+ "/_layout/dashboard",
+ "/_layout/hello/",
+ "/_layout/hello/foo/$id",
+ "/_layout/hello/foo/"
+ ]
+ },
+ "/_layout/dashboard": {
+ "filePath": "db/dashboard.tsx",
+ "parent": "/_layout",
+ "children": [
+ "/_layout/dashboard/",
+ "/_layout/dashboard/invoices"
+ ]
+ },
+ "/_layout/dashboard/": {
+ "filePath": "db/dashboard-index.tsx",
+ "parent": "/_layout/dashboard"
+ },
+ "/_layout/dashboard/invoices": {
+ "filePath": "db/dashboard-invoices.tsx",
+ "parent": "/_layout/dashboard",
+ "children": [
+ "/_layout/dashboard/invoices/",
+ "/_layout/dashboard/invoices/$id"
+ ]
+ },
+ "/_layout/hello/": {
+ "filePath": "subtree/index.tsx",
+ "parent": "/_layout"
+ },
+ "/_layout/dashboard/invoices/": {
+ "filePath": "db/invoices-index.tsx",
+ "parent": "/_layout/dashboard/invoices"
+ },
+ "/_layout/dashboard/invoices/$id": {
+ "filePath": "db/invoice-detail.tsx",
+ "parent": "/_layout/dashboard/invoices"
+ },
+ "/_layout/hello/foo/$id": {
+ "filePath": "subtree/foo/$id.tsx",
+ "parent": "/_layout"
+ },
+ "/_layout/hello/foo/": {
+ "filePath": "subtree/foo/index.tsx",
+ "parent": "/_layout"
+ }
+ }
+}
+ROUTE_MANIFEST_END */
diff --git a/packages/router-generator/tests/generator/virtual/routes/db/dashboard-index.tsx b/packages/router-generator/tests/generator/virtual/routes/db/dashboard-index.tsx
new file mode 100644
index 0000000000..a92fc772c3
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual/routes/db/dashboard-index.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_layout/dashboard/')({
+ component: () => Hello !
,
+})
diff --git a/packages/router-generator/tests/generator/virtual/routes/db/dashboard-invoices.tsx b/packages/router-generator/tests/generator/virtual/routes/db/dashboard-invoices.tsx
new file mode 100644
index 0000000000..bf7e5a02b2
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual/routes/db/dashboard-invoices.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_layout/dashboard/invoices')({
+ component: () => Hello !
,
+})
diff --git a/packages/router-generator/tests/generator/virtual/routes/db/dashboard.tsx b/packages/router-generator/tests/generator/virtual/routes/db/dashboard.tsx
new file mode 100644
index 0000000000..d5b4f49706
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual/routes/db/dashboard.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_layout/dashboard')({
+ component: () => Hello !
,
+})
diff --git a/packages/router-generator/tests/generator/virtual/routes/db/invoice-detail.tsx b/packages/router-generator/tests/generator/virtual/routes/db/invoice-detail.tsx
new file mode 100644
index 0000000000..e7be6c1910
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual/routes/db/invoice-detail.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_layout/dashboard/invoices/$id')({
+ component: () => Hello /_layout/dashboard/invoices/$id!
,
+})
diff --git a/packages/router-generator/tests/generator/virtual/routes/db/invoices-index.tsx b/packages/router-generator/tests/generator/virtual/routes/db/invoices-index.tsx
new file mode 100644
index 0000000000..f2e56721b6
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual/routes/db/invoices-index.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_layout/dashboard/invoices/')({
+ component: () => Hello /_layout/dashboard/invoices/!
,
+})
diff --git a/packages/router-generator/tests/generator/virtual/routes/index.tsx b/packages/router-generator/tests/generator/virtual/routes/index.tsx
new file mode 100644
index 0000000000..a294139860
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual/routes/index.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/')({
+ component: () => Hello !
,
+})
diff --git a/packages/router-generator/tests/generator/virtual/routes/layout.tsx b/packages/router-generator/tests/generator/virtual/routes/layout.tsx
new file mode 100644
index 0000000000..2e48e48410
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual/routes/layout.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_layout')({
+ component: () => Hello !
,
+})
diff --git a/packages/router-generator/tests/generator/virtual/routes/root.tsx b/packages/router-generator/tests/generator/virtual/routes/root.tsx
new file mode 100644
index 0000000000..3ae2044956
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual/routes/root.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/root')({
+ component: () => Hello !
,
+})
diff --git a/packages/router-generator/tests/generator/virtual/routes/subtree/foo/$id.tsx b/packages/router-generator/tests/generator/virtual/routes/subtree/foo/$id.tsx
new file mode 100644
index 0000000000..d8cbd795a7
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual/routes/subtree/foo/$id.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_layout/hello/foo/$id')({
+ component: () => Hello /foo/$id!
,
+})
diff --git a/packages/router-generator/tests/generator/virtual/routes/subtree/foo/index.tsx b/packages/router-generator/tests/generator/virtual/routes/subtree/foo/index.tsx
new file mode 100644
index 0000000000..10233de496
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual/routes/subtree/foo/index.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_layout/hello/foo/')({
+ component: () => Hello /foo/!
,
+})
diff --git a/packages/router-generator/tests/generator/virtual/routes/subtree/index.tsx b/packages/router-generator/tests/generator/virtual/routes/subtree/index.tsx
new file mode 100644
index 0000000000..3367799b96
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual/routes/subtree/index.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_layout/hello/')({
+ component: () => Hello /!
,
+})
diff --git a/packages/router-plugin/package.json b/packages/router-plugin/package.json
index 776a2c63fd..c0dfb38486 100644
--- a/packages/router-plugin/package.json
+++ b/packages/router-plugin/package.json
@@ -101,6 +101,7 @@
"@babel/traverse": "^7.25.3",
"@babel/types": "^7.25.2",
"@tanstack/router-generator": "workspace:^",
+ "@tanstack/virtual-file-routes": "workspace:^",
"@types/babel__core": "^7.20.5",
"@types/babel__generator": "^7.6.8",
"@types/babel__template": "^7.4.4",
diff --git a/packages/virtual-file-routes/eslint.config.js b/packages/virtual-file-routes/eslint.config.js
new file mode 100644
index 0000000000..8ce6ad05fc
--- /dev/null
+++ b/packages/virtual-file-routes/eslint.config.js
@@ -0,0 +1,5 @@
+// @ts-check
+
+import rootConfig from '../../eslint.config.js'
+
+export default [...rootConfig]
diff --git a/packages/virtual-file-routes/package.json b/packages/virtual-file-routes/package.json
new file mode 100644
index 0000000000..8c98be8ddd
--- /dev/null
+++ b/packages/virtual-file-routes/package.json
@@ -0,0 +1,57 @@
+{
+ "name": "@tanstack/virtual-file-routes",
+ "version": "1.52.5",
+ "description": "Modern and scalable routing for React applications",
+ "author": "Tanner Linsley",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/TanStack/router.git",
+ "directory": "packages/virtual-file-routes"
+ },
+ "homepage": "https://tanstack.com/router",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "keywords": [
+ "react",
+ "location",
+ "router",
+ "routing",
+ "async",
+ "async router",
+ "typescript"
+ ],
+ "scripts": {
+ "clean": "rimraf ./dist && rimraf ./coverage",
+ "test:eslint": "eslint ./src",
+ "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .",
+ "build": "vite build"
+ },
+ "type": "module",
+ "types": "dist/esm/index.d.ts",
+ "main": "dist/cjs/index.cjs",
+ "module": "dist/esm/index.js",
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./dist/esm/index.d.ts",
+ "default": "./dist/esm/index.js"
+ },
+ "require": {
+ "types": "./dist/cjs/index.d.cts",
+ "default": "./dist/cjs/index.cjs"
+ }
+ },
+ "./package.json": "./package.json"
+ },
+ "sideEffects": false,
+ "files": [
+ "dist",
+ "src"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+}
diff --git a/packages/virtual-file-routes/src/api.ts b/packages/virtual-file-routes/src/api.ts
new file mode 100644
index 0000000000..d52f01c9ca
--- /dev/null
+++ b/packages/virtual-file-routes/src/api.ts
@@ -0,0 +1,81 @@
+import type {
+ IndexRoute,
+ LayoutRoute,
+ PhysicalSubtree,
+ Route,
+ VirtualRootRoute,
+ VirtualRouteNode,
+} from './types'
+
+export function rootRoute(
+ file: string,
+ children?: Array,
+): VirtualRootRoute {
+ return {
+ type: 'root',
+ file,
+ children,
+ }
+}
+
+export function index(file: string): IndexRoute {
+ return {
+ type: 'index',
+ file,
+ }
+}
+
+export function layout(
+ file: string,
+ children: Array,
+): LayoutRoute
+export function layout(
+ id: string,
+ file: string,
+ children: Array,
+): LayoutRoute
+
+export function layout(
+ idOrFile: string,
+ fileOrChildren: string | Array,
+ children?: Array,
+): LayoutRoute {
+ if (Array.isArray(fileOrChildren)) {
+ return {
+ type: 'layout',
+ file: idOrFile,
+ children: fileOrChildren,
+ }
+ } else {
+ return {
+ type: 'layout',
+ id: idOrFile,
+ file: fileOrChildren,
+ children,
+ }
+ }
+}
+
+export function route(
+ path: string,
+ file: string,
+ children?: Array,
+): Route {
+ return {
+ type: 'route',
+ file,
+ path,
+ children,
+ }
+}
+
+export function physical(
+ pathPrefix: string,
+ directory: string,
+): PhysicalSubtree {
+ return {
+ type: 'physical',
+ directory,
+ pathPrefix,
+ }
+}
diff --git a/packages/virtual-file-routes/src/index.ts b/packages/virtual-file-routes/src/index.ts
new file mode 100644
index 0000000000..45e3c6b4c0
--- /dev/null
+++ b/packages/virtual-file-routes/src/index.ts
@@ -0,0 +1,9 @@
+export { rootRoute, index, route, layout, physical } from './api'
+export type {
+ LayoutRoute,
+ Route,
+ IndexRoute,
+ PhysicalSubtree,
+ VirtualRootRoute,
+ VirtualRouteNode,
+} from './types'
diff --git a/packages/virtual-file-routes/src/types.ts b/packages/virtual-file-routes/src/types.ts
new file mode 100644
index 0000000000..7797e936e6
--- /dev/null
+++ b/packages/virtual-file-routes/src/types.ts
@@ -0,0 +1,35 @@
+export type IndexRoute = {
+ type: 'index'
+ file: string
+}
+
+export type LayoutRoute = {
+ type: 'layout'
+ id?: string
+ file: string
+ children?: Array
+}
+
+export type PhysicalSubtree = {
+ type: 'physical'
+ directory: string
+ pathPrefix: string
+}
+
+export type Route = {
+ type: 'route'
+ file: string
+ path: string
+ children?: Array
+}
+export type VirtualRouteNode =
+ | IndexRoute
+ | LayoutRoute
+ | Route
+ | PhysicalSubtree
+
+export type VirtualRootRoute = {
+ type: 'root'
+ file: string
+ children?: Array
+}
diff --git a/packages/virtual-file-routes/tsconfig.json b/packages/virtual-file-routes/tsconfig.json
new file mode 100644
index 0000000000..041d9fe354
--- /dev/null
+++ b/packages/virtual-file-routes/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "jsx": "react-jsx"
+ },
+ "include": ["src", "tests", "vite.config.ts"]
+}
diff --git a/packages/virtual-file-routes/vite.config.ts b/packages/virtual-file-routes/vite.config.ts
new file mode 100644
index 0000000000..5edc0264cb
--- /dev/null
+++ b/packages/virtual-file-routes/vite.config.ts
@@ -0,0 +1,21 @@
+import { defineConfig, mergeConfig } from 'vitest/config'
+import { tanstackViteConfig } from '@tanstack/config/vite'
+import packageJson from './package.json'
+
+const config = defineConfig({
+ test: {
+ name: packageJson.name,
+ dir: './tests',
+ watch: false,
+ environment: 'jsdom',
+ typecheck: { enabled: true },
+ },
+})
+
+export default mergeConfig(
+ config,
+ tanstackViteConfig({
+ entry: './src/index.ts',
+ srcDir: './src',
+ }),
+)
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9923c81506..9d0c0a5030 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -13,6 +13,7 @@ overrides:
'@tanstack/router-cli': workspace:*
'@tanstack/router-devtools': workspace:*
'@tanstack/router-generator': workspace:*
+ '@tanstack/virtual-file-routes': workspace:*
'@tanstack/router-plugin': workspace:*
'@tanstack/router-vite-plugin': workspace:*
'@tanstack/react-router-with-query': workspace:*
@@ -63,7 +64,7 @@ importers:
version: 25.0.0
nx:
specifier: ^19.5.6
- version: 19.5.6(@swc/core@1.7.6)
+ version: 19.5.6(@swc/core@1.7.6(@swc/helpers@0.5.12))
prettier:
specifier: ^3.3.3
version: 3.3.3
@@ -521,6 +522,52 @@ importers:
specifier: ^1.2.0
version: 1.2.0(@babel/core@7.25.2)(vite@5.3.5(@types/node@20.14.9)(terser@5.31.1))
+ examples/react/basic-virtual-file-based:
+ dependencies:
+ '@tanstack/react-router':
+ specifier: workspace:*
+ version: link:../../../packages/react-router
+ '@tanstack/router-devtools':
+ specifier: workspace:*
+ version: link:../../../packages/router-devtools
+ '@tanstack/router-plugin':
+ specifier: workspace:*
+ version: link:../../../packages/router-plugin
+ '@tanstack/virtual-file-routes':
+ specifier: workspace:*
+ version: link:../../../packages/virtual-file-routes
+ immer:
+ specifier: ^10.1.1
+ version: 10.1.1
+ react:
+ specifier: ^18.2.0
+ version: 18.3.1
+ react-dom:
+ specifier: ^18.2.0
+ version: 18.3.1(react@18.3.1)
+ redaxios:
+ specifier: ^0.5.1
+ version: 0.5.1
+ zod:
+ specifier: ^3.23.8
+ version: 3.23.8
+ devDependencies:
+ '@playwright/test':
+ specifier: ^1.46.1
+ version: 1.46.1
+ '@types/react':
+ specifier: ^18.2.47
+ version: 18.3.3
+ '@types/react-dom':
+ specifier: ^18.2.18
+ version: 18.3.0
+ '@vitejs/plugin-react':
+ specifier: ^4.3.1
+ version: 4.3.1(vite@5.3.5(@types/node@20.14.9)(terser@5.31.1))
+ vite:
+ specifier: ^5.3.5
+ version: 5.3.5(@types/node@20.14.9)(terser@5.31.1)
+
examples/react/deferred-data:
dependencies:
'@tanstack/react-router':
@@ -1927,6 +1974,9 @@ importers:
packages/router-generator:
dependencies:
+ '@tanstack/virtual-file-routes':
+ specifier: workspace:*
+ version: link:../virtual-file-routes
prettier:
specifier: ^3.3.3
version: 3.3.3
@@ -1966,6 +2016,9 @@ importers:
'@tanstack/router-generator':
specifier: workspace:*
version: link:../router-generator
+ '@tanstack/virtual-file-routes':
+ specifier: workspace:*
+ version: link:../virtual-file-routes
'@types/babel__core':
specifier: ^7.20.5
version: 7.20.5
@@ -1992,7 +2045,7 @@ importers:
version: 5.3.5(@types/node@20.14.9)(terser@5.31.1)
webpack:
specifier: '>=5.92.0'
- version: 5.93.0(@swc/core@1.7.6)(esbuild@0.21.5)
+ version: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)
zod:
specifier: ^3.23.8
version: 3.23.8
@@ -2146,6 +2199,8 @@ importers:
specifier: ^7.20.6
version: 7.20.6
+ packages/virtual-file-routes: {}
+
packages:
'@aashutoshrathi/word-wrap@1.2.6':
@@ -9721,9 +9776,9 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
- '@nrwl/tao@19.5.6(@swc/core@1.7.6)':
+ '@nrwl/tao@19.5.6(@swc/core@1.7.6(@swc/helpers@0.5.12))':
dependencies:
- nx: 19.5.6(@swc/core@1.7.6)
+ nx: 19.5.6(@swc/core@1.7.6(@swc/helpers@0.5.12))
tslib: 2.7.0
transitivePeerDependencies:
- '@swc-node/register'
@@ -13920,10 +13975,10 @@ snapshots:
nwsapi@2.2.12: {}
- nx@19.5.6(@swc/core@1.7.6):
+ nx@19.5.6(@swc/core@1.7.6(@swc/helpers@0.5.12)):
dependencies:
'@napi-rs/wasm-runtime': 0.2.4
- '@nrwl/tao': 19.5.6(@swc/core@1.7.6)
+ '@nrwl/tao': 19.5.6(@swc/core@1.7.6(@swc/helpers@0.5.12))
'@yarnpkg/lockfile': 1.1.0
'@yarnpkg/parsers': 3.0.0-rc.46
'@zkochan/js-yaml': 0.0.7
@@ -15081,14 +15136,14 @@ snapshots:
'@swc/core': 1.7.6(@swc/helpers@0.5.12)
esbuild: 0.21.5
- terser-webpack-plugin@5.3.10(@swc/core@1.7.6)(esbuild@0.21.5)(webpack@5.93.0(@swc/core@1.7.6)(esbuild@0.21.5)):
+ terser-webpack-plugin@5.3.10(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
jest-worker: 27.5.1
schema-utils: 3.3.0
serialize-javascript: 6.0.2
terser: 5.31.1
- webpack: 5.93.0(@swc/core@1.7.6)(esbuild@0.21.5)
+ webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)
optionalDependencies:
'@swc/core': 1.7.6(@swc/helpers@0.5.12)
esbuild: 0.21.5
@@ -15707,7 +15762,7 @@ snapshots:
webpack-virtual-modules@0.6.2: {}
- webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4):
+ webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5):
dependencies:
'@types/eslint-scope': 3.7.7
'@types/estree': 1.0.5
@@ -15730,17 +15785,15 @@ snapshots:
neo-async: 2.6.2
schema-utils: 3.3.0
tapable: 2.2.1
- terser-webpack-plugin: 5.3.10(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))
+ terser-webpack-plugin: 5.3.10(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5))
watchpack: 2.4.1
webpack-sources: 3.2.3
- optionalDependencies:
- webpack-cli: 5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0)
transitivePeerDependencies:
- '@swc/core'
- esbuild
- uglify-js
- webpack@5.93.0(@swc/core@1.7.6)(esbuild@0.21.5):
+ webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4):
dependencies:
'@types/eslint-scope': 3.7.7
'@types/estree': 1.0.5
@@ -15763,9 +15816,11 @@ snapshots:
neo-async: 2.6.2
schema-utils: 3.3.0
tapable: 2.2.1
- terser-webpack-plugin: 5.3.10(@swc/core@1.7.6)(esbuild@0.21.5)(webpack@5.93.0(@swc/core@1.7.6)(esbuild@0.21.5))
+ terser-webpack-plugin: 5.3.10(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))
watchpack: 2.4.1
webpack-sources: 3.2.3
+ optionalDependencies:
+ webpack-cli: 5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0)
transitivePeerDependencies:
- '@swc/core'
- esbuild
From b15d310fa7ba6a0f3e430d1579482cd38419b16e Mon Sep 17 00:00:00 2001
From: Tanner Linsley
Date: Wed, 4 Sep 2024 21:38:14 +0000
Subject: [PATCH 049/154] release: v1.54.0
---
examples/react/authenticated-routes/package.json | 2 +-
examples/react/basic-file-based-codesplitting/package.json | 2 +-
examples/react/basic-file-based/package.json | 2 +-
examples/react/basic-react-query-file-based/package.json | 2 +-
examples/react/basic-ssr-file-based/package.json | 4 ++--
examples/react/basic-ssr-streaming-file-based/package.json | 4 ++--
examples/react/basic-virtual-file-based/package.json | 2 +-
examples/react/kitchen-sink-file-based/package.json | 2 +-
.../react/kitchen-sink-react-query-file-based/package.json | 2 +-
examples/react/large-file-based/package.json | 2 +-
examples/react/quickstart-file-based/package.json | 2 +-
examples/react/quickstart-rspack-file-based/package.json | 2 +-
examples/react/quickstart-webpack-file-based/package.json | 2 +-
examples/react/search-validator-adapters/package.json | 2 +-
examples/react/start-basic-auth/package.json | 4 ++--
examples/react/start-basic-counter/package.json | 2 +-
examples/react/start-basic-react-query/package.json | 4 ++--
examples/react/start-basic-rsc/package.json | 4 ++--
examples/react/start-basic/package.json | 4 ++--
examples/react/start-clerk-basic/package.json | 4 ++--
examples/react/start-convex-trellaux/package.json | 4 ++--
examples/react/start-trellaux/package.json | 4 ++--
examples/react/with-trpc-react-query/package.json | 2 +-
examples/react/with-trpc/package.json | 2 +-
packages/router-cli/package.json | 2 +-
packages/router-generator/package.json | 2 +-
packages/router-plugin/package.json | 2 +-
packages/router-vite-plugin/package.json | 2 +-
packages/start/package.json | 2 +-
29 files changed, 38 insertions(+), 38 deletions(-)
diff --git a/examples/react/authenticated-routes/package.json b/examples/react/authenticated-routes/package.json
index 2ac617c7f3..8bfac7bbbc 100644
--- a/examples/react/authenticated-routes/package.json
+++ b/examples/react/authenticated-routes/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-file-based-codesplitting/package.json b/examples/react/basic-file-based-codesplitting/package.json
index 493efd962d..8ef5dabc26 100644
--- a/examples/react/basic-file-based-codesplitting/package.json
+++ b/examples/react/basic-file-based-codesplitting/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-file-based/package.json b/examples/react/basic-file-based/package.json
index 448d829f17..e5dfb85898 100644
--- a/examples/react/basic-file-based/package.json
+++ b/examples/react/basic-file-based/package.json
@@ -12,7 +12,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-react-query-file-based/package.json b/examples/react/basic-react-query-file-based/package.json
index b93ad8f3f9..7ad875a26d 100644
--- a/examples/react/basic-react-query-file-based/package.json
+++ b/examples/react/basic-react-query-file-based/package.json
@@ -14,7 +14,7 @@
"@tanstack/react-query-devtools": "^5.51.21",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-ssr-file-based/package.json b/examples/react/basic-ssr-file-based/package.json
index 793ebeb3c4..258645fc29 100644
--- a/examples/react/basic-ssr-file-based/package.json
+++ b/examples/react/basic-ssr-file-based/package.json
@@ -13,8 +13,8 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
- "@tanstack/start": "^1.53.1",
+ "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/start": "^1.54.0",
"get-port": "^7.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-ssr-streaming-file-based/package.json b/examples/react/basic-ssr-streaming-file-based/package.json
index 0eb75c2711..706a6930a8 100644
--- a/examples/react/basic-ssr-streaming-file-based/package.json
+++ b/examples/react/basic-ssr-streaming-file-based/package.json
@@ -13,8 +13,8 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
- "@tanstack/start": "^1.53.1",
+ "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/start": "^1.54.0",
"get-port": "^7.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-virtual-file-based/package.json b/examples/react/basic-virtual-file-based/package.json
index 6205f9540d..b51fe8e0f3 100644
--- a/examples/react/basic-virtual-file-based/package.json
+++ b/examples/react/basic-virtual-file-based/package.json
@@ -12,7 +12,7 @@
"dependencies": {
"@tanstack/react-router": "^1.52.5",
"@tanstack/router-devtools": "^1.52.5",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"@tanstack/virtual-file-routes": "^1.52.5",
"immer": "^10.1.1",
"react": "^18.2.0",
diff --git a/examples/react/kitchen-sink-file-based/package.json b/examples/react/kitchen-sink-file-based/package.json
index db8bb3bc4c..962220cb59 100644
--- a/examples/react/kitchen-sink-file-based/package.json
+++ b/examples/react/kitchen-sink-file-based/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/kitchen-sink-react-query-file-based/package.json b/examples/react/kitchen-sink-react-query-file-based/package.json
index 583113cee1..956fdc709c 100644
--- a/examples/react/kitchen-sink-react-query-file-based/package.json
+++ b/examples/react/kitchen-sink-react-query-file-based/package.json
@@ -13,7 +13,7 @@
"@tanstack/react-query-devtools": "^5.51.21",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/large-file-based/package.json b/examples/react/large-file-based/package.json
index 3624290b02..c0ee3dfda6 100644
--- a/examples/react/large-file-based/package.json
+++ b/examples/react/large-file-based/package.json
@@ -14,7 +14,7 @@
"@tanstack/react-query": "^5.51.21",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/quickstart-file-based/package.json b/examples/react/quickstart-file-based/package.json
index a26969c3a3..5299603b02 100644
--- a/examples/react/quickstart-file-based/package.json
+++ b/examples/react/quickstart-file-based/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/quickstart-rspack-file-based/package.json b/examples/react/quickstart-rspack-file-based/package.json
index 56fa74255d..7e8686325b 100644
--- a/examples/react/quickstart-rspack-file-based/package.json
+++ b/examples/react/quickstart-rspack-file-based/package.json
@@ -16,7 +16,7 @@
"devDependencies": {
"@rsbuild/core": "1.0.1-rc.0",
"@rsbuild/plugin-react": "1.0.1-rc.0",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"typescript": "^5.5.3"
diff --git a/examples/react/quickstart-webpack-file-based/package.json b/examples/react/quickstart-webpack-file-based/package.json
index ac958d5a73..beb03a2a69 100644
--- a/examples/react/quickstart-webpack-file-based/package.json
+++ b/examples/react/quickstart-webpack-file-based/package.json
@@ -14,7 +14,7 @@
},
"devDependencies": {
"@swc/core": "^1.7.6",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"html-webpack-plugin": "^5.6.0",
diff --git a/examples/react/search-validator-adapters/package.json b/examples/react/search-validator-adapters/package.json
index 1f394fe56e..778de2be72 100644
--- a/examples/react/search-validator-adapters/package.json
+++ b/examples/react/search-validator-adapters/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"@tanstack/router-zod-adapter": "^1.53.1",
"@tanstack/router-valibot-adapter": "^1.53.1",
"@tanstack/router-arktype-adapter": "^1.53.1",
diff --git a/examples/react/start-basic-auth/package.json b/examples/react/start-basic-auth/package.json
index 217ac4f941..82503cff2d 100644
--- a/examples/react/start-basic-auth/package.json
+++ b/examples/react/start-basic-auth/package.json
@@ -16,8 +16,8 @@
"@prisma/client": "5.17.0",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
- "@tanstack/start": "^1.53.1",
+ "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/start": "^1.54.0",
"@vitejs/plugin-react": "^4.3.1",
"dotenv": "^16.4.5",
"isbot": "^5.1.12",
diff --git a/examples/react/start-basic-counter/package.json b/examples/react/start-basic-counter/package.json
index 5190d2a2d9..e8d9d2bc97 100644
--- a/examples/react/start-basic-counter/package.json
+++ b/examples/react/start-basic-counter/package.json
@@ -12,7 +12,7 @@
},
"dependencies": {
"@tanstack/react-router": "^1.53.1",
- "@tanstack/start": "^1.53.1",
+ "@tanstack/start": "^1.54.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"vinxi": "0.4.2"
diff --git a/examples/react/start-basic-react-query/package.json b/examples/react/start-basic-react-query/package.json
index 3ec4255777..427483f33e 100644
--- a/examples/react/start-basic-react-query/package.json
+++ b/examples/react/start-basic-react-query/package.json
@@ -17,8 +17,8 @@
"@tanstack/react-router": "^1.53.1",
"@tanstack/react-router-with-query": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
- "@tanstack/start": "^1.53.1",
+ "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/start": "^1.54.0",
"@vitejs/plugin-react": "^4.3.1",
"isbot": "^5.1.14",
"react": "^18.3.1",
diff --git a/examples/react/start-basic-rsc/package.json b/examples/react/start-basic-rsc/package.json
index 0803638a35..55977f4b7b 100644
--- a/examples/react/start-basic-rsc/package.json
+++ b/examples/react/start-basic-rsc/package.json
@@ -14,8 +14,8 @@
"@babel/plugin-syntax-typescript": "^7.24.7",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
- "@tanstack/start": "^1.53.1",
+ "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/start": "^1.54.0",
"redaxios": "^0.5.1",
"tailwind-merge": "^2.5.2",
"vinxi": "0.4.2"
diff --git a/examples/react/start-basic/package.json b/examples/react/start-basic/package.json
index 6d15126b62..9535b8fbcd 100644
--- a/examples/react/start-basic/package.json
+++ b/examples/react/start-basic/package.json
@@ -14,8 +14,8 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
- "@tanstack/start": "^1.53.1",
+ "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/start": "^1.54.0",
"@vitejs/plugin-react": "^4.3.1",
"isbot": "^5.1.14",
"react": "^18.3.1",
diff --git a/examples/react/start-clerk-basic/package.json b/examples/react/start-clerk-basic/package.json
index ec182ffc08..6dcd9c1149 100644
--- a/examples/react/start-clerk-basic/package.json
+++ b/examples/react/start-clerk-basic/package.json
@@ -15,8 +15,8 @@
"@clerk/tanstack-start": "0.3.0-snapshot.vdf04997",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
- "@tanstack/start": "^1.53.1",
+ "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/start": "^1.54.0",
"@vitejs/plugin-react": "^4.3.1",
"dotenv": "^16.4.5",
"isbot": "^5.1.12",
diff --git a/examples/react/start-convex-trellaux/package.json b/examples/react/start-convex-trellaux/package.json
index 73a3ee4b8a..0a3eba22f2 100644
--- a/examples/react/start-convex-trellaux/package.json
+++ b/examples/react/start-convex-trellaux/package.json
@@ -18,8 +18,8 @@
"@tanstack/react-router": "^1.53.1",
"@tanstack/react-router-with-query": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
- "@tanstack/start": "^1.53.1",
+ "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/start": "^1.54.0",
"@vitejs/plugin-react": "^4.3.1",
"@convex-dev/react-query": "0.0.0-alpha.5",
"concurrently": "^8.2.2",
diff --git a/examples/react/start-trellaux/package.json b/examples/react/start-trellaux/package.json
index cbe328e47d..d8239fc8c2 100644
--- a/examples/react/start-trellaux/package.json
+++ b/examples/react/start-trellaux/package.json
@@ -16,8 +16,8 @@
"@tanstack/react-router": "^1.53.1",
"@tanstack/react-router-with-query": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
- "@tanstack/start": "^1.53.1",
+ "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/start": "^1.54.0",
"@vitejs/plugin-react": "^4.3.1",
"isbot": "^5.1.14",
"ky": "^1.5.0",
diff --git a/examples/react/with-trpc-react-query/package.json b/examples/react/with-trpc-react-query/package.json
index b19c3e4b21..f76d3159de 100644
--- a/examples/react/with-trpc-react-query/package.json
+++ b/examples/react/with-trpc-react-query/package.json
@@ -12,7 +12,7 @@
"@tanstack/react-query-devtools": "^5.51.21",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"@trpc/client": "11.0.0-rc.477",
"@trpc/react-query": "11.0.0-rc.477",
"@trpc/server": "11.0.0-rc.477",
diff --git a/examples/react/with-trpc/package.json b/examples/react/with-trpc/package.json
index 244cb62f34..27b203f0aa 100644
--- a/examples/react/with-trpc/package.json
+++ b/examples/react/with-trpc/package.json
@@ -10,7 +10,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.52.0",
+ "@tanstack/router-plugin": "^1.54.0",
"@trpc/client": "11.0.0-rc.477",
"@trpc/server": "11.0.0-rc.477",
"react": "^18.2.0",
diff --git a/packages/router-cli/package.json b/packages/router-cli/package.json
index b7a47fb7bf..06c6843f38 100644
--- a/packages/router-cli/package.json
+++ b/packages/router-cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/router-cli",
- "version": "1.52.0",
+ "version": "1.54.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/router-generator/package.json b/packages/router-generator/package.json
index 74c58cd950..019d130f72 100644
--- a/packages/router-generator/package.json
+++ b/packages/router-generator/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/router-generator",
- "version": "1.52.0",
+ "version": "1.54.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/router-plugin/package.json b/packages/router-plugin/package.json
index c0dfb38486..d6b394a92e 100644
--- a/packages/router-plugin/package.json
+++ b/packages/router-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/router-plugin",
- "version": "1.52.0",
+ "version": "1.54.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/router-vite-plugin/package.json b/packages/router-vite-plugin/package.json
index 5f77eb72d2..1c42a3ae19 100644
--- a/packages/router-vite-plugin/package.json
+++ b/packages/router-vite-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/router-vite-plugin",
- "version": "1.52.0",
+ "version": "1.54.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/start/package.json b/packages/start/package.json
index e14e9ce96a..5abe58fc81 100644
--- a/packages/start/package.json
+++ b/packages/start/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/start",
- "version": "1.53.1",
+ "version": "1.54.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
From 72b1eac97969d53f9b072ea412b032f8a784553d Mon Sep 17 00:00:00 2001
From: Manuel Schiller
Date: Wed, 4 Sep 2024 23:41:26 +0200
Subject: [PATCH 050/154] feat: publish virtual-file-routes (#2266)
---
scripts/publish.js | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/scripts/publish.js b/scripts/publish.js
index 64dbe71ca4..8a6cf779d7 100644
--- a/scripts/publish.js
+++ b/scripts/publish.js
@@ -40,6 +40,10 @@ await publish({
name: '@tanstack/router-generator',
packageDir: 'packages/router-generator',
},
+ {
+ name: '@tanstack/virtual-file-routes',
+ packageDir: 'packages/virtual-file-routes',
+ },
{
name: '@tanstack/router-cli',
packageDir: 'packages/router-cli',
From 5f791faae8d4a60130dcdb49d4030b716c015804 Mon Sep 17 00:00:00 2001
From: SeanCassiere <33615041+SeanCassiere@users.noreply.github.com>
Date: Thu, 5 Sep 2024 10:03:07 +1200
Subject: [PATCH 051/154] docs: linking to the virtual files routes page
---
docs/framework/react/guide/file-based-routing.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/framework/react/guide/file-based-routing.md b/docs/framework/react/guide/file-based-routing.md
index f1986a9752..52a8518274 100644
--- a/docs/framework/react/guide/file-based-routing.md
+++ b/docs/framework/react/guide/file-based-routing.md
@@ -123,7 +123,7 @@ const virtualRouteConfig = rootRoute('root.tsx', [
])
```
-For more information on how to configure virtual file routes, see the [Virtual File Routes](./virtual-file-routes) guide.
+For more information on how to configure virtual file routes, see the [Virtual File Routes](./virtual-file-routes.md) guide.
## Dynamic Path Params
From 93fb3dfb1382b0b168bc1bae0bb8cff15c73c847 Mon Sep 17 00:00:00 2001
From: Sean Cassiere <33615041+SeanCassiere@users.noreply.github.com>
Date: Thu, 5 Sep 2024 23:22:12 +1200
Subject: [PATCH 052/154] test(router-generator): add tests to the utils
(#2270)
---
packages/router-generator/src/generator.ts | 31 +----
packages/router-generator/src/utils.ts | 30 +++++
packages/router-generator/tests/utils.test.ts | 125 ++++++++++++++++++
3 files changed, 156 insertions(+), 30 deletions(-)
create mode 100644 packages/router-generator/tests/utils.test.ts
diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts
index d91e561a13..f282381db6 100644
--- a/packages/router-generator/src/generator.ts
+++ b/packages/router-generator/src/generator.ts
@@ -5,6 +5,7 @@ import * as prettier from 'prettier'
import {
determineInitialRoutePath,
logging,
+ multiSortBy,
removeExt,
removeTrailingSlash,
removeUnderscores,
@@ -671,36 +672,6 @@ function spaces(d: number): string {
.join('')
}
-export function multiSortBy(
- arr: Array,
- accessors: Array<(item: T) => any> = [(d) => d],
-): Array {
- return arr
- .map((d, i) => [d, i] as const)
- .sort(([a, ai], [b, bi]) => {
- for (const accessor of accessors) {
- const ao = accessor(a)
- const bo = accessor(b)
-
- if (typeof ao === 'undefined') {
- if (typeof bo === 'undefined') {
- continue
- }
- return 1
- }
-
- if (ao === bo) {
- continue
- }
-
- return ao > bo ? 1 : -1
- }
-
- return ai - bi
- })
- .map(([d]) => d)
-}
-
function removeTrailingUnderscores(s?: string) {
return s?.replaceAll(/(_$)/gi, '').replaceAll(/(_\/)/gi, '/')
}
diff --git a/packages/router-generator/src/utils.ts b/packages/router-generator/src/utils.ts
index ffcac863fa..201341f773 100644
--- a/packages/router-generator/src/utils.ts
+++ b/packages/router-generator/src/utils.ts
@@ -1,3 +1,33 @@
+export function multiSortBy(
+ arr: Array,
+ accessors: Array<(item: T) => any> = [(d) => d],
+): Array {
+ return arr
+ .map((d, i) => [d, i] as const)
+ .sort(([a, ai], [b, bi]) => {
+ for (const accessor of accessors) {
+ const ao = accessor(a)
+ const bo = accessor(b)
+
+ if (typeof ao === 'undefined') {
+ if (typeof bo === 'undefined') {
+ continue
+ }
+ return 1
+ }
+
+ if (ao === bo) {
+ continue
+ }
+
+ return ao > bo ? 1 : -1
+ }
+
+ return ai - bi
+ })
+ .map(([d]) => d)
+}
+
export function cleanPath(path: string) {
// remove double slashes
return path.replace(/\/{2,}/g, '/')
diff --git a/packages/router-generator/tests/utils.test.ts b/packages/router-generator/tests/utils.test.ts
new file mode 100644
index 0000000000..22cb05f204
--- /dev/null
+++ b/packages/router-generator/tests/utils.test.ts
@@ -0,0 +1,125 @@
+import { describe, expect, it } from 'vitest'
+import {
+ cleanPath,
+ determineInitialRoutePath,
+ multiSortBy,
+ removeExt,
+ removeUnderscores,
+ routePathToVariable,
+} from '../src/utils'
+
+describe('cleanPath', () => {
+ it('keeps path with leading slash and trailing slash', () => {
+ expect(cleanPath('/test/')).toBe('/test/')
+ })
+})
+
+describe('determineInitialRoutePath', () => {
+ it('removes dots and adds slashes', () => {
+ expect(determineInitialRoutePath('test.test')).toBe('/test/test')
+ })
+
+ it('keeps leading slash', () => {
+ expect(determineInitialRoutePath('/test.test')).toBe('/test/test')
+ })
+
+ it('keeps trailing slash', () => {
+ expect(determineInitialRoutePath('test.test/')).toBe('/test/test/')
+ })
+
+ it('removes dots and adds slashes with leading and trailing slashes', () => {
+ expect(determineInitialRoutePath('/test.test/')).toBe('/test/test/')
+ })
+
+ it("returns '/' if path is empty", () => {
+ expect(determineInitialRoutePath('')).toBe('/')
+ })
+
+ it("returns '/' if path is '.'", () => {
+ expect(determineInitialRoutePath('.')).toBe('/')
+ })
+
+ it("returns '/' if path is './'", () => {
+ expect(determineInitialRoutePath('./')).toBe('/')
+ })
+})
+
+describe('multiSortBy', () => {
+ it('sorts by multiple criteria', () => {
+ const data = [
+ { routePath: '/test/1/2/index', f: 'b' },
+ { routePath: '/test/1', f: 'b' },
+ { routePath: '/test/1/2/3/4/index', f: 'b' },
+ { routePath: '/test/1/2/3', f: 'b' },
+ { routePath: '/test/1/2/3/index', f: 'b' },
+ { routePath: '/test/1/2', f: 'b' },
+ { routePath: '/test/1/2/3/4', f: 'b' },
+ ]
+
+ const sorted = multiSortBy(data, [
+ (d) => (d.routePath.includes('1') ? -1 : 1),
+ (d) => d.routePath.split('/').length,
+ (d) => (d.routePath.endsWith('index') ? -1 : 1),
+ (d) => d,
+ ])
+
+ expect(sorted).toEqual([
+ { routePath: '/test/1', f: 'b' },
+ { routePath: '/test/1/2', f: 'b' },
+ { routePath: '/test/1/2/index', f: 'b' },
+ { routePath: '/test/1/2/3', f: 'b' },
+ { routePath: '/test/1/2/3/index', f: 'b' },
+ { routePath: '/test/1/2/3/4', f: 'b' },
+ { routePath: '/test/1/2/3/4/index', f: 'b' },
+ ])
+ })
+})
+
+describe('removeExt', () => {
+ it('removes extension', () => {
+ expect(removeExt('test.ts')).toBe('test')
+ })
+
+ it('does not remove extension if no extension', () => {
+ expect(removeExt('test')).toBe('test')
+ })
+
+ it('removes extension with multiple dots', () => {
+ expect(removeExt('test.test.ts')).toBe('test.test')
+ })
+
+ it('removes extension with leading dot', () => {
+ expect(removeExt('.test.ts')).toBe('.test')
+ })
+
+ it('removes extension when in a route path', () => {
+ expect(removeExt('/test/test.ts')).toBe('/test/test')
+ })
+})
+
+describe('removeUnderscores', () => {
+ it('removes leading underscore', () => {
+ expect(removeUnderscores('_test')).toBe('test')
+ })
+
+ it('removes trailing underscore', () => {
+ expect(removeUnderscores('test_')).toBe('test')
+ })
+
+ it('removes leading and trailing underscores', () => {
+ expect(removeUnderscores('_test_')).toBe('test')
+ })
+})
+
+describe('routePathToVariable', () => {
+ it.each([
+ ['/test/$/index', 'TestSplatIndex'],
+ ['/test/$', 'TestSplat'],
+ ['/test/$/', 'TestSplat'],
+ ['/test/index', 'TestIndex'],
+ ['/test', 'Test'],
+ ['/test/', 'Test'],
+ ])(`converts "%s" to "%s"`, (routePath, expected) => {
+ expect(routePathToVariable(routePath)).toBe(expected)
+ })
+})
From 1f92ff086d4d96656116abc55dd369da65e28419 Mon Sep 17 00:00:00 2001
From: Tanner Linsley
Date: Thu, 5 Sep 2024 11:24:03 +0000
Subject: [PATCH 053/154] release: v1.55.0
---
examples/react/authenticated-routes/package.json | 2 +-
examples/react/basic-file-based-codesplitting/package.json | 2 +-
examples/react/basic-file-based/package.json | 2 +-
examples/react/basic-react-query-file-based/package.json | 2 +-
examples/react/basic-ssr-file-based/package.json | 4 ++--
examples/react/basic-ssr-streaming-file-based/package.json | 4 ++--
examples/react/basic-virtual-file-based/package.json | 2 +-
examples/react/kitchen-sink-file-based/package.json | 2 +-
.../react/kitchen-sink-react-query-file-based/package.json | 2 +-
examples/react/large-file-based/package.json | 2 +-
examples/react/quickstart-file-based/package.json | 2 +-
examples/react/quickstart-rspack-file-based/package.json | 2 +-
examples/react/quickstart-webpack-file-based/package.json | 2 +-
examples/react/search-validator-adapters/package.json | 2 +-
examples/react/start-basic-auth/package.json | 4 ++--
examples/react/start-basic-counter/package.json | 2 +-
examples/react/start-basic-react-query/package.json | 4 ++--
examples/react/start-basic-rsc/package.json | 4 ++--
examples/react/start-basic/package.json | 4 ++--
examples/react/start-clerk-basic/package.json | 4 ++--
examples/react/start-convex-trellaux/package.json | 4 ++--
examples/react/start-trellaux/package.json | 4 ++--
examples/react/with-trpc-react-query/package.json | 2 +-
examples/react/with-trpc/package.json | 2 +-
packages/router-cli/package.json | 2 +-
packages/router-generator/package.json | 2 +-
packages/router-plugin/package.json | 2 +-
packages/router-vite-plugin/package.json | 2 +-
packages/start/package.json | 2 +-
29 files changed, 38 insertions(+), 38 deletions(-)
diff --git a/examples/react/authenticated-routes/package.json b/examples/react/authenticated-routes/package.json
index 8bfac7bbbc..8e9632571e 100644
--- a/examples/react/authenticated-routes/package.json
+++ b/examples/react/authenticated-routes/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-file-based-codesplitting/package.json b/examples/react/basic-file-based-codesplitting/package.json
index 8ef5dabc26..bfde4a0650 100644
--- a/examples/react/basic-file-based-codesplitting/package.json
+++ b/examples/react/basic-file-based-codesplitting/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-file-based/package.json b/examples/react/basic-file-based/package.json
index e5dfb85898..13ce3a700b 100644
--- a/examples/react/basic-file-based/package.json
+++ b/examples/react/basic-file-based/package.json
@@ -12,7 +12,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-react-query-file-based/package.json b/examples/react/basic-react-query-file-based/package.json
index 7ad875a26d..1b7634cd56 100644
--- a/examples/react/basic-react-query-file-based/package.json
+++ b/examples/react/basic-react-query-file-based/package.json
@@ -14,7 +14,7 @@
"@tanstack/react-query-devtools": "^5.51.21",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-ssr-file-based/package.json b/examples/react/basic-ssr-file-based/package.json
index 258645fc29..5f35d21b3e 100644
--- a/examples/react/basic-ssr-file-based/package.json
+++ b/examples/react/basic-ssr-file-based/package.json
@@ -13,8 +13,8 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
- "@tanstack/start": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/start": "^1.55.0",
"get-port": "^7.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-ssr-streaming-file-based/package.json b/examples/react/basic-ssr-streaming-file-based/package.json
index 706a6930a8..285cf16015 100644
--- a/examples/react/basic-ssr-streaming-file-based/package.json
+++ b/examples/react/basic-ssr-streaming-file-based/package.json
@@ -13,8 +13,8 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
- "@tanstack/start": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/start": "^1.55.0",
"get-port": "^7.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-virtual-file-based/package.json b/examples/react/basic-virtual-file-based/package.json
index b51fe8e0f3..971f8ec8b7 100644
--- a/examples/react/basic-virtual-file-based/package.json
+++ b/examples/react/basic-virtual-file-based/package.json
@@ -12,7 +12,7 @@
"dependencies": {
"@tanstack/react-router": "^1.52.5",
"@tanstack/router-devtools": "^1.52.5",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"@tanstack/virtual-file-routes": "^1.52.5",
"immer": "^10.1.1",
"react": "^18.2.0",
diff --git a/examples/react/kitchen-sink-file-based/package.json b/examples/react/kitchen-sink-file-based/package.json
index 962220cb59..6b3259f541 100644
--- a/examples/react/kitchen-sink-file-based/package.json
+++ b/examples/react/kitchen-sink-file-based/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/kitchen-sink-react-query-file-based/package.json b/examples/react/kitchen-sink-react-query-file-based/package.json
index 956fdc709c..2f63e43d85 100644
--- a/examples/react/kitchen-sink-react-query-file-based/package.json
+++ b/examples/react/kitchen-sink-react-query-file-based/package.json
@@ -13,7 +13,7 @@
"@tanstack/react-query-devtools": "^5.51.21",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/large-file-based/package.json b/examples/react/large-file-based/package.json
index c0ee3dfda6..913581b109 100644
--- a/examples/react/large-file-based/package.json
+++ b/examples/react/large-file-based/package.json
@@ -14,7 +14,7 @@
"@tanstack/react-query": "^5.51.21",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/quickstart-file-based/package.json b/examples/react/quickstart-file-based/package.json
index 5299603b02..f8cd564ada 100644
--- a/examples/react/quickstart-file-based/package.json
+++ b/examples/react/quickstart-file-based/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/quickstart-rspack-file-based/package.json b/examples/react/quickstart-rspack-file-based/package.json
index 7e8686325b..ed04832833 100644
--- a/examples/react/quickstart-rspack-file-based/package.json
+++ b/examples/react/quickstart-rspack-file-based/package.json
@@ -16,7 +16,7 @@
"devDependencies": {
"@rsbuild/core": "1.0.1-rc.0",
"@rsbuild/plugin-react": "1.0.1-rc.0",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"typescript": "^5.5.3"
diff --git a/examples/react/quickstart-webpack-file-based/package.json b/examples/react/quickstart-webpack-file-based/package.json
index beb03a2a69..ee2dc11560 100644
--- a/examples/react/quickstart-webpack-file-based/package.json
+++ b/examples/react/quickstart-webpack-file-based/package.json
@@ -14,7 +14,7 @@
},
"devDependencies": {
"@swc/core": "^1.7.6",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"html-webpack-plugin": "^5.6.0",
diff --git a/examples/react/search-validator-adapters/package.json b/examples/react/search-validator-adapters/package.json
index 778de2be72..d4c5974e1e 100644
--- a/examples/react/search-validator-adapters/package.json
+++ b/examples/react/search-validator-adapters/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"@tanstack/router-zod-adapter": "^1.53.1",
"@tanstack/router-valibot-adapter": "^1.53.1",
"@tanstack/router-arktype-adapter": "^1.53.1",
diff --git a/examples/react/start-basic-auth/package.json b/examples/react/start-basic-auth/package.json
index 82503cff2d..dc38e12329 100644
--- a/examples/react/start-basic-auth/package.json
+++ b/examples/react/start-basic-auth/package.json
@@ -16,8 +16,8 @@
"@prisma/client": "5.17.0",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
- "@tanstack/start": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/start": "^1.55.0",
"@vitejs/plugin-react": "^4.3.1",
"dotenv": "^16.4.5",
"isbot": "^5.1.12",
diff --git a/examples/react/start-basic-counter/package.json b/examples/react/start-basic-counter/package.json
index e8d9d2bc97..d0ff148bec 100644
--- a/examples/react/start-basic-counter/package.json
+++ b/examples/react/start-basic-counter/package.json
@@ -12,7 +12,7 @@
},
"dependencies": {
"@tanstack/react-router": "^1.53.1",
- "@tanstack/start": "^1.54.0",
+ "@tanstack/start": "^1.55.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"vinxi": "0.4.2"
diff --git a/examples/react/start-basic-react-query/package.json b/examples/react/start-basic-react-query/package.json
index 427483f33e..68a5ba120e 100644
--- a/examples/react/start-basic-react-query/package.json
+++ b/examples/react/start-basic-react-query/package.json
@@ -17,8 +17,8 @@
"@tanstack/react-router": "^1.53.1",
"@tanstack/react-router-with-query": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
- "@tanstack/start": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/start": "^1.55.0",
"@vitejs/plugin-react": "^4.3.1",
"isbot": "^5.1.14",
"react": "^18.3.1",
diff --git a/examples/react/start-basic-rsc/package.json b/examples/react/start-basic-rsc/package.json
index 55977f4b7b..774c6b8a14 100644
--- a/examples/react/start-basic-rsc/package.json
+++ b/examples/react/start-basic-rsc/package.json
@@ -14,8 +14,8 @@
"@babel/plugin-syntax-typescript": "^7.24.7",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
- "@tanstack/start": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/start": "^1.55.0",
"redaxios": "^0.5.1",
"tailwind-merge": "^2.5.2",
"vinxi": "0.4.2"
diff --git a/examples/react/start-basic/package.json b/examples/react/start-basic/package.json
index 9535b8fbcd..314336f9b4 100644
--- a/examples/react/start-basic/package.json
+++ b/examples/react/start-basic/package.json
@@ -14,8 +14,8 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
- "@tanstack/start": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/start": "^1.55.0",
"@vitejs/plugin-react": "^4.3.1",
"isbot": "^5.1.14",
"react": "^18.3.1",
diff --git a/examples/react/start-clerk-basic/package.json b/examples/react/start-clerk-basic/package.json
index 6dcd9c1149..c3e09fbe5c 100644
--- a/examples/react/start-clerk-basic/package.json
+++ b/examples/react/start-clerk-basic/package.json
@@ -15,8 +15,8 @@
"@clerk/tanstack-start": "0.3.0-snapshot.vdf04997",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
- "@tanstack/start": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/start": "^1.55.0",
"@vitejs/plugin-react": "^4.3.1",
"dotenv": "^16.4.5",
"isbot": "^5.1.12",
diff --git a/examples/react/start-convex-trellaux/package.json b/examples/react/start-convex-trellaux/package.json
index 0a3eba22f2..1d1e4d36c5 100644
--- a/examples/react/start-convex-trellaux/package.json
+++ b/examples/react/start-convex-trellaux/package.json
@@ -18,8 +18,8 @@
"@tanstack/react-router": "^1.53.1",
"@tanstack/react-router-with-query": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
- "@tanstack/start": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/start": "^1.55.0",
"@vitejs/plugin-react": "^4.3.1",
"@convex-dev/react-query": "0.0.0-alpha.5",
"concurrently": "^8.2.2",
diff --git a/examples/react/start-trellaux/package.json b/examples/react/start-trellaux/package.json
index d8239fc8c2..a78d1de034 100644
--- a/examples/react/start-trellaux/package.json
+++ b/examples/react/start-trellaux/package.json
@@ -16,8 +16,8 @@
"@tanstack/react-router": "^1.53.1",
"@tanstack/react-router-with-query": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
- "@tanstack/start": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/start": "^1.55.0",
"@vitejs/plugin-react": "^4.3.1",
"isbot": "^5.1.14",
"ky": "^1.5.0",
diff --git a/examples/react/with-trpc-react-query/package.json b/examples/react/with-trpc-react-query/package.json
index f76d3159de..ab142de533 100644
--- a/examples/react/with-trpc-react-query/package.json
+++ b/examples/react/with-trpc-react-query/package.json
@@ -12,7 +12,7 @@
"@tanstack/react-query-devtools": "^5.51.21",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"@trpc/client": "11.0.0-rc.477",
"@trpc/react-query": "11.0.0-rc.477",
"@trpc/server": "11.0.0-rc.477",
diff --git a/examples/react/with-trpc/package.json b/examples/react/with-trpc/package.json
index 27b203f0aa..f98377b057 100644
--- a/examples/react/with-trpc/package.json
+++ b/examples/react/with-trpc/package.json
@@ -10,7 +10,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.54.0",
+ "@tanstack/router-plugin": "^1.55.0",
"@trpc/client": "11.0.0-rc.477",
"@trpc/server": "11.0.0-rc.477",
"react": "^18.2.0",
diff --git a/packages/router-cli/package.json b/packages/router-cli/package.json
index 06c6843f38..6bff22784d 100644
--- a/packages/router-cli/package.json
+++ b/packages/router-cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/router-cli",
- "version": "1.54.0",
+ "version": "1.55.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/router-generator/package.json b/packages/router-generator/package.json
index 019d130f72..49ea0bf49b 100644
--- a/packages/router-generator/package.json
+++ b/packages/router-generator/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/router-generator",
- "version": "1.54.0",
+ "version": "1.55.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/router-plugin/package.json b/packages/router-plugin/package.json
index d6b394a92e..8f9dcd4ae6 100644
--- a/packages/router-plugin/package.json
+++ b/packages/router-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/router-plugin",
- "version": "1.54.0",
+ "version": "1.55.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/router-vite-plugin/package.json b/packages/router-vite-plugin/package.json
index 1c42a3ae19..03f3156b80 100644
--- a/packages/router-vite-plugin/package.json
+++ b/packages/router-vite-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/router-vite-plugin",
- "version": "1.54.0",
+ "version": "1.55.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/start/package.json b/packages/start/package.json
index 5abe58fc81..0a3a81339b 100644
--- a/packages/start/package.json
+++ b/packages/start/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/start",
- "version": "1.54.0",
+ "version": "1.55.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
From 423728f412cd40efa528983aded4d11d12ba44fe Mon Sep 17 00:00:00 2001
From: Tanner Linsley
Date: Thu, 5 Sep 2024 09:57:40 -0600
Subject: [PATCH 054/154] Update already released virtual-file-routes to 1.54.0
---
packages/virtual-file-routes/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/virtual-file-routes/package.json b/packages/virtual-file-routes/package.json
index 8c98be8ddd..b14dfd8e65 100644
--- a/packages/virtual-file-routes/package.json
+++ b/packages/virtual-file-routes/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/virtual-file-routes",
- "version": "1.52.5",
+ "version": "1.54.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
From f64587fe83eb1f85c7ca28c5dadd27478213de42 Mon Sep 17 00:00:00 2001
From: Manuel Schiller
Date: Thu, 5 Sep 2024 23:22:06 +0200
Subject: [PATCH 055/154] feat(router-generator): allow virtual subtree in file
based routing (#2271)
---
.../react/guide/virtual-file-routes.md | 65 +++
.../.gitignore | 10 +
.../basic-virtual-inside-file-based/README.md | 6 +
.../index.html | 24 ++
.../package.json | 29 ++
.../src/main.tsx | 25 ++
.../src/posts.tsx | 32 ++
.../src/routeTree.gen.ts | 237 +++++++++++
.../src/routes/__root.tsx | 62 +++
.../src/routes/_layout.tsx | 16 +
.../src/routes/_layout/_layout-2.tsx | 34 ++
.../src/routes/_layout/_layout-2/layout-a.tsx | 9 +
.../src/routes/_layout/_layout-2/layout-b.tsx | 9 +
.../src/routes/index.tsx | 14 +
.../src/routes/posts.tsx | 39 ++
.../src/routes/posts/__virtual.ts | 13 +
.../src/routes/posts/details.tsx | 28 ++
.../src/routes/posts/home.tsx | 10 +
.../routes/posts/lets-go/deeper/__virtual.ts | 6 +
.../src/routes/posts/lets-go/deeper/home.tsx | 5 +
.../src/routes/posts/lets-go/index.tsx | 5 +
.../tsconfig.dev.json | 10 +
.../tsconfig.json | 9 +
.../vite.config.ts | 8 +
packages/router-generator/package.json | 5 +-
.../src/filesystem/physical/getRouteNodes.ts | 46 +++
.../src/filesystem/virtual/loadConfigFile.ts | 6 +
.../routeTree.snapshot.ts | 115 ++++++
.../virtual-inside-nested/routes/__root.tsx | 11 +
.../virtual-inside-nested/routes/foo/bar.tsx | 5 +
.../routes/foo/bar/__virtual.ts | 10 +
.../routes/foo/bar/details.tsx | 5 +
.../routes/foo/bar/home.tsx | 5 +
.../routes/foo/bar/route.ts | 0
.../virtual-inside-nested/routes/index.tsx | 5 +
.../virtual-file-routes/src/defineConfig.ts | 38 ++
packages/virtual-file-routes/src/index.ts | 9 +
pnpm-lock.yaml | 383 ++++++++++++++++--
38 files changed, 1309 insertions(+), 39 deletions(-)
create mode 100644 examples/react/basic-virtual-inside-file-based/.gitignore
create mode 100644 examples/react/basic-virtual-inside-file-based/README.md
create mode 100644 examples/react/basic-virtual-inside-file-based/index.html
create mode 100644 examples/react/basic-virtual-inside-file-based/package.json
create mode 100644 examples/react/basic-virtual-inside-file-based/src/main.tsx
create mode 100644 examples/react/basic-virtual-inside-file-based/src/posts.tsx
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routeTree.gen.ts
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routes/__root.tsx
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routes/_layout.tsx
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routes/_layout/_layout-2.tsx
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routes/_layout/_layout-2/layout-a.tsx
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routes/_layout/_layout-2/layout-b.tsx
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routes/index.tsx
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routes/posts.tsx
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routes/posts/__virtual.ts
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routes/posts/details.tsx
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routes/posts/home.tsx
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routes/posts/lets-go/deeper/__virtual.ts
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routes/posts/lets-go/deeper/home.tsx
create mode 100644 examples/react/basic-virtual-inside-file-based/src/routes/posts/lets-go/index.tsx
create mode 100644 examples/react/basic-virtual-inside-file-based/tsconfig.dev.json
create mode 100644 examples/react/basic-virtual-inside-file-based/tsconfig.json
create mode 100644 examples/react/basic-virtual-inside-file-based/vite.config.ts
create mode 100644 packages/router-generator/src/filesystem/virtual/loadConfigFile.ts
create mode 100644 packages/router-generator/tests/generator/virtual-inside-nested/routeTree.snapshot.ts
create mode 100644 packages/router-generator/tests/generator/virtual-inside-nested/routes/__root.tsx
create mode 100644 packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar.tsx
create mode 100644 packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/__virtual.ts
create mode 100644 packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/details.tsx
create mode 100644 packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/home.tsx
create mode 100644 packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/route.ts
create mode 100644 packages/router-generator/tests/generator/virtual-inside-nested/routes/index.tsx
create mode 100644 packages/virtual-file-routes/src/defineConfig.ts
diff --git a/docs/framework/react/guide/virtual-file-routes.md b/docs/framework/react/guide/virtual-file-routes.md
index f9f153999e..d8abcdffe8 100644
--- a/docs/framework/react/guide/virtual-file-routes.md
+++ b/docs/framework/react/guide/virtual-file-routes.md
@@ -184,6 +184,71 @@ const virtualRouteConfig = rootRoute('root.tsx', [
])
```
+## Virtual Routes inside of TanStack Router File Based routing
+
+The previous section showed you how you can use TanStack Router's File Based routing convention inside of a virtual route configuration.
+However, the opposite is possible as well.
+You can configure the main part of your app's route tree using TanStack Router's File Based routing convention and opt into virtual route configuration for specific subtrees.
+
+Consider the following file structure:
+
+```
+/routes
+├── __root.tsx
+├── foo
+│ ├── bar
+│ │ ├── __virtual.ts
+│ │ ├── details.tsx
+│ │ ├── home.tsx
+│ │ └── route.ts
+│ └── bar.tsx
+└── index.tsx
+```
+
+Let's look at the `bar` directory which contains a special file named `__virtual.ts`. This file instructs the generator to switch over to virtual file route configuration for this directory (and its child directories).
+
+`__virtual.ts` configures the virtual routes for that particular subtree of the route tree. It uses the same API as explained above, with the only difference being that no `rootRoute` is defined for that subtree:
+
+```tsx
+import {
+ defineVirtualSubtreeConfig,
+ index,
+ route,
+} from '@tanstack/virtual-file-routes'
+
+export default defineVirtualSubtreeConfig([
+ index('home.tsx'),
+ route('$id', 'details.tsx'),
+])
+```
+
+The helper function `defineVirtualSubtreeConfig` is closely modeled after vite's `defineConfig` and allows you to define a subtree configuration via a default export. The default export can either be
+
+- a subtree config object
+- a function returning a subtree config object
+- an async function returning a subtree config object
+
+## Inception
+
+You can mix and match TanStack Router's File Based routing convention and virtual route configuration however you like.
+Let's go deeper!
+Check out the following example that starts off using File Based routing convention, switches over to virtual route configuration for `/posts`, switches back to File Based routing convention for `/posts/lets-go` only to switch over to virtual route configuration again for `/posts/lets-go/deeper`.
+
+```
+├── __root.tsx
+├── index.tsx
+├── posts
+│ ├── __virtual.ts
+│ ├── details.tsx
+│ ├── home.tsx
+│ └── lets-go
+│ ├── deeper
+│ │ ├── __virtual.ts
+│ │ └── home.tsx
+│ └── index.tsx
+└── posts.tsx
+```
+
## Configuration via the TanStack Router CLI
While much less common, you can also configure virtual file routes via the TanStack Router CLI by adding a `virtualRouteConfig` object to your `tsr.config.json` file and defining your virtual routes and passing the resulting JSON that is generated by calling the actual `rootRoute`/`route`/`index`/etc functions from the `@tanstack/virtual-file-routes` package:
diff --git a/examples/react/basic-virtual-inside-file-based/.gitignore b/examples/react/basic-virtual-inside-file-based/.gitignore
new file mode 100644
index 0000000000..a6ea47e508
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/.gitignore
@@ -0,0 +1,10 @@
+node_modules
+.DS_Store
+dist
+dist-ssr
+*.local
+
+/test-results/
+/playwright-report/
+/blob-report/
+/playwright/.cache/
diff --git a/examples/react/basic-virtual-inside-file-based/README.md b/examples/react/basic-virtual-inside-file-based/README.md
new file mode 100644
index 0000000000..115199d292
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/README.md
@@ -0,0 +1,6 @@
+# Example
+
+To run this example:
+
+- `npm install` or `yarn`
+- `npm start` or `yarn start`
diff --git a/examples/react/basic-virtual-inside-file-based/index.html b/examples/react/basic-virtual-inside-file-based/index.html
new file mode 100644
index 0000000000..a4b3349437
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/index.html
@@ -0,0 +1,24 @@
+
+
+
+
+
+ Vite App
+
+
+
+
+
+
+
+
diff --git a/examples/react/basic-virtual-inside-file-based/package.json b/examples/react/basic-virtual-inside-file-based/package.json
new file mode 100644
index 0000000000..e17cf99fd0
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "tanstack-router-react-example-basic-virtual-inside-file-based",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vite --port=3001",
+ "build": "vite build",
+ "serve": "vite preview",
+ "start": "vite"
+ },
+ "dependencies": {
+ "@tanstack/react-router": "^1.52.5",
+ "@tanstack/router-devtools": "^1.52.5",
+ "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/virtual-file-routes": "^1.52.5",
+ "immer": "^10.1.1",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "redaxios": "^0.5.1",
+ "zod": "^3.23.8"
+ },
+ "devDependencies": {
+ "@playwright/test": "^1.46.1",
+ "@types/react": "^18.2.47",
+ "@types/react-dom": "^18.2.18",
+ "@vitejs/plugin-react": "^4.3.1",
+ "vite": "^5.3.5"
+ }
+}
diff --git a/examples/react/basic-virtual-inside-file-based/src/main.tsx b/examples/react/basic-virtual-inside-file-based/src/main.tsx
new file mode 100644
index 0000000000..18b1b603f8
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/main.tsx
@@ -0,0 +1,25 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import { RouterProvider, createRouter } from '@tanstack/react-router'
+import { routeTree } from './routeTree.gen'
+
+// Set up a Router instance
+const router = createRouter({
+ routeTree,
+ defaultPreload: 'intent',
+ defaultStaleTime: 5000,
+})
+
+// Register things for typesafety
+declare module '@tanstack/react-router' {
+ interface Register {
+ router: typeof router
+ }
+}
+
+const rootElement = document.getElementById('app')!
+
+if (!rootElement.innerHTML) {
+ const root = ReactDOM.createRoot(rootElement)
+ root.render( )
+}
diff --git a/examples/react/basic-virtual-inside-file-based/src/posts.tsx b/examples/react/basic-virtual-inside-file-based/src/posts.tsx
new file mode 100644
index 0000000000..3ccf1ff421
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/posts.tsx
@@ -0,0 +1,32 @@
+import { notFound } from '@tanstack/react-router'
+import axios from 'redaxios'
+
+export type PostType = {
+ id: string
+ title: string
+ body: string
+}
+
+export const fetchPost = async (postId: string) => {
+ console.info(`Fetching post with id ${postId}...`)
+ await new Promise((r) => setTimeout(r, 500))
+ const post = await axios
+ .get(`https://jsonplaceholder.typicode.com/posts/${postId}`)
+ .then((r) => r.data)
+ .catch((err) => {
+ if (err.status === 404) {
+ throw notFound()
+ }
+ throw err
+ })
+
+ return post
+}
+
+export const fetchPosts = async () => {
+ console.info('Fetching posts...')
+ await new Promise((r) => setTimeout(r, 500))
+ return axios
+ .get>('https://jsonplaceholder.typicode.com/posts')
+ .then((r) => r.data.slice(0, 10))
+}
diff --git a/examples/react/basic-virtual-inside-file-based/src/routeTree.gen.ts b/examples/react/basic-virtual-inside-file-based/src/routeTree.gen.ts
new file mode 100644
index 0000000000..9f23d1480d
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routeTree.gen.ts
@@ -0,0 +1,237 @@
+/* prettier-ignore-start */
+
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file is auto-generated by TanStack Router
+
+// Import Routes
+
+import { Route as rootRoute } from './routes/__root'
+import { Route as PostsImport } from './routes/posts'
+import { Route as LayoutImport } from './routes/_layout'
+import { Route as IndexImport } from './routes/index'
+import { Route as postsDetailsImport } from './routes/posts/details'
+import { Route as LayoutLayout2Import } from './routes/_layout/_layout-2'
+import { Route as postsHomeImport } from './routes/posts/home'
+import { Route as postsLetsGoIndexImport } from './routes/posts/lets-go/index'
+import { Route as LayoutLayout2LayoutBImport } from './routes/_layout/_layout-2/layout-b'
+import { Route as LayoutLayout2LayoutAImport } from './routes/_layout/_layout-2/layout-a'
+import { Route as postsLetsGoDeeperHomeImport } from './routes/posts/lets-go/deeper/home'
+
+// Create/Update Routes
+
+const PostsRoute = PostsImport.update({
+ path: '/posts',
+ getParentRoute: () => rootRoute,
+} as any)
+
+const LayoutRoute = LayoutImport.update({
+ id: '/_layout',
+ getParentRoute: () => rootRoute,
+} as any)
+
+const IndexRoute = IndexImport.update({
+ path: '/',
+ getParentRoute: () => rootRoute,
+} as any)
+
+const postsDetailsRoute = postsDetailsImport.update({
+ path: '/$postId',
+ getParentRoute: () => PostsRoute,
+} as any)
+
+const LayoutLayout2Route = LayoutLayout2Import.update({
+ id: '/_layout-2',
+ getParentRoute: () => LayoutRoute,
+} as any)
+
+const postsHomeRoute = postsHomeImport.update({
+ path: '/',
+ getParentRoute: () => PostsRoute,
+} as any)
+
+const postsLetsGoIndexRoute = postsLetsGoIndexImport.update({
+ path: '/inception/',
+ getParentRoute: () => PostsRoute,
+} as any)
+
+const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBImport.update({
+ path: '/layout-b',
+ getParentRoute: () => LayoutLayout2Route,
+} as any)
+
+const LayoutLayout2LayoutARoute = LayoutLayout2LayoutAImport.update({
+ path: '/layout-a',
+ getParentRoute: () => LayoutLayout2Route,
+} as any)
+
+const postsLetsGoDeeperHomeRoute = postsLetsGoDeeperHomeImport.update({
+ path: '/inception/deeper/',
+ getParentRoute: () => PostsRoute,
+} as any)
+
+// Populate the FileRoutesByPath interface
+
+declare module '@tanstack/react-router' {
+ interface FileRoutesByPath {
+ '/': {
+ id: '/'
+ path: '/'
+ fullPath: '/'
+ preLoaderRoute: typeof IndexImport
+ parentRoute: typeof rootRoute
+ }
+ '/_layout': {
+ id: '/_layout'
+ path: ''
+ fullPath: ''
+ preLoaderRoute: typeof LayoutImport
+ parentRoute: typeof rootRoute
+ }
+ '/posts': {
+ id: '/posts'
+ path: '/posts'
+ fullPath: '/posts'
+ preLoaderRoute: typeof PostsImport
+ parentRoute: typeof rootRoute
+ }
+ '/posts/': {
+ id: '/posts/'
+ path: '/'
+ fullPath: '/posts/'
+ preLoaderRoute: typeof postsHomeImport
+ parentRoute: typeof PostsImport
+ }
+ '/_layout/_layout-2': {
+ id: '/_layout/_layout-2'
+ path: ''
+ fullPath: ''
+ preLoaderRoute: typeof LayoutLayout2Import
+ parentRoute: typeof LayoutImport
+ }
+ '/posts/$postId': {
+ id: '/posts/$postId'
+ path: '/$postId'
+ fullPath: '/posts/$postId'
+ preLoaderRoute: typeof postsDetailsImport
+ parentRoute: typeof PostsImport
+ }
+ '/_layout/_layout-2/layout-a': {
+ id: '/_layout/_layout-2/layout-a'
+ path: '/layout-a'
+ fullPath: '/layout-a'
+ preLoaderRoute: typeof LayoutLayout2LayoutAImport
+ parentRoute: typeof LayoutLayout2Import
+ }
+ '/_layout/_layout-2/layout-b': {
+ id: '/_layout/_layout-2/layout-b'
+ path: '/layout-b'
+ fullPath: '/layout-b'
+ preLoaderRoute: typeof LayoutLayout2LayoutBImport
+ parentRoute: typeof LayoutLayout2Import
+ }
+ '/posts/inception/': {
+ id: '/posts/inception/'
+ path: '/inception'
+ fullPath: '/posts/inception'
+ preLoaderRoute: typeof postsLetsGoIndexImport
+ parentRoute: typeof PostsImport
+ }
+ '/posts/inception/deeper/': {
+ id: '/posts/inception/deeper/'
+ path: '/inception/deeper'
+ fullPath: '/posts/inception/deeper'
+ preLoaderRoute: typeof postsLetsGoDeeperHomeImport
+ parentRoute: typeof PostsImport
+ }
+ }
+}
+
+// Create and export the route tree
+
+export const routeTree = rootRoute.addChildren({
+ IndexRoute,
+ LayoutRoute: LayoutRoute.addChildren({
+ LayoutLayout2Route: LayoutLayout2Route.addChildren({
+ LayoutLayout2LayoutARoute,
+ LayoutLayout2LayoutBRoute,
+ }),
+ }),
+ PostsRoute: PostsRoute.addChildren({
+ postsHomeRoute,
+ postsDetailsRoute,
+ postsLetsGoIndexRoute,
+ postsLetsGoDeeperHomeRoute,
+ }),
+})
+
+/* prettier-ignore-end */
+
+/* ROUTE_MANIFEST_START
+{
+ "routes": {
+ "__root__": {
+ "filePath": "__root.tsx",
+ "children": [
+ "/",
+ "/_layout",
+ "/posts"
+ ]
+ },
+ "/": {
+ "filePath": "index.tsx"
+ },
+ "/_layout": {
+ "filePath": "_layout.tsx",
+ "children": [
+ "/_layout/_layout-2"
+ ]
+ },
+ "/posts": {
+ "filePath": "posts.tsx",
+ "children": [
+ "/posts/",
+ "/posts/$postId",
+ "/posts/inception/",
+ "/posts/inception/deeper/"
+ ]
+ },
+ "/posts/": {
+ "filePath": "posts/home.tsx",
+ "parent": "/posts"
+ },
+ "/_layout/_layout-2": {
+ "filePath": "_layout/_layout-2.tsx",
+ "parent": "/_layout",
+ "children": [
+ "/_layout/_layout-2/layout-a",
+ "/_layout/_layout-2/layout-b"
+ ]
+ },
+ "/posts/$postId": {
+ "filePath": "posts/details.tsx",
+ "parent": "/posts"
+ },
+ "/_layout/_layout-2/layout-a": {
+ "filePath": "_layout/_layout-2/layout-a.tsx",
+ "parent": "/_layout/_layout-2"
+ },
+ "/_layout/_layout-2/layout-b": {
+ "filePath": "_layout/_layout-2/layout-b.tsx",
+ "parent": "/_layout/_layout-2"
+ },
+ "/posts/inception/": {
+ "filePath": "posts/lets-go/index.tsx",
+ "parent": "/posts"
+ },
+ "/posts/inception/deeper/": {
+ "filePath": "posts/lets-go/deeper/home.tsx",
+ "parent": "/posts"
+ }
+ }
+}
+ROUTE_MANIFEST_END */
diff --git a/examples/react/basic-virtual-inside-file-based/src/routes/__root.tsx b/examples/react/basic-virtual-inside-file-based/src/routes/__root.tsx
new file mode 100644
index 0000000000..52c5059f55
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routes/__root.tsx
@@ -0,0 +1,62 @@
+import * as React from 'react'
+import { Link, Outlet, createRootRoute } from '@tanstack/react-router'
+import { TanStackRouterDevtools } from '@tanstack/router-devtools'
+
+export const Route = createRootRoute({
+ component: RootComponent,
+ notFoundComponent: () => {
+ return (
+
+
This is the notFoundComponent configured on root route
+
Start Over
+
+ )
+ },
+})
+
+function RootComponent() {
+ return (
+ <>
+
+
+ Home
+ {' '}
+
+ Posts
+ {' '}
+
+ Layout
+ {' '}
+
+ This Route Does Not Exist
+
+
+
+
+ {/* Start rendering router matches */}
+
+ >
+ )
+}
diff --git a/examples/react/basic-virtual-inside-file-based/src/routes/_layout.tsx b/examples/react/basic-virtual-inside-file-based/src/routes/_layout.tsx
new file mode 100644
index 0000000000..02ddbb1cd9
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routes/_layout.tsx
@@ -0,0 +1,16 @@
+import { Outlet, createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_layout')({
+ component: LayoutComponent,
+})
+
+function LayoutComponent() {
+ return (
+
+ )
+}
diff --git a/examples/react/basic-virtual-inside-file-based/src/routes/_layout/_layout-2.tsx b/examples/react/basic-virtual-inside-file-based/src/routes/_layout/_layout-2.tsx
new file mode 100644
index 0000000000..3b7dbf2903
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routes/_layout/_layout-2.tsx
@@ -0,0 +1,34 @@
+import { Link, Outlet, createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_layout/_layout-2')({
+ component: LayoutComponent,
+})
+
+function LayoutComponent() {
+ return (
+
+
I'm a nested layout
+
+
+ Layout A
+
+
+ Layout B
+
+
+
+
+
+
+ )
+}
diff --git a/examples/react/basic-virtual-inside-file-based/src/routes/_layout/_layout-2/layout-a.tsx b/examples/react/basic-virtual-inside-file-based/src/routes/_layout/_layout-2/layout-a.tsx
new file mode 100644
index 0000000000..61e19b4d9f
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routes/_layout/_layout-2/layout-a.tsx
@@ -0,0 +1,9 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_layout/_layout-2/layout-a')({
+ component: LayoutAComponent,
+})
+
+function LayoutAComponent() {
+ return I'm layout A!
+}
diff --git a/examples/react/basic-virtual-inside-file-based/src/routes/_layout/_layout-2/layout-b.tsx b/examples/react/basic-virtual-inside-file-based/src/routes/_layout/_layout-2/layout-b.tsx
new file mode 100644
index 0000000000..cceed1fb9a
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routes/_layout/_layout-2/layout-b.tsx
@@ -0,0 +1,9 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_layout/_layout-2/layout-b')({
+ component: LayoutBComponent,
+})
+
+function LayoutBComponent() {
+ return I'm layout B!
+}
diff --git a/examples/react/basic-virtual-inside-file-based/src/routes/index.tsx b/examples/react/basic-virtual-inside-file-based/src/routes/index.tsx
new file mode 100644
index 0000000000..eac82a9174
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routes/index.tsx
@@ -0,0 +1,14 @@
+import * as React from 'react'
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/')({
+ component: Home,
+})
+
+function Home() {
+ return (
+
+
Welcome Home!
+
+ )
+}
diff --git a/examples/react/basic-virtual-inside-file-based/src/routes/posts.tsx b/examples/react/basic-virtual-inside-file-based/src/routes/posts.tsx
new file mode 100644
index 0000000000..c7a09ed7f8
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routes/posts.tsx
@@ -0,0 +1,39 @@
+import * as React from 'react'
+import { Link, Outlet, createFileRoute } from '@tanstack/react-router'
+import { fetchPosts } from '../posts'
+
+export const Route = createFileRoute('/posts')({
+ loader: fetchPosts,
+ component: PostsComponent,
+})
+
+function PostsComponent() {
+ const posts = Route.useLoaderData()
+
+ return (
+
+ )
+}
diff --git a/examples/react/basic-virtual-inside-file-based/src/routes/posts/__virtual.ts b/examples/react/basic-virtual-inside-file-based/src/routes/posts/__virtual.ts
new file mode 100644
index 0000000000..afecfb2f97
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routes/posts/__virtual.ts
@@ -0,0 +1,13 @@
+import {
+ defineVirtualSubtreeConfig,
+ index,
+ physical,
+ route,
+} from '@tanstack/virtual-file-routes'
+
+// this just shows that you can use an async function to define your virtual routes
+export default defineVirtualSubtreeConfig(async () => [
+ index('home.tsx'),
+ route('$postId', 'details.tsx'),
+ physical('/inception', 'lets-go'),
+])
diff --git a/examples/react/basic-virtual-inside-file-based/src/routes/posts/details.tsx b/examples/react/basic-virtual-inside-file-based/src/routes/posts/details.tsx
new file mode 100644
index 0000000000..948d52d6d6
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routes/posts/details.tsx
@@ -0,0 +1,28 @@
+import * as React from 'react'
+import { ErrorComponent, createFileRoute } from '@tanstack/react-router'
+import { fetchPost } from '../../posts'
+import type { ErrorComponentProps } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/posts/$postId')({
+ loader: async ({ params: { postId } }) => fetchPost(postId),
+ errorComponent: PostErrorComponent as any,
+ notFoundComponent: () => {
+ return Post not found
+ },
+ component: PostComponent,
+})
+
+export function PostErrorComponent({ error }: ErrorComponentProps) {
+ return
+}
+
+function PostComponent() {
+ const post = Route.useLoaderData()
+
+ return (
+
+
{post.title}
+
{post.body}
+
+ )
+}
diff --git a/examples/react/basic-virtual-inside-file-based/src/routes/posts/home.tsx b/examples/react/basic-virtual-inside-file-based/src/routes/posts/home.tsx
new file mode 100644
index 0000000000..056433ca0a
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routes/posts/home.tsx
@@ -0,0 +1,10 @@
+import * as React from 'react'
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/posts/')({
+ component: PostsIndexComponent,
+})
+
+function PostsIndexComponent() {
+ return Select a post.
+}
diff --git a/examples/react/basic-virtual-inside-file-based/src/routes/posts/lets-go/deeper/__virtual.ts b/examples/react/basic-virtual-inside-file-based/src/routes/posts/lets-go/deeper/__virtual.ts
new file mode 100644
index 0000000000..1c82ce7a2c
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routes/posts/lets-go/deeper/__virtual.ts
@@ -0,0 +1,6 @@
+import {
+ defineVirtualSubtreeConfig,
+ index,
+} from '@tanstack/virtual-file-routes'
+
+export default defineVirtualSubtreeConfig([index('home.tsx')])
diff --git a/examples/react/basic-virtual-inside-file-based/src/routes/posts/lets-go/deeper/home.tsx b/examples/react/basic-virtual-inside-file-based/src/routes/posts/lets-go/deeper/home.tsx
new file mode 100644
index 0000000000..11f7fa95ca
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routes/posts/lets-go/deeper/home.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/posts/inception/deeper/')({
+ component: () => Hello /posts/inception/deeper/!
,
+})
diff --git a/examples/react/basic-virtual-inside-file-based/src/routes/posts/lets-go/index.tsx b/examples/react/basic-virtual-inside-file-based/src/routes/posts/lets-go/index.tsx
new file mode 100644
index 0000000000..964ab3c900
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/src/routes/posts/lets-go/index.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/posts/inception/')({
+ component: () => Hello /posts/inception/!
,
+})
diff --git a/examples/react/basic-virtual-inside-file-based/tsconfig.dev.json b/examples/react/basic-virtual-inside-file-based/tsconfig.dev.json
new file mode 100644
index 0000000000..285a09b0dc
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/tsconfig.dev.json
@@ -0,0 +1,10 @@
+{
+ "composite": true,
+ "extends": "../../../tsconfig.base.json",
+
+ "files": ["src/main.tsx"],
+ "include": [
+ "src"
+ // "__tests__/**/*.test.*"
+ ]
+}
diff --git a/examples/react/basic-virtual-inside-file-based/tsconfig.json b/examples/react/basic-virtual-inside-file-based/tsconfig.json
new file mode 100644
index 0000000000..e2241c355e
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions": {
+ "strict": true,
+ "esModuleInterop": true,
+ "jsx": "react-jsx",
+ "module": "Preserve",
+ "moduleResolution": "Bundler"
+ }
+}
diff --git a/examples/react/basic-virtual-inside-file-based/vite.config.ts b/examples/react/basic-virtual-inside-file-based/vite.config.ts
new file mode 100644
index 0000000000..9cb8cad864
--- /dev/null
+++ b/examples/react/basic-virtual-inside-file-based/vite.config.ts
@@ -0,0 +1,8 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [TanStackRouterVite(), react()],
+})
diff --git a/packages/router-generator/package.json b/packages/router-generator/package.json
index 49ea0bf49b..7530dce359 100644
--- a/packages/router-generator/package.json
+++ b/packages/router-generator/package.json
@@ -63,8 +63,9 @@
"node": ">=12"
},
"dependencies": {
+ "@tanstack/virtual-file-routes": "workspace:^",
+ "tsx": "^4.19.0",
"prettier": "^3.3.3",
- "zod": "^3.23.8",
- "@tanstack/virtual-file-routes": "workspace:^"
+ "zod": "^3.23.8"
}
}
diff --git a/packages/router-generator/src/filesystem/physical/getRouteNodes.ts b/packages/router-generator/src/filesystem/physical/getRouteNodes.ts
index a2d3e26f23..560a38b6ad 100644
--- a/packages/router-generator/src/filesystem/physical/getRouteNodes.ts
+++ b/packages/router-generator/src/filesystem/physical/getRouteNodes.ts
@@ -8,7 +8,13 @@ import {
replaceBackslash,
routePathToVariable,
} from '../../utils'
+import { getRouteNodes as getRouteNodesVirtual } from '../virtual/getRouteNodes'
+import { loadConfigFile } from '../virtual/loadConfigFile'
import { rootPathId } from './rootPathId'
+import type {
+ VirtualRootRoute,
+ VirtualRouteSubtreeConfig,
+} from '@tanstack/virtual-file-routes'
import type { GetRouteNodesResult, RouteNode } from '../../types'
import type { Config } from '../../config'
@@ -47,6 +53,46 @@ export async function getRouteNodes(
return true
})
+ const virtualConfigFile = dirList.find((dirent) => {
+ return dirent.isFile() && dirent.name.match(/__virtual\.[mc]?[jt]s$/)
+ })
+
+ if (virtualConfigFile !== undefined) {
+ const virtualRouteConfigExport = await loadConfigFile(
+ path.resolve(fullDir, virtualConfigFile.name),
+ )
+ let virtualRouteSubtreeConfig: VirtualRouteSubtreeConfig
+ if (typeof virtualRouteConfigExport.default === 'function') {
+ virtualRouteSubtreeConfig = await virtualRouteConfigExport.default()
+ } else {
+ virtualRouteSubtreeConfig = virtualRouteConfigExport.default
+ }
+ const dummyRoot: VirtualRootRoute = {
+ type: 'root',
+ file: '',
+ children: virtualRouteSubtreeConfig,
+ }
+ const { routeNodes: virtualRouteNodes } = await getRouteNodesVirtual({
+ ...config,
+ routesDirectory: fullDir,
+ virtualRouteConfig: dummyRoot,
+ })
+ virtualRouteNodes.forEach((node) => {
+ const filePath = replaceBackslash(path.join(dir, node.filePath))
+ const routePath = `/${dir}${node.routePath}`
+
+ node.variableName = routePathToVariable(
+ `${dir}/${removeExt(node.filePath)}`,
+ )
+ node.routePath = routePath
+ node.filePath = filePath
+ })
+
+ routeNodes.push(...virtualRouteNodes)
+
+ return
+ }
+
await Promise.all(
dirList.map(async (dirent) => {
const fullPath = path.join(fullDir, dirent.name)
diff --git a/packages/router-generator/src/filesystem/virtual/loadConfigFile.ts b/packages/router-generator/src/filesystem/virtual/loadConfigFile.ts
new file mode 100644
index 0000000000..92c63356b2
--- /dev/null
+++ b/packages/router-generator/src/filesystem/virtual/loadConfigFile.ts
@@ -0,0 +1,6 @@
+import { tsImport } from 'tsx/esm/api'
+
+export async function loadConfigFile(filePath: string) {
+ const loaded = await tsImport(filePath, import.meta.url)
+ return loaded
+}
diff --git a/packages/router-generator/tests/generator/virtual-inside-nested/routeTree.snapshot.ts b/packages/router-generator/tests/generator/virtual-inside-nested/routeTree.snapshot.ts
new file mode 100644
index 0000000000..0d0aaa0dce
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual-inside-nested/routeTree.snapshot.ts
@@ -0,0 +1,115 @@
+/* prettier-ignore-start */
+
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file is auto-generated by TanStack Router
+
+// Import Routes
+
+import { Route as rootRoute } from './routes/__root'
+import { Route as IndexImport } from './routes/index'
+import { Route as FooBarImport } from './routes/foo/bar'
+import { Route as fooBarDetailsImport } from './routes/foo/bar/details'
+import { Route as fooBarHomeImport } from './routes/foo/bar/home'
+
+// Create/Update Routes
+
+const IndexRoute = IndexImport.update({
+ path: '/',
+ getParentRoute: () => rootRoute,
+} as any)
+
+const FooBarRoute = FooBarImport.update({
+ path: '/foo/bar',
+ getParentRoute: () => rootRoute,
+} as any)
+
+const fooBarDetailsRoute = fooBarDetailsImport.update({
+ path: '/$id',
+ getParentRoute: () => FooBarRoute,
+} as any)
+
+const fooBarHomeRoute = fooBarHomeImport.update({
+ path: '/',
+ getParentRoute: () => FooBarRoute,
+} as any)
+
+// Populate the FileRoutesByPath interface
+
+declare module '@tanstack/react-router' {
+ interface FileRoutesByPath {
+ '/': {
+ id: '/'
+ path: '/'
+ fullPath: '/'
+ preLoaderRoute: typeof IndexImport
+ parentRoute: typeof rootRoute
+ }
+ '/foo/bar': {
+ id: '/foo/bar'
+ path: '/foo/bar'
+ fullPath: '/foo/bar'
+ preLoaderRoute: typeof FooBarImport
+ parentRoute: typeof rootRoute
+ }
+ '/foo/bar/': {
+ id: '/foo/bar/'
+ path: '/'
+ fullPath: '/foo/bar/'
+ preLoaderRoute: typeof fooBarHomeImport
+ parentRoute: typeof FooBarImport
+ }
+ '/foo/bar/$id': {
+ id: '/foo/bar/$id'
+ path: '/$id'
+ fullPath: '/foo/bar/$id'
+ preLoaderRoute: typeof fooBarDetailsImport
+ parentRoute: typeof FooBarImport
+ }
+ }
+}
+
+// Create and export the route tree
+
+export const routeTree = rootRoute.addChildren({
+ IndexRoute,
+ FooBarRoute: FooBarRoute.addChildren({ fooBarHomeRoute, fooBarDetailsRoute }),
+})
+
+/* prettier-ignore-end */
+
+/* ROUTE_MANIFEST_START
+{
+ "routes": {
+ "__root__": {
+ "filePath": "__root.tsx",
+ "children": [
+ "/",
+ "/foo/bar"
+ ]
+ },
+ "/": {
+ "filePath": "index.tsx"
+ },
+ "/foo/bar": {
+ "filePath": "foo/bar.tsx",
+ "children": [
+ "/foo/bar/",
+ "/foo/bar/$id"
+ ]
+ },
+ "/foo/bar/": {
+ "filePath": "foo/bar/home.tsx",
+ "parent": "/foo/bar"
+ },
+ "/foo/bar/$id": {
+ "filePath": "foo/bar/details.tsx",
+ "parent": "/foo/bar"
+ }
+ }
+}
+ROUTE_MANIFEST_END */
diff --git a/packages/router-generator/tests/generator/virtual-inside-nested/routes/__root.tsx b/packages/router-generator/tests/generator/virtual-inside-nested/routes/__root.tsx
new file mode 100644
index 0000000000..f89644e82d
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual-inside-nested/routes/__root.tsx
@@ -0,0 +1,11 @@
+import * as React from 'react'
+import { Outlet, createRootRoute } from '@tanstack/react-router'
+
+export const Route = createRootRoute({
+ component: () => (
+
+ Hello "__root"!
+
+
+ ),
+})
diff --git a/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar.tsx b/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar.tsx
new file mode 100644
index 0000000000..6ef5a1ca27
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/foo/bar')({
+ component: () => Hello /foo/bar!
,
+})
diff --git a/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/__virtual.ts b/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/__virtual.ts
new file mode 100644
index 0000000000..a732c66101
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/__virtual.ts
@@ -0,0 +1,10 @@
+import {
+ defineVirtualSubtreeConfig,
+ index,
+ route,
+} from '@tanstack/virtual-file-routes'
+
+export default defineVirtualSubtreeConfig([
+ index('home.tsx'),
+ route('$id', 'details.tsx'),
+])
diff --git a/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/details.tsx b/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/details.tsx
new file mode 100644
index 0000000000..59c29910fe
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/details.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/foo/bar/$id')({
+ component: () => Hello /foo/bar/$id!
,
+})
diff --git a/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/home.tsx b/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/home.tsx
new file mode 100644
index 0000000000..b7a0742abf
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/home.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/foo/bar/')({
+ component: () => Hello /foo/bar/!
,
+})
diff --git a/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/route.ts b/packages/router-generator/tests/generator/virtual-inside-nested/routes/foo/bar/route.ts
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/router-generator/tests/generator/virtual-inside-nested/routes/index.tsx b/packages/router-generator/tests/generator/virtual-inside-nested/routes/index.tsx
new file mode 100644
index 0000000000..a680913ded
--- /dev/null
+++ b/packages/router-generator/tests/generator/virtual-inside-nested/routes/index.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/')({
+ component: () => Hello /!
,
+})
diff --git a/packages/virtual-file-routes/src/defineConfig.ts b/packages/virtual-file-routes/src/defineConfig.ts
new file mode 100644
index 0000000000..726d068b80
--- /dev/null
+++ b/packages/virtual-file-routes/src/defineConfig.ts
@@ -0,0 +1,38 @@
+import type { VirtualRouteNode } from './types'
+
+// this is adapted from vite/src/node/config.ts
+
+export type ConfigFnObject = () => TConfig
+export type ConfigFnPromise = () => Promise
+export type ConfigFn = () => TConfig | Promise
+
+export type ConfigExport =
+ | TConfig
+ | Promise
+ | ConfigFnObject
+ | ConfigFnPromise
+ | ConfigFn
+
+export type VirtualRouteSubtreeConfig = Array
+
+/**
+ * Type helper to make it easier to use __virtual.ts
+ * accepts a direct {@link VirtualRouteSubtreeConfig} object, or a function that returns it.
+ */
+export function defineVirtualSubtreeConfig(
+ config: VirtualRouteSubtreeConfig,
+): VirtualRouteSubtreeConfig
+export function defineVirtualSubtreeConfig(
+ config: Promise,
+): Promise
+export function defineVirtualSubtreeConfig(
+ config: ConfigFnObject,
+): ConfigFnObject
+export function defineVirtualSubtreeConfig(
+ config: ConfigExport,
+): ConfigExport
+export function defineVirtualSubtreeConfig(
+ config: ConfigExport,
+): ConfigExport {
+ return config
+}
diff --git a/packages/virtual-file-routes/src/index.ts b/packages/virtual-file-routes/src/index.ts
index 45e3c6b4c0..f52991a13c 100644
--- a/packages/virtual-file-routes/src/index.ts
+++ b/packages/virtual-file-routes/src/index.ts
@@ -7,3 +7,12 @@ export type {
VirtualRootRoute,
VirtualRouteNode,
} from './types'
+
+export { defineVirtualSubtreeConfig } from './defineConfig'
+export type {
+ ConfigExport,
+ ConfigFn,
+ ConfigFnObject,
+ ConfigFnPromise,
+ VirtualRouteSubtreeConfig,
+} from './defineConfig'
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9d0c0a5030..65cb3faa02 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -40,7 +40,7 @@ importers:
version: 1.46.1
'@tanstack/config':
specifier: ^0.13.1
- version: 0.13.1(@types/node@20.14.9)(esbuild@0.21.5)(eslint@9.9.1(jiti@1.21.0))(rollup@4.18.0)(typescript@5.5.3)(vite@5.3.5(@types/node@20.14.9)(terser@5.31.1))
+ version: 0.13.1(@types/node@20.14.9)(esbuild@0.23.1)(eslint@9.9.1(jiti@1.21.0))(rollup@4.18.0)(typescript@5.5.3)(vite@5.3.5(@types/node@20.14.9)(terser@5.31.1))
'@types/node':
specifier: ^20.14.7
version: 20.14.9
@@ -568,6 +568,52 @@ importers:
specifier: ^5.3.5
version: 5.3.5(@types/node@20.14.9)(terser@5.31.1)
+ examples/react/basic-virtual-inside-file-based:
+ dependencies:
+ '@tanstack/react-router':
+ specifier: workspace:*
+ version: link:../../../packages/react-router
+ '@tanstack/router-devtools':
+ specifier: workspace:*
+ version: link:../../../packages/router-devtools
+ '@tanstack/router-plugin':
+ specifier: workspace:*
+ version: link:../../../packages/router-plugin
+ '@tanstack/virtual-file-routes':
+ specifier: workspace:*
+ version: link:../../../packages/virtual-file-routes
+ immer:
+ specifier: ^10.1.1
+ version: 10.1.1
+ react:
+ specifier: ^18.2.0
+ version: 18.3.1
+ react-dom:
+ specifier: ^18.2.0
+ version: 18.3.1(react@18.3.1)
+ redaxios:
+ specifier: ^0.5.1
+ version: 0.5.1
+ zod:
+ specifier: ^3.23.8
+ version: 3.23.8
+ devDependencies:
+ '@playwright/test':
+ specifier: ^1.46.1
+ version: 1.46.1
+ '@types/react':
+ specifier: ^18.2.47
+ version: 18.3.3
+ '@types/react-dom':
+ specifier: ^18.2.18
+ version: 18.3.0
+ '@vitejs/plugin-react':
+ specifier: ^4.3.1
+ version: 4.3.1(vite@5.3.5(@types/node@20.14.9)(terser@5.31.1))
+ vite:
+ specifier: ^5.3.5
+ version: 5.3.5(@types/node@20.14.9)(terser@5.31.1)
+
examples/react/deferred-data:
dependencies:
'@tanstack/react-router':
@@ -1016,16 +1062,16 @@ importers:
version: 18.3.0
html-webpack-plugin:
specifier: ^5.6.0
- version: 5.6.0(@rspack/core@1.0.0(@swc/helpers@0.5.12))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))
+ version: 5.6.0(@rspack/core@1.0.0(@swc/helpers@0.5.12))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))
swc-loader:
specifier: ^0.2.6
- version: 0.2.6(@swc/core@1.7.6(@swc/helpers@0.5.12))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))
+ version: 0.2.6(@swc/core@1.7.6(@swc/helpers@0.5.12))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))
typescript:
specifier: ^5.5.3
version: 5.5.3
webpack:
specifier: ^5.93.0
- version: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)
+ version: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)
webpack-cli:
specifier: ^5.1.4
version: 5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0)
@@ -1980,6 +2026,9 @@ importers:
prettier:
specifier: ^3.3.3
version: 3.3.3
+ tsx:
+ specifier: ^4.19.0
+ version: 4.19.0
zod:
specifier: ^3.23.8
version: 3.23.8
@@ -2045,7 +2094,7 @@ importers:
version: 5.3.5(@types/node@20.14.9)(terser@5.31.1)
webpack:
specifier: '>=5.92.0'
- version: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)
+ version: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)
zod:
specifier: ^3.23.8
version: 3.23.8
@@ -2450,6 +2499,12 @@ packages:
cpu: [ppc64]
os: [aix]
+ '@esbuild/aix-ppc64@0.23.1':
+ resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
'@esbuild/android-arm64@0.17.19':
resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==}
engines: {node: '>=12'}
@@ -2468,6 +2523,12 @@ packages:
cpu: [arm64]
os: [android]
+ '@esbuild/android-arm64@0.23.1':
+ resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
'@esbuild/android-arm@0.17.19':
resolution: {integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==}
engines: {node: '>=12'}
@@ -2486,6 +2547,12 @@ packages:
cpu: [arm]
os: [android]
+ '@esbuild/android-arm@0.23.1':
+ resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
'@esbuild/android-x64@0.17.19':
resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==}
engines: {node: '>=12'}
@@ -2504,6 +2571,12 @@ packages:
cpu: [x64]
os: [android]
+ '@esbuild/android-x64@0.23.1':
+ resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
'@esbuild/darwin-arm64@0.17.19':
resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==}
engines: {node: '>=12'}
@@ -2522,6 +2595,12 @@ packages:
cpu: [arm64]
os: [darwin]
+ '@esbuild/darwin-arm64@0.23.1':
+ resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
'@esbuild/darwin-x64@0.17.19':
resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==}
engines: {node: '>=12'}
@@ -2540,6 +2619,12 @@ packages:
cpu: [x64]
os: [darwin]
+ '@esbuild/darwin-x64@0.23.1':
+ resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
'@esbuild/freebsd-arm64@0.17.19':
resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==}
engines: {node: '>=12'}
@@ -2558,6 +2643,12 @@ packages:
cpu: [arm64]
os: [freebsd]
+ '@esbuild/freebsd-arm64@0.23.1':
+ resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
'@esbuild/freebsd-x64@0.17.19':
resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==}
engines: {node: '>=12'}
@@ -2576,6 +2667,12 @@ packages:
cpu: [x64]
os: [freebsd]
+ '@esbuild/freebsd-x64@0.23.1':
+ resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
'@esbuild/linux-arm64@0.17.19':
resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==}
engines: {node: '>=12'}
@@ -2594,6 +2691,12 @@ packages:
cpu: [arm64]
os: [linux]
+ '@esbuild/linux-arm64@0.23.1':
+ resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
'@esbuild/linux-arm@0.17.19':
resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==}
engines: {node: '>=12'}
@@ -2612,6 +2715,12 @@ packages:
cpu: [arm]
os: [linux]
+ '@esbuild/linux-arm@0.23.1':
+ resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
'@esbuild/linux-ia32@0.17.19':
resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==}
engines: {node: '>=12'}
@@ -2630,6 +2739,12 @@ packages:
cpu: [ia32]
os: [linux]
+ '@esbuild/linux-ia32@0.23.1':
+ resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
'@esbuild/linux-loong64@0.17.19':
resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==}
engines: {node: '>=12'}
@@ -2648,6 +2763,12 @@ packages:
cpu: [loong64]
os: [linux]
+ '@esbuild/linux-loong64@0.23.1':
+ resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
'@esbuild/linux-mips64el@0.17.19':
resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==}
engines: {node: '>=12'}
@@ -2666,6 +2787,12 @@ packages:
cpu: [mips64el]
os: [linux]
+ '@esbuild/linux-mips64el@0.23.1':
+ resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
'@esbuild/linux-ppc64@0.17.19':
resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==}
engines: {node: '>=12'}
@@ -2684,6 +2811,12 @@ packages:
cpu: [ppc64]
os: [linux]
+ '@esbuild/linux-ppc64@0.23.1':
+ resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
'@esbuild/linux-riscv64@0.17.19':
resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==}
engines: {node: '>=12'}
@@ -2702,6 +2835,12 @@ packages:
cpu: [riscv64]
os: [linux]
+ '@esbuild/linux-riscv64@0.23.1':
+ resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
'@esbuild/linux-s390x@0.17.19':
resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==}
engines: {node: '>=12'}
@@ -2720,6 +2859,12 @@ packages:
cpu: [s390x]
os: [linux]
+ '@esbuild/linux-s390x@0.23.1':
+ resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
'@esbuild/linux-x64@0.17.19':
resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==}
engines: {node: '>=12'}
@@ -2738,6 +2883,12 @@ packages:
cpu: [x64]
os: [linux]
+ '@esbuild/linux-x64@0.23.1':
+ resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
'@esbuild/netbsd-x64@0.17.19':
resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==}
engines: {node: '>=12'}
@@ -2756,6 +2907,18 @@ packages:
cpu: [x64]
os: [netbsd]
+ '@esbuild/netbsd-x64@0.23.1':
+ resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-arm64@0.23.1':
+ resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
'@esbuild/openbsd-x64@0.17.19':
resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==}
engines: {node: '>=12'}
@@ -2774,6 +2937,12 @@ packages:
cpu: [x64]
os: [openbsd]
+ '@esbuild/openbsd-x64@0.23.1':
+ resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
'@esbuild/sunos-x64@0.17.19':
resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==}
engines: {node: '>=12'}
@@ -2792,6 +2961,12 @@ packages:
cpu: [x64]
os: [sunos]
+ '@esbuild/sunos-x64@0.23.1':
+ resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
'@esbuild/win32-arm64@0.17.19':
resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==}
engines: {node: '>=12'}
@@ -2810,6 +2985,12 @@ packages:
cpu: [arm64]
os: [win32]
+ '@esbuild/win32-arm64@0.23.1':
+ resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
'@esbuild/win32-ia32@0.17.19':
resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==}
engines: {node: '>=12'}
@@ -2828,6 +3009,12 @@ packages:
cpu: [ia32]
os: [win32]
+ '@esbuild/win32-ia32@0.23.1':
+ resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
'@esbuild/win32-x64@0.17.19':
resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==}
engines: {node: '>=12'}
@@ -2846,6 +3033,12 @@ packages:
cpu: [x64]
os: [win32]
+ '@esbuild/win32-x64@0.23.1':
+ resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
'@eslint-community/eslint-utils@4.4.0':
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -5532,6 +5725,11 @@ packages:
engines: {node: '>=12'}
hasBin: true
+ esbuild@0.23.1:
+ resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==}
+ engines: {node: '>=18'}
+ hasBin: true
+
escalade@3.1.2:
resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
engines: {node: '>=6'}
@@ -8241,6 +8439,11 @@ packages:
tslib@2.7.0:
resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
+ tsx@4.19.0:
+ resolution: {integrity: sha512-bV30kM7bsLZKZIOCHeMNVMJ32/LuJzLVajkQI/qf92J2Qr08ueLQvW00PUZGiuLPP760UINwupgUj8qrSCPUKg==}
+ engines: {node: '>=18.0.0'}
+ hasBin: true
+
turbo-stream@2.2.0:
resolution: {integrity: sha512-FKFg7A0To1VU4CH9YmSMON5QphK0BXjSoiC7D9yMh+mEEbXLUP9qJ4hEt1qcjKtzncs1OpcnjZO8NgrlVbZH+g==}
@@ -9182,6 +9385,9 @@ snapshots:
'@esbuild/aix-ppc64@0.21.5':
optional: true
+ '@esbuild/aix-ppc64@0.23.1':
+ optional: true
+
'@esbuild/android-arm64@0.17.19':
optional: true
@@ -9191,6 +9397,9 @@ snapshots:
'@esbuild/android-arm64@0.21.5':
optional: true
+ '@esbuild/android-arm64@0.23.1':
+ optional: true
+
'@esbuild/android-arm@0.17.19':
optional: true
@@ -9200,6 +9409,9 @@ snapshots:
'@esbuild/android-arm@0.21.5':
optional: true
+ '@esbuild/android-arm@0.23.1':
+ optional: true
+
'@esbuild/android-x64@0.17.19':
optional: true
@@ -9209,6 +9421,9 @@ snapshots:
'@esbuild/android-x64@0.21.5':
optional: true
+ '@esbuild/android-x64@0.23.1':
+ optional: true
+
'@esbuild/darwin-arm64@0.17.19':
optional: true
@@ -9218,6 +9433,9 @@ snapshots:
'@esbuild/darwin-arm64@0.21.5':
optional: true
+ '@esbuild/darwin-arm64@0.23.1':
+ optional: true
+
'@esbuild/darwin-x64@0.17.19':
optional: true
@@ -9227,6 +9445,9 @@ snapshots:
'@esbuild/darwin-x64@0.21.5':
optional: true
+ '@esbuild/darwin-x64@0.23.1':
+ optional: true
+
'@esbuild/freebsd-arm64@0.17.19':
optional: true
@@ -9236,6 +9457,9 @@ snapshots:
'@esbuild/freebsd-arm64@0.21.5':
optional: true
+ '@esbuild/freebsd-arm64@0.23.1':
+ optional: true
+
'@esbuild/freebsd-x64@0.17.19':
optional: true
@@ -9245,6 +9469,9 @@ snapshots:
'@esbuild/freebsd-x64@0.21.5':
optional: true
+ '@esbuild/freebsd-x64@0.23.1':
+ optional: true
+
'@esbuild/linux-arm64@0.17.19':
optional: true
@@ -9254,6 +9481,9 @@ snapshots:
'@esbuild/linux-arm64@0.21.5':
optional: true
+ '@esbuild/linux-arm64@0.23.1':
+ optional: true
+
'@esbuild/linux-arm@0.17.19':
optional: true
@@ -9263,6 +9493,9 @@ snapshots:
'@esbuild/linux-arm@0.21.5':
optional: true
+ '@esbuild/linux-arm@0.23.1':
+ optional: true
+
'@esbuild/linux-ia32@0.17.19':
optional: true
@@ -9272,6 +9505,9 @@ snapshots:
'@esbuild/linux-ia32@0.21.5':
optional: true
+ '@esbuild/linux-ia32@0.23.1':
+ optional: true
+
'@esbuild/linux-loong64@0.17.19':
optional: true
@@ -9281,6 +9517,9 @@ snapshots:
'@esbuild/linux-loong64@0.21.5':
optional: true
+ '@esbuild/linux-loong64@0.23.1':
+ optional: true
+
'@esbuild/linux-mips64el@0.17.19':
optional: true
@@ -9290,6 +9529,9 @@ snapshots:
'@esbuild/linux-mips64el@0.21.5':
optional: true
+ '@esbuild/linux-mips64el@0.23.1':
+ optional: true
+
'@esbuild/linux-ppc64@0.17.19':
optional: true
@@ -9299,6 +9541,9 @@ snapshots:
'@esbuild/linux-ppc64@0.21.5':
optional: true
+ '@esbuild/linux-ppc64@0.23.1':
+ optional: true
+
'@esbuild/linux-riscv64@0.17.19':
optional: true
@@ -9308,6 +9553,9 @@ snapshots:
'@esbuild/linux-riscv64@0.21.5':
optional: true
+ '@esbuild/linux-riscv64@0.23.1':
+ optional: true
+
'@esbuild/linux-s390x@0.17.19':
optional: true
@@ -9317,6 +9565,9 @@ snapshots:
'@esbuild/linux-s390x@0.21.5':
optional: true
+ '@esbuild/linux-s390x@0.23.1':
+ optional: true
+
'@esbuild/linux-x64@0.17.19':
optional: true
@@ -9326,6 +9577,9 @@ snapshots:
'@esbuild/linux-x64@0.21.5':
optional: true
+ '@esbuild/linux-x64@0.23.1':
+ optional: true
+
'@esbuild/netbsd-x64@0.17.19':
optional: true
@@ -9335,6 +9589,12 @@ snapshots:
'@esbuild/netbsd-x64@0.21.5':
optional: true
+ '@esbuild/netbsd-x64@0.23.1':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.23.1':
+ optional: true
+
'@esbuild/openbsd-x64@0.17.19':
optional: true
@@ -9344,6 +9604,9 @@ snapshots:
'@esbuild/openbsd-x64@0.21.5':
optional: true
+ '@esbuild/openbsd-x64@0.23.1':
+ optional: true
+
'@esbuild/sunos-x64@0.17.19':
optional: true
@@ -9353,6 +9616,9 @@ snapshots:
'@esbuild/sunos-x64@0.21.5':
optional: true
+ '@esbuild/sunos-x64@0.23.1':
+ optional: true
+
'@esbuild/win32-arm64@0.17.19':
optional: true
@@ -9362,6 +9628,9 @@ snapshots:
'@esbuild/win32-arm64@0.21.5':
optional: true
+ '@esbuild/win32-arm64@0.23.1':
+ optional: true
+
'@esbuild/win32-ia32@0.17.19':
optional: true
@@ -9371,6 +9640,9 @@ snapshots:
'@esbuild/win32-ia32@0.21.5':
optional: true
+ '@esbuild/win32-ia32@0.23.1':
+ optional: true
+
'@esbuild/win32-x64@0.17.19':
optional: true
@@ -9380,6 +9652,9 @@ snapshots:
'@esbuild/win32-x64@0.21.5':
optional: true
+ '@esbuild/win32-x64@0.23.1':
+ optional: true
+
'@eslint-community/eslint-utils@4.4.0(eslint@9.9.1(jiti@1.21.0))':
dependencies:
eslint: 9.9.1(jiti@1.21.0)
@@ -10609,14 +10884,14 @@ snapshots:
dependencies:
'@swc/counter': 0.1.3
- '@tanstack/config@0.13.1(@types/node@20.14.9)(esbuild@0.21.5)(eslint@9.9.1(jiti@1.21.0))(rollup@4.18.0)(typescript@5.5.3)(vite@5.3.5(@types/node@20.14.9)(terser@5.31.1))':
+ '@tanstack/config@0.13.1(@types/node@20.14.9)(esbuild@0.23.1)(eslint@9.9.1(jiti@1.21.0))(rollup@4.18.0)(typescript@5.5.3)(vite@5.3.5(@types/node@20.14.9)(terser@5.31.1))':
dependencies:
'@commitlint/parse': 19.0.3
'@eslint/js': 9.9.1
'@stylistic/eslint-plugin-js': 2.7.1(eslint@9.9.1(jiti@1.21.0))
commander: 12.1.0
current-git-branch: 1.1.0
- esbuild-register: 3.6.0(esbuild@0.21.5)
+ esbuild-register: 3.6.0(esbuild@0.23.1)
eslint-plugin-import-x: 4.1.1(eslint@9.9.1(jiti@1.21.0))(typescript@5.5.3)
eslint-plugin-n: 17.10.2(eslint@9.9.1(jiti@1.21.0))
globals: 15.9.0
@@ -11225,19 +11500,19 @@ snapshots:
'@webassemblyjs/ast': 1.12.1
'@xtuc/long': 4.2.2
- '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))':
+ '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))':
dependencies:
- webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)
+ webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)
webpack-cli: 5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0)
- '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))':
+ '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))':
dependencies:
- webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)
+ webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)
webpack-cli: 5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0)
- '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0))(webpack-dev-server@5.0.4(webpack-cli@5.1.4)(webpack@5.93.0))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))':
+ '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0))(webpack-dev-server@5.0.4(webpack-cli@5.1.4)(webpack@5.93.0))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))':
dependencies:
- webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)
+ webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)
webpack-cli: 5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0)
optionalDependencies:
webpack-dev-server: 5.0.4(webpack-cli@5.1.4)(webpack@5.93.0)
@@ -12186,10 +12461,10 @@ snapshots:
es-module-lexer@1.5.4: {}
- esbuild-register@3.6.0(esbuild@0.21.5):
+ esbuild-register@3.6.0(esbuild@0.23.1):
dependencies:
debug: 4.3.6
- esbuild: 0.21.5
+ esbuild: 0.23.1
transitivePeerDependencies:
- supports-color
@@ -12270,6 +12545,33 @@ snapshots:
'@esbuild/win32-ia32': 0.21.5
'@esbuild/win32-x64': 0.21.5
+ esbuild@0.23.1:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.23.1
+ '@esbuild/android-arm': 0.23.1
+ '@esbuild/android-arm64': 0.23.1
+ '@esbuild/android-x64': 0.23.1
+ '@esbuild/darwin-arm64': 0.23.1
+ '@esbuild/darwin-x64': 0.23.1
+ '@esbuild/freebsd-arm64': 0.23.1
+ '@esbuild/freebsd-x64': 0.23.1
+ '@esbuild/linux-arm': 0.23.1
+ '@esbuild/linux-arm64': 0.23.1
+ '@esbuild/linux-ia32': 0.23.1
+ '@esbuild/linux-loong64': 0.23.1
+ '@esbuild/linux-mips64el': 0.23.1
+ '@esbuild/linux-ppc64': 0.23.1
+ '@esbuild/linux-riscv64': 0.23.1
+ '@esbuild/linux-s390x': 0.23.1
+ '@esbuild/linux-x64': 0.23.1
+ '@esbuild/netbsd-x64': 0.23.1
+ '@esbuild/openbsd-arm64': 0.23.1
+ '@esbuild/openbsd-x64': 0.23.1
+ '@esbuild/sunos-x64': 0.23.1
+ '@esbuild/win32-arm64': 0.23.1
+ '@esbuild/win32-ia32': 0.23.1
+ '@esbuild/win32-x64': 0.23.1
+
escalade@3.1.2: {}
escape-html@1.0.3: {}
@@ -13022,7 +13324,7 @@ snapshots:
lodash: 4.17.21
tapable: 2.2.1
- html-webpack-plugin@5.6.0(@rspack/core@1.0.0(@swc/helpers@0.5.12))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)):
+ html-webpack-plugin@5.6.0(@rspack/core@1.0.0(@swc/helpers@0.5.12))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)):
dependencies:
'@types/html-minifier-terser': 6.1.0
html-minifier-terser: 6.1.0
@@ -13031,7 +13333,7 @@ snapshots:
tapable: 2.2.1
optionalDependencies:
'@rspack/core': 1.0.0(@swc/helpers@0.5.12)
- webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)
+ webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)
htmlparser2@6.1.0:
dependencies:
@@ -15049,11 +15351,11 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
- swc-loader@0.2.6(@swc/core@1.7.6(@swc/helpers@0.5.12))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)):
+ swc-loader@0.2.6(@swc/core@1.7.6(@swc/helpers@0.5.12))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)):
dependencies:
'@swc/core': 1.7.6(@swc/helpers@0.5.12)
'@swc/counter': 0.1.3
- webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)
+ webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)
swr@2.2.5(react@18.3.1):
dependencies:
@@ -15124,29 +15426,29 @@ snapshots:
ansi-escapes: 4.3.2
supports-hyperlinks: 2.3.0
- terser-webpack-plugin@5.3.10(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)):
+ terser-webpack-plugin@5.3.10(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
jest-worker: 27.5.1
schema-utils: 3.3.0
serialize-javascript: 6.0.2
terser: 5.31.1
- webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)
+ webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)
optionalDependencies:
'@swc/core': 1.7.6(@swc/helpers@0.5.12)
- esbuild: 0.21.5
+ esbuild: 0.23.1
- terser-webpack-plugin@5.3.10(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)):
+ terser-webpack-plugin@5.3.10(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
jest-worker: 27.5.1
schema-utils: 3.3.0
serialize-javascript: 6.0.2
terser: 5.31.1
- webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)
+ webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)
optionalDependencies:
'@swc/core': 1.7.6(@swc/helpers@0.5.12)
- esbuild: 0.21.5
+ esbuild: 0.23.1
terser@5.31.1:
dependencies:
@@ -15247,6 +15549,13 @@ snapshots:
tslib@2.7.0: {}
+ tsx@4.19.0:
+ dependencies:
+ esbuild: 0.23.1
+ get-tsconfig: 4.7.5
+ optionalDependencies:
+ fsevents: 2.3.3
+
turbo-stream@2.2.0: {}
turbo-stream@2.3.0: {}
@@ -15684,9 +15993,9 @@ snapshots:
webpack-cli@5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0):
dependencies:
'@discoveryjs/json-ext': 0.5.7
- '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))
- '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))
- '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0))(webpack-dev-server@5.0.4(webpack-cli@5.1.4)(webpack@5.93.0))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))
+ '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))
+ '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))
+ '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0))(webpack-dev-server@5.0.4(webpack-cli@5.1.4)(webpack@5.93.0))(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))
colorette: 2.0.20
commander: 10.0.1
cross-spawn: 7.0.3
@@ -15695,12 +16004,12 @@ snapshots:
import-local: 3.1.0
interpret: 3.1.1
rechoir: 0.8.0
- webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)
+ webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)
webpack-merge: 5.10.0
optionalDependencies:
webpack-dev-server: 5.0.4(webpack-cli@5.1.4)(webpack@5.93.0)
- webpack-dev-middleware@7.2.1(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)):
+ webpack-dev-middleware@7.2.1(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)):
dependencies:
colorette: 2.0.20
memfs: 4.9.3
@@ -15709,7 +16018,7 @@ snapshots:
range-parser: 1.2.1
schema-utils: 4.2.0
optionalDependencies:
- webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)
+ webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)
webpack-dev-server@5.0.4(webpack-cli@5.1.4)(webpack@5.93.0):
dependencies:
@@ -15741,10 +16050,10 @@ snapshots:
serve-index: 1.9.1
sockjs: 0.3.24
spdy: 4.0.2
- webpack-dev-middleware: 7.2.1(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))
+ webpack-dev-middleware: 7.2.1(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))
ws: 8.18.0
optionalDependencies:
- webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)
+ webpack: 5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)
webpack-cli: 5.1.4(webpack-dev-server@5.0.4)(webpack@5.93.0)
transitivePeerDependencies:
- bufferutil
@@ -15762,7 +16071,7 @@ snapshots:
webpack-virtual-modules@0.6.2: {}
- webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5):
+ webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1):
dependencies:
'@types/eslint-scope': 3.7.7
'@types/estree': 1.0.5
@@ -15785,7 +16094,7 @@ snapshots:
neo-async: 2.6.2
schema-utils: 3.3.0
tapable: 2.2.1
- terser-webpack-plugin: 5.3.10(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5))
+ terser-webpack-plugin: 5.3.10(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1))
watchpack: 2.4.1
webpack-sources: 3.2.3
transitivePeerDependencies:
@@ -15793,7 +16102,7 @@ snapshots:
- esbuild
- uglify-js
- webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4):
+ webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4):
dependencies:
'@types/eslint-scope': 3.7.7
'@types/estree': 1.0.5
@@ -15816,7 +16125,7 @@ snapshots:
neo-async: 2.6.2
schema-utils: 3.3.0
tapable: 2.2.1
- terser-webpack-plugin: 5.3.10(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))
+ terser-webpack-plugin: 5.3.10(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.93.0(@swc/core@1.7.6(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))
watchpack: 2.4.1
webpack-sources: 3.2.3
optionalDependencies:
From 3ecffa39b9699e3625acfa3ee41d01aa21b98c6b Mon Sep 17 00:00:00 2001
From: Tanner Linsley
Date: Thu, 5 Sep 2024 21:23:14 +0000
Subject: [PATCH 056/154] release: v1.56.0
---
examples/react/authenticated-routes/package.json | 2 +-
examples/react/basic-file-based-codesplitting/package.json | 2 +-
examples/react/basic-file-based/package.json | 2 +-
examples/react/basic-react-query-file-based/package.json | 2 +-
examples/react/basic-ssr-file-based/package.json | 4 ++--
examples/react/basic-ssr-streaming-file-based/package.json | 4 ++--
examples/react/basic-virtual-file-based/package.json | 4 ++--
examples/react/basic-virtual-inside-file-based/package.json | 4 ++--
examples/react/kitchen-sink-file-based/package.json | 2 +-
.../react/kitchen-sink-react-query-file-based/package.json | 2 +-
examples/react/large-file-based/package.json | 2 +-
examples/react/quickstart-file-based/package.json | 2 +-
examples/react/quickstart-rspack-file-based/package.json | 2 +-
examples/react/quickstart-webpack-file-based/package.json | 2 +-
examples/react/search-validator-adapters/package.json | 2 +-
examples/react/start-basic-auth/package.json | 4 ++--
examples/react/start-basic-counter/package.json | 2 +-
examples/react/start-basic-react-query/package.json | 4 ++--
examples/react/start-basic-rsc/package.json | 4 ++--
examples/react/start-basic/package.json | 4 ++--
examples/react/start-clerk-basic/package.json | 4 ++--
examples/react/start-convex-trellaux/package.json | 4 ++--
examples/react/start-trellaux/package.json | 4 ++--
examples/react/with-trpc-react-query/package.json | 2 +-
examples/react/with-trpc/package.json | 2 +-
packages/router-cli/package.json | 2 +-
packages/router-generator/package.json | 2 +-
packages/router-plugin/package.json | 2 +-
packages/router-vite-plugin/package.json | 2 +-
packages/start/package.json | 2 +-
packages/virtual-file-routes/package.json | 2 +-
31 files changed, 42 insertions(+), 42 deletions(-)
diff --git a/examples/react/authenticated-routes/package.json b/examples/react/authenticated-routes/package.json
index 8e9632571e..2da91739dd 100644
--- a/examples/react/authenticated-routes/package.json
+++ b/examples/react/authenticated-routes/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-file-based-codesplitting/package.json b/examples/react/basic-file-based-codesplitting/package.json
index bfde4a0650..de299ca889 100644
--- a/examples/react/basic-file-based-codesplitting/package.json
+++ b/examples/react/basic-file-based-codesplitting/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-file-based/package.json b/examples/react/basic-file-based/package.json
index 13ce3a700b..7e9845f3a6 100644
--- a/examples/react/basic-file-based/package.json
+++ b/examples/react/basic-file-based/package.json
@@ -12,7 +12,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-react-query-file-based/package.json b/examples/react/basic-react-query-file-based/package.json
index 1b7634cd56..b58357c656 100644
--- a/examples/react/basic-react-query-file-based/package.json
+++ b/examples/react/basic-react-query-file-based/package.json
@@ -14,7 +14,7 @@
"@tanstack/react-query-devtools": "^5.51.21",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-ssr-file-based/package.json b/examples/react/basic-ssr-file-based/package.json
index 5f35d21b3e..afda40e072 100644
--- a/examples/react/basic-ssr-file-based/package.json
+++ b/examples/react/basic-ssr-file-based/package.json
@@ -13,8 +13,8 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
- "@tanstack/start": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
+ "@tanstack/start": "^1.56.0",
"get-port": "^7.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-ssr-streaming-file-based/package.json b/examples/react/basic-ssr-streaming-file-based/package.json
index 285cf16015..7b6e75452b 100644
--- a/examples/react/basic-ssr-streaming-file-based/package.json
+++ b/examples/react/basic-ssr-streaming-file-based/package.json
@@ -13,8 +13,8 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
- "@tanstack/start": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
+ "@tanstack/start": "^1.56.0",
"get-port": "^7.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-virtual-file-based/package.json b/examples/react/basic-virtual-file-based/package.json
index 971f8ec8b7..b1495475a2 100644
--- a/examples/react/basic-virtual-file-based/package.json
+++ b/examples/react/basic-virtual-file-based/package.json
@@ -12,8 +12,8 @@
"dependencies": {
"@tanstack/react-router": "^1.52.5",
"@tanstack/router-devtools": "^1.52.5",
- "@tanstack/router-plugin": "^1.55.0",
- "@tanstack/virtual-file-routes": "^1.52.5",
+ "@tanstack/router-plugin": "^1.56.0",
+ "@tanstack/virtual-file-routes": "^1.56.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/basic-virtual-inside-file-based/package.json b/examples/react/basic-virtual-inside-file-based/package.json
index e17cf99fd0..176b9c5811 100644
--- a/examples/react/basic-virtual-inside-file-based/package.json
+++ b/examples/react/basic-virtual-inside-file-based/package.json
@@ -11,8 +11,8 @@
"dependencies": {
"@tanstack/react-router": "^1.52.5",
"@tanstack/router-devtools": "^1.52.5",
- "@tanstack/router-plugin": "^1.55.0",
- "@tanstack/virtual-file-routes": "^1.52.5",
+ "@tanstack/router-plugin": "^1.56.0",
+ "@tanstack/virtual-file-routes": "^1.56.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/kitchen-sink-file-based/package.json b/examples/react/kitchen-sink-file-based/package.json
index 6b3259f541..c8cfca9e0b 100644
--- a/examples/react/kitchen-sink-file-based/package.json
+++ b/examples/react/kitchen-sink-file-based/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/kitchen-sink-react-query-file-based/package.json b/examples/react/kitchen-sink-react-query-file-based/package.json
index 2f63e43d85..7a33baf629 100644
--- a/examples/react/kitchen-sink-react-query-file-based/package.json
+++ b/examples/react/kitchen-sink-react-query-file-based/package.json
@@ -13,7 +13,7 @@
"@tanstack/react-query-devtools": "^5.51.21",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/large-file-based/package.json b/examples/react/large-file-based/package.json
index 913581b109..9669e0131c 100644
--- a/examples/react/large-file-based/package.json
+++ b/examples/react/large-file-based/package.json
@@ -14,7 +14,7 @@
"@tanstack/react-query": "^5.51.21",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/quickstart-file-based/package.json b/examples/react/quickstart-file-based/package.json
index f8cd564ada..b59d99373f 100644
--- a/examples/react/quickstart-file-based/package.json
+++ b/examples/react/quickstart-file-based/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/examples/react/quickstart-rspack-file-based/package.json b/examples/react/quickstart-rspack-file-based/package.json
index ed04832833..724364a9e7 100644
--- a/examples/react/quickstart-rspack-file-based/package.json
+++ b/examples/react/quickstart-rspack-file-based/package.json
@@ -16,7 +16,7 @@
"devDependencies": {
"@rsbuild/core": "1.0.1-rc.0",
"@rsbuild/plugin-react": "1.0.1-rc.0",
- "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"typescript": "^5.5.3"
diff --git a/examples/react/quickstart-webpack-file-based/package.json b/examples/react/quickstart-webpack-file-based/package.json
index ee2dc11560..9873d5c289 100644
--- a/examples/react/quickstart-webpack-file-based/package.json
+++ b/examples/react/quickstart-webpack-file-based/package.json
@@ -14,7 +14,7 @@
},
"devDependencies": {
"@swc/core": "^1.7.6",
- "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"html-webpack-plugin": "^5.6.0",
diff --git a/examples/react/search-validator-adapters/package.json b/examples/react/search-validator-adapters/package.json
index d4c5974e1e..d0da00f6c4 100644
--- a/examples/react/search-validator-adapters/package.json
+++ b/examples/react/search-validator-adapters/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
"@tanstack/router-zod-adapter": "^1.53.1",
"@tanstack/router-valibot-adapter": "^1.53.1",
"@tanstack/router-arktype-adapter": "^1.53.1",
diff --git a/examples/react/start-basic-auth/package.json b/examples/react/start-basic-auth/package.json
index dc38e12329..2b26d7fc69 100644
--- a/examples/react/start-basic-auth/package.json
+++ b/examples/react/start-basic-auth/package.json
@@ -16,8 +16,8 @@
"@prisma/client": "5.17.0",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
- "@tanstack/start": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
+ "@tanstack/start": "^1.56.0",
"@vitejs/plugin-react": "^4.3.1",
"dotenv": "^16.4.5",
"isbot": "^5.1.12",
diff --git a/examples/react/start-basic-counter/package.json b/examples/react/start-basic-counter/package.json
index d0ff148bec..0ce7c43421 100644
--- a/examples/react/start-basic-counter/package.json
+++ b/examples/react/start-basic-counter/package.json
@@ -12,7 +12,7 @@
},
"dependencies": {
"@tanstack/react-router": "^1.53.1",
- "@tanstack/start": "^1.55.0",
+ "@tanstack/start": "^1.56.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"vinxi": "0.4.2"
diff --git a/examples/react/start-basic-react-query/package.json b/examples/react/start-basic-react-query/package.json
index 68a5ba120e..7d505a24de 100644
--- a/examples/react/start-basic-react-query/package.json
+++ b/examples/react/start-basic-react-query/package.json
@@ -17,8 +17,8 @@
"@tanstack/react-router": "^1.53.1",
"@tanstack/react-router-with-query": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
- "@tanstack/start": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
+ "@tanstack/start": "^1.56.0",
"@vitejs/plugin-react": "^4.3.1",
"isbot": "^5.1.14",
"react": "^18.3.1",
diff --git a/examples/react/start-basic-rsc/package.json b/examples/react/start-basic-rsc/package.json
index 774c6b8a14..cf99d3c7fa 100644
--- a/examples/react/start-basic-rsc/package.json
+++ b/examples/react/start-basic-rsc/package.json
@@ -14,8 +14,8 @@
"@babel/plugin-syntax-typescript": "^7.24.7",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
- "@tanstack/start": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
+ "@tanstack/start": "^1.56.0",
"redaxios": "^0.5.1",
"tailwind-merge": "^2.5.2",
"vinxi": "0.4.2"
diff --git a/examples/react/start-basic/package.json b/examples/react/start-basic/package.json
index 314336f9b4..08b42bc37d 100644
--- a/examples/react/start-basic/package.json
+++ b/examples/react/start-basic/package.json
@@ -14,8 +14,8 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
- "@tanstack/start": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
+ "@tanstack/start": "^1.56.0",
"@vitejs/plugin-react": "^4.3.1",
"isbot": "^5.1.14",
"react": "^18.3.1",
diff --git a/examples/react/start-clerk-basic/package.json b/examples/react/start-clerk-basic/package.json
index c3e09fbe5c..6b31378646 100644
--- a/examples/react/start-clerk-basic/package.json
+++ b/examples/react/start-clerk-basic/package.json
@@ -15,8 +15,8 @@
"@clerk/tanstack-start": "0.3.0-snapshot.vdf04997",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
- "@tanstack/start": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
+ "@tanstack/start": "^1.56.0",
"@vitejs/plugin-react": "^4.3.1",
"dotenv": "^16.4.5",
"isbot": "^5.1.12",
diff --git a/examples/react/start-convex-trellaux/package.json b/examples/react/start-convex-trellaux/package.json
index 1d1e4d36c5..74245a03bf 100644
--- a/examples/react/start-convex-trellaux/package.json
+++ b/examples/react/start-convex-trellaux/package.json
@@ -18,8 +18,8 @@
"@tanstack/react-router": "^1.53.1",
"@tanstack/react-router-with-query": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
- "@tanstack/start": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
+ "@tanstack/start": "^1.56.0",
"@vitejs/plugin-react": "^4.3.1",
"@convex-dev/react-query": "0.0.0-alpha.5",
"concurrently": "^8.2.2",
diff --git a/examples/react/start-trellaux/package.json b/examples/react/start-trellaux/package.json
index a78d1de034..c89e68819f 100644
--- a/examples/react/start-trellaux/package.json
+++ b/examples/react/start-trellaux/package.json
@@ -16,8 +16,8 @@
"@tanstack/react-router": "^1.53.1",
"@tanstack/react-router-with-query": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
- "@tanstack/start": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
+ "@tanstack/start": "^1.56.0",
"@vitejs/plugin-react": "^4.3.1",
"isbot": "^5.1.14",
"ky": "^1.5.0",
diff --git a/examples/react/with-trpc-react-query/package.json b/examples/react/with-trpc-react-query/package.json
index ab142de533..3adc65d66d 100644
--- a/examples/react/with-trpc-react-query/package.json
+++ b/examples/react/with-trpc-react-query/package.json
@@ -12,7 +12,7 @@
"@tanstack/react-query-devtools": "^5.51.21",
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
"@trpc/client": "11.0.0-rc.477",
"@trpc/react-query": "11.0.0-rc.477",
"@trpc/server": "11.0.0-rc.477",
diff --git a/examples/react/with-trpc/package.json b/examples/react/with-trpc/package.json
index f98377b057..63cd95463a 100644
--- a/examples/react/with-trpc/package.json
+++ b/examples/react/with-trpc/package.json
@@ -10,7 +10,7 @@
"dependencies": {
"@tanstack/react-router": "^1.53.1",
"@tanstack/router-devtools": "^1.53.1",
- "@tanstack/router-plugin": "^1.55.0",
+ "@tanstack/router-plugin": "^1.56.0",
"@trpc/client": "11.0.0-rc.477",
"@trpc/server": "11.0.0-rc.477",
"react": "^18.2.0",
diff --git a/packages/router-cli/package.json b/packages/router-cli/package.json
index 6bff22784d..8fc500382b 100644
--- a/packages/router-cli/package.json
+++ b/packages/router-cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/router-cli",
- "version": "1.55.0",
+ "version": "1.56.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/router-generator/package.json b/packages/router-generator/package.json
index 7530dce359..513080a9f7 100644
--- a/packages/router-generator/package.json
+++ b/packages/router-generator/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/router-generator",
- "version": "1.55.0",
+ "version": "1.56.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/router-plugin/package.json b/packages/router-plugin/package.json
index 8f9dcd4ae6..13252e21c1 100644
--- a/packages/router-plugin/package.json
+++ b/packages/router-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/router-plugin",
- "version": "1.55.0",
+ "version": "1.56.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/router-vite-plugin/package.json b/packages/router-vite-plugin/package.json
index 03f3156b80..42aec0ab11 100644
--- a/packages/router-vite-plugin/package.json
+++ b/packages/router-vite-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/router-vite-plugin",
- "version": "1.55.0",
+ "version": "1.56.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/start/package.json b/packages/start/package.json
index 0a3a81339b..4d46a40ea3 100644
--- a/packages/start/package.json
+++ b/packages/start/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/start",
- "version": "1.55.0",
+ "version": "1.56.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/virtual-file-routes/package.json b/packages/virtual-file-routes/package.json
index b14dfd8e65..ed77b28bb6 100644
--- a/packages/virtual-file-routes/package.json
+++ b/packages/virtual-file-routes/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/virtual-file-routes",
- "version": "1.54.0",
+ "version": "1.56.0",
"description": "Modern and scalable routing for React applications",
"author": "Tanner Linsley",
"license": "MIT",
From 0482da561a342292409254cbd4b9fdab75015db5 Mon Sep 17 00:00:00 2001
From: Christopher Horobin
Date: Fri, 6 Sep 2024 01:33:37 +0200
Subject: [PATCH 057/154] perf(react-router): constant editor performance
regardless how large a file based route tree is (#2243)
---
.gitignore | 3 -
.../large-file-based/src/routeTree.gen.ts | 123 ++-
packages/react-router/src/Matches.tsx | 37 +-
packages/react-router/src/RouterProvider.tsx | 8 +-
packages/react-router/src/fileRoute.ts | 26 +-
packages/react-router/src/index.tsx | 11 +-
packages/react-router/src/link.tsx | 157 ++--
packages/react-router/src/redirects.ts | 16 +-
packages/react-router/src/route.ts | 107 ++-
packages/react-router/src/routeInfo.ts | 154 +++-
packages/react-router/src/router.ts | 14 +-
packages/react-router/src/useLoaderData.tsx | 6 +-
packages/react-router/src/useLoaderDeps.tsx | 6 +-
packages/react-router/src/useMatch.tsx | 12 +-
packages/react-router/src/useNavigate.tsx | 10 +-
packages/react-router/src/useParams.tsx | 13 +-
packages/react-router/src/useRouteContext.ts | 11 +-
packages/react-router/src/useSearch.tsx | 15 +-
.../react-router/tests/Matches.test-d.tsx | 1 -
packages/react-router/tests/link.test-d.tsx | 17 +-
packages/react-router/tests/navigate.test.tsx | 22 +-
.../react-router/tests/redirects.test-d.tsx | 2 +-
packages/react-router/tests/route.test-d.tsx | 25 +-
packages/react-router/tests/router.test-d.tsx | 68 ++
.../react-router/tests/useNavigate.test-d.tsx | 2 +-
packages/router-generator/package.json | 3 +
packages/router-generator/src/generator.ts | 133 ++-
.../append-and-prepend/routeTree.gen.ts | 86 ++
.../append-and-prepend/routeTree.snapshot.ts | 33 +-
.../append-and-prepend/routes/__root.tsx | 4 +-
.../append-and-prepend/routes/index.tsx | 18 +-
.../generator/custom-tokens/routeTree.gen.ts | 291 +++++++
.../custom-tokens/routeTree.snapshot.ts | 116 ++-
.../generator/custom-tokens/routes/_1nd3x.tsx | 6 +-
.../generator/custom-tokens/routes/__root.tsx | 12 +-
.../custom-tokens/routes/blog/$slug.tsx | 6 +-
.../custom-tokens/routes/blog/_1nd3x.tsx | 6 +-
.../custom-tokens/routes/blog/_r0ut3_.tsx | 6 +-
.../routes/posts/$postId/_1nd3x.tsx | 6 +-
.../routes/posts/$postId/deep.tsx | 6 +-
.../custom-tokens/routes/posts/_1nd3x.tsx | 6 +-
.../custom-tokens/routes/posts/_r0ut3_.tsx | 6 +-
.../file-modification/post.$postId.tsx | 45 +
.../file-modification/routeTree.gen.ts | 165 ++++
.../file-modification/routeTree.snapshot.ts | 53 +-
.../file-modification/routes/__root.tsx | 12 +-
.../file-modification/snapshot/bar.lazy.tsx | 9 +-
.../file-modification/snapshot/empty.lazy.tsx | 9 +-
.../file-modification/snapshot/empty.tsx | 9 +-
.../file-modification/snapshot/foo.tsx | 9 +-
.../snapshot/initiallyEmpty.lazy.tsx | 9 +-
.../snapshot/initiallyEmpty.tsx | 9 +-
.../snapshot/initiallyLazy.tsx | 9 +-
.../file-modification/template.lazy.tsx | 2 +
.../generator/file-modification/template.tsx | 9 +-
.../tests/generator/flat/routeTree.gen.ts | 316 +++++++
.../generator/flat/routeTree.snapshot.ts | 128 ++-
.../generator/nested-layouts/routeTree.gen.ts | 816 ++++++++++++++++++
.../nested-layouts/routeTree.snapshot.ts | 340 +++++++-
.../tests/generator/nested/routeTree.gen.ts | 316 +++++++
.../generator/nested/routeTree.snapshot.ts | 125 ++-
.../tests/generator/nested/routes/__root.tsx | 12 +-
.../generator/nested/routes/blog/$slug.tsx | 6 +-
.../generator/nested/routes/blog/index.tsx | 6 +-
.../generator/nested/routes/blog/route.tsx | 6 +-
.../generator/nested/routes/blog_/stats.tsx | 6 +-
.../tests/generator/nested/routes/index.tsx | 6 +-
.../nested/routes/posts/$postId/deep.tsx | 9 +-
.../nested/routes/posts/$postId/index.tsx | 9 +-
.../generator/nested/routes/posts/index.tsx | 6 +-
.../generator/nested/routes/posts/route.tsx | 6 +-
.../tests/generator/nested/tests.test-d.ts | 534 ++++++++++++
.../generator/no-manifest/routeTree.gen.ts | 72 ++
.../no-manifest/routeTree.snapshot.ts | 33 +-
.../generator/route-groups/routeTree.gen.ts | 88 ++
.../route-groups/routeTree.snapshot.ts | 33 +-
.../generator/single-level/routeTree.gen.ts | 110 +++
.../single-level/routeTree.snapshot.ts | 38 +-
.../virtual-inside-nested/routeTree.gen.ts | 166 ++++
.../routeTree.snapshot.ts | 59 +-
.../tests/generator/virtual/routeTree.gen.ts | 354 ++++++++
.../generator/virtual/routeTree.snapshot.ts | 146 +++-
.../tests/generator/virtual/routes/root.tsx | 2 +-
packages/router-generator/tsconfig.json | 7 +-
pnpm-lock.yaml | 4 +
85 files changed, 5345 insertions(+), 373 deletions(-)
create mode 100644 packages/router-generator/tests/generator/append-and-prepend/routeTree.gen.ts
create mode 100644 packages/router-generator/tests/generator/custom-tokens/routeTree.gen.ts
create mode 100644 packages/router-generator/tests/generator/file-modification/post.$postId.tsx
create mode 100644 packages/router-generator/tests/generator/file-modification/routeTree.gen.ts
create mode 100644 packages/router-generator/tests/generator/flat/routeTree.gen.ts
create mode 100644 packages/router-generator/tests/generator/nested-layouts/routeTree.gen.ts
create mode 100644 packages/router-generator/tests/generator/nested/routeTree.gen.ts
create mode 100644 packages/router-generator/tests/generator/nested/tests.test-d.ts
create mode 100644 packages/router-generator/tests/generator/no-manifest/routeTree.gen.ts
create mode 100644 packages/router-generator/tests/generator/route-groups/routeTree.gen.ts
create mode 100644 packages/router-generator/tests/generator/single-level/routeTree.gen.ts
create mode 100644 packages/router-generator/tests/generator/virtual-inside-nested/routeTree.gen.ts
create mode 100644 packages/router-generator/tests/generator/virtual/routeTree.gen.ts
diff --git a/.gitignore b/.gitignore
index ce8d7b7cd9..aa0f287284 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,9 +20,6 @@ coverage
*.tgz
.wrangler
-# tests
-packages/router-generator/tests/**/*.gen.ts
-
# misc
.DS_Store
.env
diff --git a/examples/react/large-file-based/src/routeTree.gen.ts b/examples/react/large-file-based/src/routeTree.gen.ts
index 2205993a25..f60b8d145f 100644
--- a/examples/react/large-file-based/src/routeTree.gen.ts
+++ b/examples/react/large-file-based/src/routeTree.gen.ts
@@ -127,18 +127,117 @@ declare module '@tanstack/react-router' {
// Create and export the route tree
-export const routeTree = rootRoute.addChildren({
- IndexRoute,
- ParamsRouteRoute: ParamsRouteRoute.addChildren({
- ParamsParamsPlaceholderRoute,
- }),
- SearchRouteRoute: SearchRouteRoute.addChildren({
- SearchSearchPlaceholderRoute,
- }),
- AbsoluteRoute,
- LinkPropsRoute,
- RelativeRoute,
-})
+interface ParamsRouteRouteChildren {
+ ParamsParamsPlaceholderRoute: typeof ParamsParamsPlaceholderRoute
+}
+
+const ParamsRouteRouteChildren: ParamsRouteRouteChildren = {
+ ParamsParamsPlaceholderRoute: ParamsParamsPlaceholderRoute,
+}
+
+const ParamsRouteRouteWithChildren = ParamsRouteRoute._addFileChildren(
+ ParamsRouteRouteChildren,
+)
+
+interface SearchRouteRouteChildren {
+ SearchSearchPlaceholderRoute: typeof SearchSearchPlaceholderRoute
+}
+
+const SearchRouteRouteChildren: SearchRouteRouteChildren = {
+ SearchSearchPlaceholderRoute: SearchSearchPlaceholderRoute,
+}
+
+const SearchRouteRouteWithChildren = SearchRouteRoute._addFileChildren(
+ SearchRouteRouteChildren,
+)
+
+interface FileRoutesByFullPath {
+ '/': typeof IndexRoute
+ '/params': typeof ParamsRouteRouteWithChildren
+ '/search': typeof SearchRouteRouteWithChildren
+ '/absolute': typeof AbsoluteRoute
+ '/linkProps': typeof LinkPropsRoute
+ '/relative': typeof RelativeRoute
+ '/params/$paramsPlaceholder': typeof ParamsParamsPlaceholderRoute
+ '/search/searchPlaceholder': typeof SearchSearchPlaceholderRoute
+}
+
+interface FileRoutesByTo {
+ '/': typeof IndexRoute
+ '/params': typeof ParamsRouteRouteWithChildren
+ '/search': typeof SearchRouteRouteWithChildren
+ '/absolute': typeof AbsoluteRoute
+ '/linkProps': typeof LinkPropsRoute
+ '/relative': typeof RelativeRoute
+ '/params/$paramsPlaceholder': typeof ParamsParamsPlaceholderRoute
+ '/search/searchPlaceholder': typeof SearchSearchPlaceholderRoute
+}
+
+interface FileRoutesById {
+ '/': typeof IndexRoute
+ '/params': typeof ParamsRouteRouteWithChildren
+ '/search': typeof SearchRouteRouteWithChildren
+ '/absolute': typeof AbsoluteRoute
+ '/linkProps': typeof LinkPropsRoute
+ '/relative': typeof RelativeRoute
+ '/params/$paramsPlaceholder': typeof ParamsParamsPlaceholderRoute
+ '/search/searchPlaceholder': typeof SearchSearchPlaceholderRoute
+}
+
+interface FileRouteTypes {
+ fileRoutesByFullPath: FileRoutesByFullPath
+ fullPaths:
+ | '/'
+ | '/params'
+ | '/search'
+ | '/absolute'
+ | '/linkProps'
+ | '/relative'
+ | '/params/$paramsPlaceholder'
+ | '/search/searchPlaceholder'
+ fileRoutesByTo: FileRoutesByTo
+ to:
+ | '/'
+ | '/params'
+ | '/search'
+ | '/absolute'
+ | '/linkProps'
+ | '/relative'
+ | '/params/$paramsPlaceholder'
+ | '/search/searchPlaceholder'
+ id:
+ | '/'
+ | '/params'
+ | '/search'
+ | '/absolute'
+ | '/linkProps'
+ | '/relative'
+ | '/params/$paramsPlaceholder'
+ | '/search/searchPlaceholder'
+ fileRoutesById: FileRoutesById
+}
+
+interface RootRouteChildren {
+ IndexRoute: typeof IndexRoute
+ ParamsRouteRoute: typeof ParamsRouteRouteWithChildren
+ SearchRouteRoute: typeof SearchRouteRouteWithChildren
+ AbsoluteRoute: typeof AbsoluteRoute
+ LinkPropsRoute: typeof LinkPropsRoute
+ RelativeRoute: typeof RelativeRoute
+}
+
+const rootRouteChildren: RootRouteChildren = {
+ IndexRoute: IndexRoute,
+ ParamsRouteRoute: ParamsRouteRouteWithChildren,
+ SearchRouteRoute: SearchRouteRouteWithChildren,
+ AbsoluteRoute: AbsoluteRoute,
+ LinkPropsRoute: LinkPropsRoute,
+ RelativeRoute: RelativeRoute,
+}
+
+export const routeTree = rootRoute
+ ._addFileChildren(rootRouteChildren)
+ ._addFileTypes()
/* prettier-ignore-end */
diff --git a/packages/react-router/src/Matches.tsx b/packages/react-router/src/Matches.tsx
index fd58cab151..0b5f12ba36 100644
--- a/packages/react-router/src/Matches.tsx
+++ b/packages/react-router/src/Matches.tsx
@@ -169,31 +169,24 @@ export interface RouteMatch<
export type MakeRouteMatch<
TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
- TRouteId = ParseRoute['id'],
+ TRouteId = RouteIds,
TStrict extends boolean = true,
- TTypes extends AnyRoute['types'] = RouteById['types'],
- TFullPath = TTypes['fullPath'],
- TAllParams = TStrict extends false
+> = RouteMatch<
+ TRouteId,
+ RouteById['types']['fullPath'],
+ TStrict extends false
? AllParams
- : TTypes['allParams'],
- TFullSearchSchema = TStrict extends false
+ : RouteById['types']['allParams'],
+ TStrict extends false
? FullSearchSchema
- : TTypes['fullSearchSchema'],
- TLoaderData = TStrict extends false
+ : RouteById['types']['fullSearchSchema'],
+ TStrict extends false
? AllLoaderData
- : TTypes['loaderData'],
- TAllContext = TStrict extends false
+ : RouteById['types']['loaderData'],
+ TStrict extends false
? AllContext
- : TTypes['allContext'],
- TLoaderDeps = TTypes['loaderDeps'],
-> = RouteMatch<
- TRouteId,
- TFullPath,
- TAllParams,
- TFullSearchSchema,
- TLoaderData,
- TAllContext,
- TLoaderDeps
+ : RouteById['types']['allContext'],
+ RouteById['types']['loaderDeps']
>
export type AnyRouteMatch = RouteMatch
@@ -264,11 +257,11 @@ export interface MatchRouteOptions {
export type UseMatchRouteOptions<
TRouter extends AnyRouter = RegisteredRouter,
- TFrom extends RoutePaths = RoutePaths<
+ TFrom extends RoutePaths | string = RoutePaths<
TRouter['routeTree']
>,
TTo extends string = '',
- TMaskFrom extends RoutePaths = TFrom,
+ TMaskFrom extends RoutePaths | string = TFrom,
TMaskTo extends string = '',
TOptions extends ToOptions<
TRouter,
diff --git a/packages/react-router/src/RouterProvider.tsx b/packages/react-router/src/RouterProvider.tsx
index 6f17cbdac8..d9188a4559 100644
--- a/packages/react-router/src/RouterProvider.tsx
+++ b/packages/react-router/src/RouterProvider.tsx
@@ -30,8 +30,8 @@ export interface MatchLocation {
}
export type NavigateFn = <
- TTo extends string,
- TRouter extends AnyRouter = RegisteredRouter,
+ TRouter extends RegisteredRouter,
+ TTo extends string | undefined,
TFrom extends RoutePaths | string = string,
TMaskFrom extends RoutePaths | string = TFrom,
TMaskTo extends string = '',
@@ -42,8 +42,8 @@ export type NavigateFn = <
) => Promise
export type BuildLocationFn = <
- TTo extends string,
- TRouter extends AnyRouter = RegisteredRouter,
+ TRouter extends RegisteredRouter,
+ TTo extends string | undefined,
TFrom extends RoutePaths | string = string,
TMaskFrom extends RoutePaths | string = TFrom,
TMaskTo extends string = '',
diff --git a/packages/react-router/src/fileRoute.ts b/packages/react-router/src/fileRoute.ts
index 9f3a347d73..3cedea12c0 100644
--- a/packages/react-router/src/fileRoute.ts
+++ b/packages/react-router/src/fileRoute.ts
@@ -14,13 +14,14 @@ import type {
AnySearchValidator,
FileBaseRouteOptions,
ResolveParams,
+ RootRoute,
Route,
RouteConstraints,
RouteLoaderFn,
UpdatableRouteOptions,
} from './route'
import type { MakeRouteMatch } from './Matches'
-import type { RegisteredRouter } from './router'
+import type { AnyRouter, RegisteredRouter } from './router'
import type { RouteById, RouteIds } from './routeInfo'
export interface FileRoutesByPath {
@@ -29,6 +30,29 @@ export interface FileRoutesByPath {
// }
}
+export interface FileRouteTypes {
+ fileRoutesByFullPath: any
+ fullPaths: any
+ to: any
+ fileRoutesByTo: any
+ id: any
+ fileRoutesById: any
+}
+
+export type InferFileRouteTypes =
+ TRouteTree extends RootRoute<
+ any,
+ any,
+ any,
+ any,
+ any,
+ any,
+ any,
+ infer TFileRouteTypes extends FileRouteTypes
+ >
+ ? TFileRouteTypes
+ : never
+
export function createFileRoute<
TFilePath extends keyof FileRoutesByPath,
TParentRoute extends AnyRoute = FileRoutesByPath[TFilePath]['parentRoute'],
diff --git a/packages/react-router/src/index.tsx b/packages/react-router/src/index.tsx
index 59bbe43f38..913713db47 100644
--- a/packages/react-router/src/index.tsx
+++ b/packages/react-router/src/index.tsx
@@ -32,7 +32,11 @@ export {
createLazyRoute,
createLazyFileRoute,
} from './fileRoute'
-export type { FileRoutesByPath, LazyRouteOptions } from './fileRoute'
+export type {
+ FileRoutesByPath,
+ FileRouteTypes,
+ LazyRouteOptions,
+} from './fileRoute'
export * from './history'
@@ -88,6 +92,8 @@ export type {
MatchRouteOptions,
UseMatchRouteOptions,
MakeMatchRouteOptions,
+ MakeRouteMatch,
+ MakeRouteMatchUnion,
} from './Matches'
export { matchContext } from './matchContext'
@@ -230,6 +236,9 @@ export type {
RoutePaths,
FullSearchSchema,
AllParams,
+ AllLoaderData,
+ FullSearchSchemaInput,
+ AllContext,
} from './routeInfo'
export {
diff --git a/packages/react-router/src/link.tsx b/packages/react-router/src/link.tsx
index 9c1ac28141..2513d2b6d2 100644
--- a/packages/react-router/src/link.tsx
+++ b/packages/react-router/src/link.tsx
@@ -97,6 +97,8 @@ export type Last> = T extends [...infer _, infer L]
? L
: never
+export type AddTrailingSlash = T extends `${string}/` ? T : `${T & string}/`
+
export type RemoveTrailingSlashes = T extends `${infer R}/` ? R : T
export type RemoveLeadingSlashes = T extends `/${infer R}` ? R : T
@@ -116,15 +118,14 @@ export type SearchPaths<
TRouter extends AnyRouter,
TSearchPath extends string,
TPaths = ResolvePaths,
-> = TPaths extends `${RemoveTrailingSlashes}${infer TRest}`
- ? TRest
- : never
+ TPrefix extends string = `${RemoveTrailingSlashes}/`,
+> = TPaths extends `${TPrefix}${infer TRest}` ? TRest : never
export type SearchRelativePathAutoComplete<
TRouter extends AnyRouter,
TTo extends string,
TSearchPath extends string,
-> = `${TTo}${SearchPaths}`
+> = `${TTo}/${SearchPaths}`
export type RelativeToParentPathAutoComplete<
TRouter extends AnyRouter,
@@ -144,7 +145,9 @@ export type RelativeToCurrentPathAutoComplete<
TFrom extends string,
TTo extends string,
TResolvedPath extends string = ResolveRelativePath,
-> = SearchRelativePathAutoComplete
+> =
+ | SearchRelativePathAutoComplete
+ | CurrentPath>
export type AbsolutePathAutoComplete<
TRouter extends AnyRouter,
@@ -173,22 +176,28 @@ export type RelativeToPathAutoComplete<
TRouter extends AnyRouter,
TFrom extends string,
TTo extends string,
-> = TTo extends `..${string}`
- ? RelativeToParentPathAutoComplete>
- : TTo extends `.${string}`
- ? RelativeToCurrentPathAutoComplete<
+> = string extends TFrom
+ ? AbsolutePathAutoComplete
+ : TTo extends `..${string}`
+ ? RelativeToParentPathAutoComplete<
TRouter,
TFrom,
RemoveTrailingSlashes
>
- : AbsolutePathAutoComplete
+ : TTo extends `.${string}`
+ ? RelativeToCurrentPathAutoComplete<
+ TRouter,
+ TFrom,
+ RemoveTrailingSlashes
+ >
+ : AbsolutePathAutoComplete
export type NavigateOptions<
TRouter extends AnyRouter = RegisteredRouter,
- TFrom extends RoutePaths | string = string,
- TTo extends string = '',
- TMaskFrom extends RoutePaths | string = TFrom,
- TMaskTo extends string = '',
+ TFrom extends string = string,
+ TTo extends string | undefined = '.',
+ TMaskFrom extends string = TFrom,
+ TMaskTo extends string = '.',
> = ToOptions & NavigateOptionProps
export interface NavigateOptionProps {
@@ -204,15 +213,15 @@ export interface NavigateOptionProps {
export type ToOptions<
TRouter extends AnyRouter = RegisteredRouter,
- TFrom extends RoutePaths | string = string,
- TTo extends string = '',
- TMaskFrom extends RoutePaths | string = TFrom,
- TMaskTo extends string = '',
+ TFrom extends string = string,
+ TTo extends string | undefined = '.',
+ TMaskFrom extends string = TFrom,
+ TMaskTo extends string = '.',
> = ToSubOptions & MaskOptions
export interface MaskOptions<
in out TRouter extends AnyRouter,
- in out TMaskFrom extends RoutePaths | string,
+ in out TMaskFrom extends string,
in out TMaskTo extends string,
> {
_fromLocation?: ParsedLocation
@@ -221,16 +230,16 @@ export interface MaskOptions<
export type ToMaskOptions<
TRouteTree extends AnyRouter = RegisteredRouter,
- TMaskFrom extends RoutePaths | string = string,
- TMaskTo extends string = '',
+ TMaskFrom extends string = string,
+ TMaskTo extends string = '.',
> = ToSubOptions & {
unmaskOnReload?: boolean
}
export type ToSubOptions<
TRouter extends AnyRouter = RegisteredRouter,
- TFrom extends RoutePaths | string = string,
- TTo extends string = '',
+ TFrom extends string = string,
+ TTo extends string | undefined = '.',
> = ToSubOptionsProps &
SearchParamOptions &
PathParamOptions
@@ -238,7 +247,7 @@ export type ToSubOptions<
export interface ToSubOptionsProps<
in out TRouter extends AnyRouter = RegisteredRouter,
in out TFrom extends RoutePaths | string = string,
- in out TTo extends string = '',
+ in out TTo extends string | undefined = '.',
> {
to?: ToPathOption & {}
hash?: true | Updater
@@ -316,15 +325,17 @@ export type ResolveToParams<
TTo,
> =
ResolveRelativePath extends infer TPath
- ? string extends TPath
- ? ResolveAllToParams
- : TPath extends CatchAllPaths>
+ ? undefined extends TPath
+ ? never
+ : string extends TPath
? ResolveAllToParams
- : ResolveRoute<
- TRouter,
- TFrom,
- TTo
- >['types'][ResolveToParamType]
+ : TPath extends CatchAllPaths>
+ ? ResolveAllToParams
+ : ResolveRoute<
+ TRouter,
+ TFrom,
+ TTo
+ >['types'][ResolveToParamType]
: never
type ResolveRelativeToParams<
@@ -410,20 +421,12 @@ export type IsRequired<
>
: never
-export type SearchParamOptions<
- TRouter extends AnyRouter,
- TFrom,
- TTo extends string,
-> =
+export type SearchParamOptions =
IsRequired extends never
? MakeOptionalSearchParams
: MakeRequiredSearchParams
-export type PathParamOptions<
- TRouter extends AnyRouter,
- TFrom,
- TTo extends string,
-> =
+export type PathParamOptions =
IsRequired extends never
? MakeOptionalPathParams
: MakeRequiredPathParams
@@ -431,7 +434,7 @@ export type PathParamOptions<
export type ToPathOption<
TRouter extends AnyRouter = AnyRouter,
TFrom extends string = string,
- TTo extends string = string,
+ TTo extends string | undefined = string,
> =
| CheckPath
| RelativeToPathAutoComplete<
@@ -469,9 +472,9 @@ export interface ActiveOptions {
export type LinkOptions<
TRouter extends AnyRouter = RegisteredRouter,
TFrom extends string = string,
- TTo extends string = '',
+ TTo extends string | undefined = '.',
TMaskFrom extends string = TFrom,
- TMaskTo extends string = '',
+ TMaskTo extends string = '.',
> = NavigateOptions & LinkOptionsProps
export interface LinkOptionsProps {
@@ -519,29 +522,31 @@ export type ResolveRelativePath = string extends TFrom
? TTo
: string extends TTo
? TFrom
- : TFrom extends string
- ? TTo extends string
- ? TTo extends '.'
- ? TFrom
- : TTo extends `./`
- ? Join<[TFrom, '/']>
- : TTo extends `./${infer TRest}`
- ? ResolveRelativePath
- : TTo extends `/${infer TRest}`
- ? TTo
- : Split extends ['..', ...infer ToRest]
- ? Split extends [...infer FromRest, infer FromTail]
- ? ToRest extends ['/']
- ? Join<['/', ...FromRest, '/']>
- : ResolveRelativePath, Join>
- : never
- : Split extends ['.', ...infer ToRest]
- ? ToRest extends ['/']
- ? Join<[TFrom, '/']>
- : ResolveRelativePath>
- : CleanPath, ...Split]>>
+ : undefined extends TTo
+ ? TFrom
+ : TFrom extends string
+ ? TTo extends string
+ ? TTo extends '.'
+ ? TFrom
+ : TTo extends `./`
+ ? Join<[TFrom, '/']>
+ : TTo extends `./${infer TRest}`
+ ? ResolveRelativePath
+ : TTo extends `/${infer TRest}`
+ ? TTo
+ : Split extends ['..', ...infer ToRest]
+ ? Split extends [...infer FromRest, infer FromTail]
+ ? ToRest extends ['/']
+ ? Join<['/', ...FromRest, '/']>
+ : ResolveRelativePath, Join>
+ : never
+ : Split extends ['.', ...infer ToRest]
+ ? ToRest extends ['/']
+ ? Join<[TFrom, '/']>
+ : ResolveRelativePath>
+ : CleanPath, ...Split]>>
+ : never
: never
- : never
// type Test1 = ResolveRelativePath<'/', '/posts'>
// // ^?
@@ -844,18 +849,18 @@ export function useLinkProps<
export type UseLinkPropsOptions<
TRouter extends AnyRouter = RegisteredRouter,
TFrom extends RoutePaths | string = string,
- TTo extends string = '',
+ TTo extends string | undefined = '.',
TMaskFrom extends RoutePaths | string = TFrom,
- TMaskTo extends string = '',
+ TMaskTo extends string = '.',
> = ActiveLinkOptions &
React.AnchorHTMLAttributes
export type ActiveLinkOptions<
TRouter extends AnyRouter = RegisteredRouter,
TFrom extends string = string,
- TTo extends string = '',
+ TTo extends string | undefined = '.',
TMaskFrom extends string = TFrom,
- TMaskTo extends string = '',
+ TMaskTo extends string = '.',
> = LinkOptions & ActiveLinkOptionProps
type ActiveLinkAnchorProps = Omit<
@@ -881,9 +886,9 @@ export interface ActiveLinkOptionProps {
export type LinkProps<
TRouter extends AnyRouter = RegisteredRouter,
TFrom extends string = string,
- TTo extends string = '',
+ TTo extends string | undefined = '.',
TMaskFrom extends string = TFrom,
- TMaskTo extends string = '',
+ TMaskTo extends string = '.',
> = ActiveLinkOptions &
LinkPropsChildren
@@ -918,16 +923,16 @@ export type LinkComponentProps<
TComp,
TRouter extends AnyRouter = RegisteredRouter,
TFrom extends string = string,
- TTo extends string = '',
+ TTo extends string | undefined = '.',
TMaskFrom extends string = TFrom,
- TMaskTo extends string = '',
+ TMaskTo extends string = '.',
> = LinkComponentReactProps &
LinkProps
export type LinkComponent = <
TRouter extends RegisteredRouter = RegisteredRouter,
TFrom extends string = string,
- TTo extends string = '',
+ TTo extends string | undefined = undefined,
TMaskFrom extends string = TFrom,
TMaskTo extends string = '',
>(
diff --git a/packages/react-router/src/redirects.ts b/packages/react-router/src/redirects.ts
index 7c3188e714..b1a29a6893 100644
--- a/packages/react-router/src/redirects.ts
+++ b/packages/react-router/src/redirects.ts
@@ -7,10 +7,10 @@ export type AnyRedirect = Redirect
export type Redirect<
TRouter extends AnyRouter = RegisteredRouter,
- TFrom extends RoutePaths = '/',
- TTo extends string = '',
- TMaskFrom extends RoutePaths