diff --git a/.github/labeler.yml b/.github/labeler.yml index 16ac3b06ef..fe89bd8c8d 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -14,26 +14,12 @@ - 'packages/react-router-with-query/**/*' 'package: react-start': - 'packages/react-start/**/*' -'package: start-api-routes': - - 'packages/start-api-routes/**/*' 'package: react-start-client': - 'packages/react-start-client/**/*' -'package: react-start-config': - - 'packages/react-start-config/**/*' 'package: react-start-plugin': - 'packages/react-start-plugin/**/*' -'package: react-start-router-manifest': - - 'packages/react-start-router-manifest/**/*' 'package: react-start-server': - 'packages/react-start-server/**/*' -'package: start-server-functions-client': - - 'packages/start-server-functions-client/**/*' -'package: start-server-functions-fetcher': - - 'packages/start-server-functions-fetcher/**/*' -'package: start-server-functions-handler': - - 'packages/start-server-functions-handler/**/*' -'package: start-server-functions-ssr': - - 'packages/start-server-functions-ssr/**/*' 'package: router-cli': - 'packages/router-cli/**/*' 'package: router-core': @@ -60,18 +46,20 @@ - 'packages/solid-start/**/*' 'package: solid-start-client': - 'packages/solid-start-client/**/*' -'package: solid-start-config': - - 'packages/solid-start-config/**/*' 'package: solid-start-plugin': - 'packages/solid-start-plugin/**/*' -'package: solid-start-router-manifest': - - 'packages/solid-start-router-manifest/**/*' 'package: solid-start-server': - 'packages/solid-start-server/**/*' -'package: start': - - 'packages/start/**/*' -'package: start-config': - - 'packages/start-config/**/*' +'package: start-client-core': + - 'packages/start-client-core/**/*' +'package: start-plugin-core': + - 'packages/start-plugin-core/**/*' +'package: start-server-core': + - 'packages/start-server-core/**/*' +'package: start-server-functions-client': + - 'packages/start-server-functions-client/**/*' +'package: start-server-functions-fetcher': + - 'packages/start-server-functions-fetcher/**/*' 'package: start-server-functions-server': - 'packages/start-server-functions-server/**/*' 'package: valibot-adapter': diff --git a/.gitignore b/.gitignore index 5cc3e94113..1db161db9d 100644 --- a/.gitignore +++ b/.gitignore @@ -60,20 +60,18 @@ nx-cloud.env gpt/db.json -app.config.timestamp-* +vite.config.timestamp-* vite.config.js.timestamp-* vite.config.ts.timestamp-* -app.config.js.timestamp-* -app.config.ts.timestamp-* -app.config.timestamp_* +vite.config.timestamp_* vite.config.js.timestamp_* vite.config.ts.timestamp_* -app.config.js.timestamp_* -app.config.ts.timestamp_* + .idea *.vitest-temp.json # Handling VSCode settings /.vscode/ -!/examples/react/**/.vscode/settings.json \ No newline at end of file +!/examples/react/**/.vscode/settings.json +**/.tanstack-start/build \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index d285f8937d..25c93015ed 100644 --- a/.prettierignore +++ b/.prettierignore @@ -7,7 +7,6 @@ pnpm-lock.yaml **/snapshots **/.vercel -**/.vinxi **/.output **/node_modules node_modules diff --git a/README.md b/README.md index 4dc5f701b1..8bfc4db239 100644 --- a/README.md +++ b/README.md @@ -87,4 +87,4 @@ Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Quer To run example React projects with Tanstack Router, see [CONTRIBUTING.md](./CONTRIBUTING.md) - + diff --git a/docs/router/api/file-based-routing.md b/docs/router/api/file-based-routing.md index 0e165665c0..777d9f3116 100644 --- a/docs/router/api/file-based-routing.md +++ b/docs/router/api/file-based-routing.md @@ -132,19 +132,6 @@ By default, this value is set to `false`. > [!TIP] > You should ignore the path of your generated route tree file from your linter and formatter to avoid conflicts. -### `apiBase` - -As a framework, [TanStack Start](/start) supports the concept of API routes. This option configures the base path for API routes. - -By default, this value is set to `/api`. - -This means that all API routes will be prefixed with `/api`. - -This configuration value is only useful if you are using TanStack Start. - -> [!IMPORTANT] -> This default value may conflict with your own project's routing if you planned on having a normal route with the same base path. You can change this value to avoid conflicts. - ### `autoCodeSplitting` This feature is only available is you are using the TanStack Router Bundler Plugin. diff --git a/docs/router/eslint/create-route-property-order.md b/docs/router/eslint/create-route-property-order.md index 3ce5102013..c0fee218d2 100644 --- a/docs/router/eslint/create-route-property-order.md +++ b/docs/router/eslint/create-route-property-order.md @@ -29,7 +29,7 @@ Examples of **incorrect** code for this rule: /* eslint "@tanstack/router/create-route-property-order": "warn" */ import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/foo/bar/$id')({ +export const Route = createFileRoute({ loader: async ({context}) => { await context.queryClient.ensureQueryData(getQueryOptions(context.hello)), }, @@ -43,7 +43,7 @@ Examples of **correct** code for this rule: /* eslint "@tanstack/router/create-route-property-order": "warn" */ import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/foo/bar/$id')({ +export const Route = createFileRoute({ beforeLoad: () => ({hello: 'world'}), loader: async ({context}) => { await context.queryClient.ensureQueryData(getQueryOptions(context.hello)), diff --git a/docs/router/framework/react/api/router/createFileRouteFunction.md b/docs/router/framework/react/api/router/createFileRouteFunction.md index 945e713075..0986d6ccff 100644 --- a/docs/router/framework/react/api/router/createFileRouteFunction.md +++ b/docs/router/framework/react/api/router/createFileRouteFunction.md @@ -26,7 +26,7 @@ A new function that accepts a single argument of type [`RouteOptions`](./RouteOp ```tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ loader: () => { return 'Hello World' }, diff --git a/docs/router/framework/react/api/router/retainSearchParamsFunction.md b/docs/router/framework/react/api/router/retainSearchParamsFunction.md index 97e411b29c..d4bc185203 100644 --- a/docs/router/framework/react/api/router/retainSearchParamsFunction.md +++ b/docs/router/framework/react/api/router/retainSearchParamsFunction.md @@ -39,7 +39,7 @@ const searchSchema = z.object({ two: z.string().optional(), }) -export const Route = createFileRoute('/hello')({ +export const Route = createFileRoute({ validateSearch: zodValidator(searchSchema), search: { middlewares: [retainSearchParams(true)], diff --git a/docs/router/framework/react/api/router/stripSearchParamsFunction.md b/docs/router/framework/react/api/router/stripSearchParamsFunction.md index 05b9b02e7f..439a1796d2 100644 --- a/docs/router/framework/react/api/router/stripSearchParamsFunction.md +++ b/docs/router/framework/react/api/router/stripSearchParamsFunction.md @@ -30,7 +30,7 @@ const searchSchema = z.object({ two: z.string().default(defaultValues.two), }) -export const Route = createFileRoute('/hello')({ +export const Route = createFileRoute({ validateSearch: zodValidator(searchSchema), search: { // strip default values @@ -68,7 +68,7 @@ const searchSchema = z.object({ two: z.string().default('xyz'), }) -export const Route = createFileRoute('/hello')({ +export const Route = createFileRoute({ validateSearch: zodValidator(searchSchema), search: { // remove all search params diff --git a/docs/router/framework/react/comparison.md b/docs/router/framework/react/comparison.md index 4ef92b2667..62e10a054e 100644 --- a/docs/router/framework/react/comparison.md +++ b/docs/router/framework/react/comparison.md @@ -10,8 +10,8 @@ Before you commit to a new tool, it's always nice to know how it stacks up again Feature/Capability Key: - ✅ 1st-class, built-in, and ready to use with no added configuration or code -- 🔵 Supported via addon package - 🟡 Partial Support (on a scale of 5) +- 🟠 Supported via addon/community package - 🔶 Possible, but requires custom code/implementation/casting - 🛑 Not officially supported @@ -39,9 +39,9 @@ Feature/Capability Key: | Ranked Routes | ✅ | ✅ | ✅ | | Active Link Customization | ✅ | ✅ | ✅ | | Optimistic UI | ✅ | ✅ | 🔶 | -| Typesafe Absolute + Relative Navigation | ✅ | 🛑 | 🛑 | +| Typesafe Absolute + Relative Navigation | ✅ | 🟡 (1/5 via `buildHref` util) | 🟠 (IDE plugin) | | Route Mount/Transition/Unmount Events | ✅ | 🛑 | 🛑 | -| Devtools | ✅ | 🛑 | 🛑 | +| Devtools | ✅ | 🟠 | 🛑 | | Basic Search Params | ✅ | ✅ | ✅ | | Search Param Hooks | ✅ | ✅ | ✅ | | ``/`useNavigate` Search Param API | ✅ | 🟡 (search-string only via the `to`/`search` options) | 🟡 (search-string only via the `to`/`search` options) | @@ -54,7 +54,7 @@ Feature/Capability Key: | Suspense Route Elements | ✅ | ✅ | ✅ | | Route Error Elements | ✅ | ✅ | ✅ | | Route Pending Elements | ✅ | ✅ | ✅ | -| ``/`useBlocker` | ✅ | 🔶 | ❓ | +| ``/`useBlocker` | ✅ | 🔶 (no hard reloads or cross-origin navigation) | 🛑 | | Deferred Primitives | ✅ | ✅ | ✅ | | Navigation Scroll Restoration | ✅ | ✅ | ❓ | | ElementScroll Restoration | ✅ | 🛑 | 🛑 | @@ -72,7 +72,7 @@ Feature/Capability Key: | React Server Function Middleware | ✅ | 🛑 | 🛑 | | API Routes | ✅ | ✅ | ✅ | | API Middleware | ✅ | 🛑 | ✅ | -| React Server Components | 🛑 | 🛑 | ✅ | +| React Server Components | 🛑 | 🟡 (Experimental) | ✅ | | `
` API | 🛑 | ✅ | ✅ | [bp-tanstack-router]: https://badgen.net/bundlephobia/minzip/@tanstack/react-router diff --git a/docs/router/framework/react/decisions-on-dx.md b/docs/router/framework/react/decisions-on-dx.md index 405db4c6eb..a38716f624 100644 --- a/docs/router/framework/react/decisions-on-dx.md +++ b/docs/router/framework/react/decisions-on-dx.md @@ -225,7 +225,7 @@ Let's take a look at how the route configuration for the previous example would // src/routes/posts/index.ts import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: () => 'Posts index component goes here!!!', }) ``` diff --git a/docs/router/framework/react/guide/code-splitting.md b/docs/router/framework/react/guide/code-splitting.md index e2646e402c..e57c7d7fe0 100644 --- a/docs/router/framework/react/guide/code-splitting.md +++ b/docs/router/framework/react/guide/code-splitting.md @@ -81,11 +81,11 @@ To enable automatic code-splitting, you just need to add the following to the co // vite.config.ts import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ // ... autoCodeSplitting: true, }), diff --git a/docs/router/framework/react/guide/external-data-loading.md b/docs/router/framework/react/guide/external-data-loading.md index e2d0e1eb53..2b1ebf78f1 100644 --- a/docs/router/framework/react/guide/external-data-loading.md +++ b/docs/router/framework/react/guide/external-data-loading.md @@ -48,7 +48,7 @@ Here is a naive illustration (don't do this) of using a Route's `loader` option // src/routes/posts.tsx let postsCache = [] -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: async () => { postsCache = await fetchPosts() }, @@ -80,7 +80,7 @@ const postsQueryOptions = queryOptions({ queryFn: () => fetchPosts(), }) -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ // Use the `loader` option to ensure that the data is loaded loader: () => queryClient.ensureQueryData(postsQueryOptions), component: () => { @@ -105,7 +105,7 @@ export const Route = createFileRoute('/posts')({ When an error occurs while using `suspense` with `Tanstack Query`, you'll need to let queries know that you want to try again when re-rendering. This can be done by using the `reset` function provided by the `useQueryErrorResetBoundary` hook. We can invoke this function in an effect as soon as the error component mounts. This will make sure that the query is reset and will try to fetch data again when the route component is rendered again. This will also cover cases where users navigate away from our route instead of clicking the `retry` button. ```tsx -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: () => queryClient.ensureQueryData(postsQueryOptions), errorComponent: ({ error, reset }) => { const router = useRouter() diff --git a/docs/router/framework/react/guide/not-found-errors.md b/docs/router/framework/react/guide/not-found-errors.md index 08dec747b0..739e2b20cb 100644 --- a/docs/router/framework/react/guide/not-found-errors.md +++ b/docs/router/framework/react/guide/not-found-errors.md @@ -16,7 +16,7 @@ There are 2 uses for not-found errors in TanStack Router: - Attempting to access `/posts/1/edit` when the route tree only handles `/posts/$postId` - **Missing resources**: When a resource cannot be found, such as a post with a given ID or any asynchronous data that is not available or does not exist - **You, the developer** must throw a not-found error when a resource cannot be found. This can be done in the `beforeLoad` or `loader` functions using the `notFound` utility. - - Will be handled by the nearest parent route with a `notFoundComponent` or the root route + - Will be handled by the nearest parent route with a `notFoundComponent` (when `notFound` is called within `loader`) or the root route. - Examples: - Attempting to access `/posts/1` when the post with ID 1 does not exist - Attempting to access `/docs/path/to/document` when the document does not exist diff --git a/docs/router/framework/react/guide/router-context.md b/docs/router/framework/react/guide/router-context.md index 561b1e2f00..f54e7a7b23 100644 --- a/docs/router/framework/react/guide/router-context.md +++ b/docs/router/framework/react/guide/router-context.md @@ -92,7 +92,7 @@ Once you have defined the router context type, you can use it in your route defi ```tsx // src/routes/todos.tsx -export const Route = createFileRoute('/todos')({ +export const Route = createFileRoute({ component: Todos, loader: ({ context }) => fetchTodosByUserId(context.user.id), }) @@ -122,7 +122,7 @@ Then, in your route: ```tsx // src/routes/todos.tsx -export const Route = createFileRoute('/todos')({ +export const Route = createFileRoute({ component: Todos, loader: ({ context }) => context.fetchTodosByUserId(context.userId), }) @@ -158,7 +158,7 @@ Then, in your route: ```tsx // src/routes/todos.tsx -export const Route = createFileRoute('/todos')({ +export const Route = createFileRoute({ component: Todos, loader: async ({ context }) => { await context.queryClient.ensureQueryData({ @@ -234,7 +234,7 @@ So, now in our route's `loader` function, we can access the `networkStrength` ho ```tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ component: Posts, loader: ({ context }) => { if (context.networkStrength === 'STRONG') { @@ -282,7 +282,7 @@ const router = createRouter({ ```tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/todos')({ +export const Route = createFileRoute({ component: Todos, beforeLoad: () => { return { diff --git a/docs/router/framework/react/guide/scroll-restoration.md b/docs/router/framework/react/guide/scroll-restoration.md index 77634d03e9..034b9465a7 100644 --- a/docs/router/framework/react/guide/scroll-restoration.md +++ b/docs/router/framework/react/guide/scroll-restoration.md @@ -177,12 +177,12 @@ function Component() { ## Scroll Behavior -To control the scroll behavior when navigating between pages, you can use the `scrollBehavior` option. This allows you to make the transition between pages instant instead of a smooth scroll. The global configuration of scroll restoration behavior has the same options as those supported by the browser, which are `smooth`, `instant`, and `auto` (see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#behavior) for more information). +To control the scroll behavior when navigating between pages, you can use the `scrollRestorationBehavior` option. This allows you to make the transition between pages instant instead of a smooth scroll. The global configuration of scroll restoration behavior has the same options as those supported by the browser, which are `smooth`, `instant`, and `auto` (see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#behavior) for more information). ```tsx import { createRouter } from '@tanstack/react-router' const router = createRouter({ - scrollBehavior: 'instant', + scrollRestorationBehavior: 'instant', }) ``` diff --git a/docs/router/framework/react/guide/tanstack-start.md b/docs/router/framework/react/guide/tanstack-start.md index 9704d721c4..a56a204e28 100644 --- a/docs/router/framework/react/guide/tanstack-start.md +++ b/docs/router/framework/react/guide/tanstack-start.md @@ -47,15 +47,12 @@ TanStack Start is powered by the following packages and need to be installed as - [@tanstack/start](https://github.com/tanstack/start) - [@tanstack/react-router](https://tanstack.com/router) -- [Vinxi](https://vinxi.vercel.app/) - -> [!NOTE] -> Vinxi is a temporary dependency that will be replaced by a simple vite plugin or a dedicated Start CLI. +- [Vite](https://vite.dev/) To install them, run: ```shell -npm i @tanstack/react-start @tanstack/react-router vinxi +npm i @tanstack/react-start @tanstack/react-router vite ``` You'll also need React and the Vite React plugin, so install their dependencies as well: @@ -72,16 +69,16 @@ npm i -D typescript @types/react @types/react-dom # Update Configuration Files -We'll then update our `package.json` to use Vinxi's CLI and set `"type": "module"`: +We'll then update our `package.json` to use Vite's CLI and set `"type": "module"`: ```jsonc { // ... "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start", + "dev": "vite dev", + "build": "vite build", + "start": "vite start", }, } ``` @@ -97,12 +94,10 @@ export default defineConfig({}) # Add the Basic Templating -There are four required files for TanStack Start usage: +There are 2 required files for TanStack Start usage: 1. The router configuration -2. The server entry point -3. The client entry point -4. The root of your application +2. The root of your application Once configuration is done, we'll have a file tree that looks like the following: @@ -111,10 +106,8 @@ Once configuration is done, we'll have a file tree that looks like the following ├── app/ │ ├── routes/ │ │ └── `__root.tsx` -│ ├── `client.tsx` │ ├── `router.tsx` │ ├── `routeTree.gen.ts` -│ └── `ssr.tsx` ├── `.gitignore` ├── `app.config.ts` ├── `package.json` @@ -123,7 +116,7 @@ Once configuration is done, we'll have a file tree that looks like the following ## The Router Configuration -This is the file that will dictate the behavior of TanStack Router used within Start. Here, you can configure everything +This is the file that will dictate the behavior of TanStack Router used within Start for both the server and the client. Here, you can configure everything from the default [preloading functionality](./preloading.md) to [caching staleness](./data-loading.md). ```tsx @@ -149,52 +142,9 @@ declare module '@tanstack/react-router' { > `routeTree.gen.ts` is not a file you're expected to have at this point. > It will be generated when you run TanStack Start (via `npm run dev` or `npm run start`) for the first time. -## The Server Entry Point - -As TanStack Start is an [SSR](https://unicorn-utterances.com/posts/what-is-ssr-and-ssg) framework, we need to pipe this router -information to our server entry point: - -```tsx -// app/ssr.tsx -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) -``` - -This allows us to know what routes and loaders we need to execute when the user hits a given route. - -## The Client Entry Point - -Now we need a way to hydrate our client-side JavaScript once the route resolves to the client. We do this by piping the same -router information to our client entry point: - -```tsx -// app/client.tsx -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter({ - scrollRestoration: true, -}) - -hydrateRoot(document!, ) -``` - -This enables us to kick off client-side routing once the user's initial server request has fulfilled. - ## The Root of Your Application -Finally, we need to create the root of our application. This is the entry point for all other routes. The code in this file will wrap all other routes in the application. +Finally, we need to create the root of our application. This is the entry point for all application routes. The code in this file will wrap all other routes in the application. ```tsx // app/routes/__root.tsx diff --git a/docs/router/framework/react/migrate-from-react-location.md b/docs/router/framework/react/migrate-from-react-location.md index 100d614cae..ed5914b41f 100644 --- a/docs/router/framework/react/migrate-from-react-location.md +++ b/docs/router/framework/react/migrate-from-react-location.md @@ -49,11 +49,11 @@ And add it to your `vite.config.js`: ```js import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' export default defineConfig({ // ... - plugins: [TanStackRouterVite(), react()], + plugins: [tanstackRouter(), react()], }) ``` @@ -112,7 +112,7 @@ export const Route = createRootRoute({ // src/routes/index.tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Index, }) ``` @@ -125,7 +125,7 @@ export const Route = createFileRoute('/')({ // src/routes/posts.tsx import { createFileRoute, Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ component: Posts, loader: async () => { const posts = await fetchPosts() @@ -164,7 +164,7 @@ function Posts() { // src/routes/posts.index.tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndex, }) ``` @@ -177,7 +177,7 @@ export const Route = createFileRoute('/posts/')({ // src/routes/posts.$postId.tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ component: PostsId, loader: async ({ params: { postId } }) => { const post = await fetchPost(postId) diff --git a/docs/router/framework/react/overview.md b/docs/router/framework/react/overview.md index be83513a79..9e064cf0a1 100644 --- a/docs/router/framework/react/overview.md +++ b/docs/router/framework/react/overview.md @@ -42,7 +42,7 @@ It's probably no surprise at this point that picking a router is so important th **Does this mean that TanStack Router is a framework?** -TanStack Router itself is not a "framework" in the traditional sense, since it doesn't address a few other common full-stack concerns. However TanStack Router has been designed to be upgradable to a full-stack framework when used in conjunction with other tools that address bundling, deployments, and server-side-specific functionality. This is why we are currently developing [TanStack Start](https://tanstack.com/start), a full-stack framework that is built on top of TanStack Router and tools like Nitro, and Vite. +TanStack Router itself is not a "framework" in the traditional sense, since it doesn't address a few other common full-stack concerns. However TanStack Router has been designed to be upgradable to a full-stack framework when used in conjunction with other tools that address bundling, deployments, and server-side-specific functionality. This is why we are currently developing [TanStack Start](https://tanstack.com/start), a full-stack framework that is built on top of TanStack Router and Vite. For a deeper dive on the history of TanStack Router, feel free to read [TanStack Router's History](./decisions-on-dx.md#tanstack-routers-origin-story). diff --git a/docs/router/framework/react/quick-start.md b/docs/router/framework/react/quick-start.md index b9264f8742..83a36555e2 100644 --- a/docs/router/framework/react/quick-start.md +++ b/docs/router/framework/react/quick-start.md @@ -44,13 +44,17 @@ deno add npm:@tanstack/react-router npm:@tanstack/router-plugin npm:@tanstack/re // vite.config.ts import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ // Please make sure that '@tanstack/router-plugin' is passed before '@vitejs/plugin-react' - TanStackRouterVite({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ + target: 'react', + autoCodeSplitting: true, + verboseFileRoutes: false, + }), react(), // ..., ], diff --git a/docs/router/framework/react/routing/installation-with-esbuild.md b/docs/router/framework/react/routing/installation-with-esbuild.md index 262213f386..da3cd9f857 100644 --- a/docs/router/framework/react/routing/installation-with-esbuild.md +++ b/docs/router/framework/react/routing/installation-with-esbuild.md @@ -14,12 +14,16 @@ Once installed, you'll need to add the plugin to your configuration. ```tsx // esbuild.config.js -import { TanStackRouterEsbuild } from '@tanstack/router-plugin/esbuild' +import { tanstackRouter } from '@tanstack/router-plugin/esbuild' export default { // ... plugins: [ - TanStackRouterEsbuild({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ + target: 'react', + autoCodeSplitting: true, + verboseFileRoutes: false, + }), ], } ``` @@ -74,6 +78,6 @@ When using the TanStack Router Plugin with Esbuild for File-based routing, it co } ``` -If these defaults work for your project, you don't need to configure anything at all! However, if you need to customize the configuration, you can do so by editing the configuration object passed into the `TanStackRouterEsbuild` function. +If these defaults work for your project, you don't need to configure anything at all! However, if you need to customize the configuration, you can do so by editing the configuration object passed into the `tanstackRouter` function. You can find all the available configuration options in the [File-based Routing API Reference](../../../api/file-based-routing.md). diff --git a/docs/router/framework/react/routing/installation-with-rspack.md b/docs/router/framework/react/routing/installation-with-rspack.md index b118773f86..741978192e 100644 --- a/docs/router/framework/react/routing/installation-with-rspack.md +++ b/docs/router/framework/react/routing/installation-with-rspack.md @@ -16,14 +16,18 @@ Once installed, you'll need to add the plugin to your configuration. // rsbuild.config.ts import { defineConfig } from '@rsbuild/core' import { pluginReact } from '@rsbuild/plugin-react' -import { TanStackRouterRspack } from '@tanstack/router-plugin/rspack' +import { tanstackRouter } from '@tanstack/router-plugin/rspack' export default defineConfig({ plugins: [pluginReact()], tools: { rspack: { plugins: [ - TanStackRouterRspack({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ + target: 'react', + autoCodeSplitting: true, + verboseFileRoutes: false, + }), ], }, }, @@ -80,6 +84,6 @@ When using the TanStack Router Plugin with Rspack (or Rsbuild) for File-based ro } ``` -If these defaults work for your project, you don't need to configure anything at all! However, if you need to customize the configuration, you can do so by editing the configuration object passed into the `TanStackRouterVite` function. +If these defaults work for your project, you don't need to configure anything at all! However, if you need to customize the configuration, you can do so by editing the configuration object passed into the `tanstackRouter` function. You can find all the available configuration options in the [File-based Routing API Reference](../../../api/file-based-routing.md). diff --git a/docs/router/framework/react/routing/installation-with-vite.md b/docs/router/framework/react/routing/installation-with-vite.md index 00dc2e37d8..a860279372 100644 --- a/docs/router/framework/react/routing/installation-with-vite.md +++ b/docs/router/framework/react/routing/installation-with-vite.md @@ -16,13 +16,17 @@ Once installed, you'll need to add the plugin to your Vite configuration. // vite.config.ts import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ // Please make sure that '@tanstack/router-plugin' is passed before '@vitejs/plugin-react' - TanStackRouterVite({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ + target: 'react', + autoCodeSplitting: true, + verboseFileRoutes: false, + }), react(), // ... ], @@ -82,6 +86,6 @@ When using the TanStack Router Plugin with Vite for File-based routing, it comes } ``` -If these defaults work for your project, you don't need to configure anything at all! However, if you need to customize the configuration, you can do so by editing the configuration object passed into the `TanStackRouterVite` function. +If these defaults work for your project, you don't need to configure anything at all! However, if you need to customize the configuration, you can do so by editing the configuration object passed into the `tanstackRouter` function. You can find all the available configuration options in the [File-based Routing API Reference](../../../api/file-based-routing.md). diff --git a/docs/router/framework/react/routing/installation-with-webpack.md b/docs/router/framework/react/routing/installation-with-webpack.md index f98a9a1cd2..e89288e2e0 100644 --- a/docs/router/framework/react/routing/installation-with-webpack.md +++ b/docs/router/framework/react/routing/installation-with-webpack.md @@ -14,11 +14,15 @@ Once installed, you'll need to add the plugin to your configuration. ```tsx // webpack.config.ts -import { TanStackRouterWebpack } from '@tanstack/router-plugin/webpack' +import { tanstackRouter } from '@tanstack/router-plugin/webpack' export default { plugins: [ - TanStackRouterWebpack({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ + target: 'react', + autoCodeSplitting: true, + verboseFileRoutes: false, + }), ], } ``` @@ -73,6 +77,6 @@ When using the TanStack Router Plugin with Webpack for File-based routing, it co } ``` -If these defaults work for your project, you don't need to configure anything at all! However, if you need to customize the configuration, you can do so by editing the configuration object passed into the `TanStackRouterWebpack` function. +If these defaults work for your project, you don't need to configure anything at all! However, if you need to customize the configuration, you can do so by editing the configuration object passed into the `tanstackRouter` function. You can find all the available configuration options in the [File-based Routing API Reference](../../../api/file-based-routing.md). diff --git a/docs/router/framework/react/routing/routing-concepts.md b/docs/router/framework/react/routing/routing-concepts.md index 38d9ae5cd9..8ba6969379 100644 --- a/docs/router/framework/react/routing/routing-concepts.md +++ b/docs/router/framework/react/routing/routing-concepts.md @@ -13,7 +13,7 @@ All other routes, other than the [Root Route](#the-root-route), are configured u ```tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ component: PostsComponent, }) ``` @@ -71,7 +71,7 @@ Let's take a look at an `/about` route: // about.tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/about')({ +export const Route = createFileRoute({ component: AboutComponent, }) @@ -93,7 +93,7 @@ Let's take a look at an index route for a `/posts` URL: import { createFileRoute } from '@tanstack/react-router' // Note the trailing slash, which is used to target index routes -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) @@ -113,7 +113,7 @@ These params are then usable in your route's configuration and components! Let's ```tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ // In a loader loader: ({ params }) => fetchPost(params.postId), // Or in a component @@ -172,7 +172,7 @@ This tree structure is used to wrap the child routes with a layout component: ```tsx import { Outlet, createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/app')({ +export const Route = createFileRoute({ component: AppLayoutComponent, }) @@ -243,7 +243,7 @@ The `_pathlessLayout.tsx` route is used to wrap the child routes with a Pathless ```tsx import { Outlet, createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout')({ +export const Route = createFileRoute({ component: PathlessLayoutComponent, }) diff --git a/docs/router/framework/react/routing/virtual-file-routes.md b/docs/router/framework/react/routing/virtual-file-routes.md index d7721989d8..f56fb87891 100644 --- a/docs/router/framework/react/routing/virtual-file-routes.md +++ b/docs/router/framework/react/routing/virtual-file-routes.md @@ -53,12 +53,13 @@ If you're using the `TanStackRouter` plugin for Vite/Rspack/Webpack, you can con // vite.config.ts import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'react', + verboseFileRoutes: false, virtualRouteConfig: './routes.ts', }), react(), @@ -72,7 +73,7 @@ Or, you choose to define the virtual routes directly in the configuration: // vite.config.ts import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' import { rootRoute } from '@tanstack/virtual-file-routes' const routes = rootRoute('root.tsx', [ @@ -80,7 +81,7 @@ const routes = rootRoute('root.tsx', [ ]) export default defineConfig({ - plugins: [TanStackRouterVite({ virtualRouteConfig: routes }), react()], + plugins: [tanstackRouter({ virtualRouteConfig: routes }), react()], }) ``` diff --git a/docs/router/framework/solid/quick-start.md b/docs/router/framework/solid/quick-start.md index a831b6de1d..4dd822540d 100644 --- a/docs/router/framework/solid/quick-start.md +++ b/docs/router/framework/solid/quick-start.md @@ -44,12 +44,16 @@ deno add npm:@tanstack/solid-router npm:@tanstack/router-plugin npm:@tanstack/so // vite.config.ts import { defineConfig } from 'vite' import solid from 'vite-plugin-solid' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'solid', autoCodeSplitting: true }), + tanstackRouter({ + target: 'solid', + autoCodeSplitting: true, + verboseFileRoutes: false, + }), solid(), // ..., ], diff --git a/docs/router/framework/solid/routing/file-based-routing.md b/docs/router/framework/solid/routing/file-based-routing.md index ffdebc1893..6c15db448e 100644 --- a/docs/router/framework/solid/routing/file-based-routing.md +++ b/docs/router/framework/solid/routing/file-based-routing.md @@ -24,12 +24,16 @@ Once installed, you'll need to add the plugin to your Vite configuration. // vite.config.ts import { defineConfig } from 'vite' import solid from 'vite-plugin-solid' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'solid', autoCodeSplitting: true }), + tanstackRouter({ + target: 'solid', + autoCodeSplitting: true, + verboseFileRoutes: false, + }), solid(), // ... ], diff --git a/docs/router/framework/solid/routing/installation-with-vite.md b/docs/router/framework/solid/routing/installation-with-vite.md index 7c05aaf581..7da230cf16 100644 --- a/docs/router/framework/solid/routing/installation-with-vite.md +++ b/docs/router/framework/solid/routing/installation-with-vite.md @@ -16,12 +16,16 @@ Once installed, you'll need to add the plugin to your Vite configuration. // vite.config.ts import { defineConfig } from 'vite' import solid from 'vite-plugin-solid' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'solid', autoCodeSplitting: true }), + tanstackRouter({ + target: 'solid', + autoCodeSplitting: true, + verboseFileRoutes: false, + }), solid(), // ... ], diff --git a/docs/start/config.json b/docs/start/config.json index 76cae14ab8..6967df720e 100644 --- a/docs/start/config.json +++ b/docs/start/config.json @@ -46,13 +46,17 @@ "to": "framework/react/middleware" }, { - "label": "API Routes", - "to": "framework/react/api-routes" + "label": "Server Routes", + "to": "framework/react/server-routes" }, { "label": "SSR", "to": "framework/react/ssr" }, + { + "label": "SPA Mode", + "to": "framework/react/spa-mode" + }, { "label": "Hosting", "to": "framework/react/hosting" @@ -115,13 +119,17 @@ "to": "framework/solid/middleware" }, { - "label": "API Routes", - "to": "framework/solid/api-routes" + "label": "Server Routes", + "to": "framework/solid/server-routes" }, { "label": "SSR", "to": "framework/solid/ssr" }, + { + "label": "SPA Mode", + "to": "framework/solid/spa-mode" + }, { "label": "Hosting", "to": "framework/solid/hosting" diff --git a/docs/start/framework/react/api-routes.md b/docs/start/framework/react/api-routes.md deleted file mode 100644 index 87032c5bcd..0000000000 --- a/docs/start/framework/react/api-routes.md +++ /dev/null @@ -1,292 +0,0 @@ ---- -id: api-routes -title: API Routes ---- - -API Routes are a powerful feature of TanStack Start that allow you to create server-side endpoints in your application without the need for a separate server. API Routes are useful for handling form submissions, user authentication, and more. - -By default, API Routes are defined in your `./app/routes/api` directory of your project and are automatically handled by the TanStack Start server. - -> 🧠 This means that by default, your API Routes will be prefixed with `/api` and will be served from the same server as your application. You can customize this base path by changing the `tsr.apiBase` in your TanStack Start config. - -## File Route Conventions - -API Routes in TanStack Start, follow the same file-based routing conventions as TanStack Router. This means that each file in your `routes` directory that is prefixed with `api` (which can be configured) will be treated as an API route. Here are a few examples: - -- `routes/api.users.ts` will create an API route at `/api/users` -- `routes/api/users.ts` will **also** create an API route at `/api/users` -- `routes/api/users.index.ts` will **also** create an API route at `/api/users` -- `routes/api/users/$id.ts` will create an API route at `/api/users/$id` -- `routes/api/users/$id/posts.ts` will create an API route at `/api/users/$id/posts` -- `routes/api.users.$id.posts.ts` will **also** create an API route at `/api/users/$id/posts` -- `routes/api/file/$.ts` will create an API route at `/api/file/$` - -Your route files that are prefixed with `api`, can be thought of as the handlers for the given API route path. - -It's important to remember that each route can only have a single handler file associated with it. So, if you have a file named `routes/api/users.ts` which'd equal the request path of `/api/users`, you cannot have other files that'd also resolve to the same route, like: - -- `routes/api/users.index.ts` -- `routes/api.users.ts`. -- `routes/api.users.index.ts`. - -❗ One more thing, API Routes do not have the concept of pathless layout routes or parallel routes. So, a file named: - -- `routes/api/_pathlessLayout/users.ts` would resolve to `/api/_pathlessLayout/users` and **NOT** `/api/users`. - -## Nested Directories vs File-names - -In the examples above, you may have noticed that the file naming conventions are flexible and allow you to mix and match directories and file names. This is intentional and allows you to organize your API Routes in a way that makes sense for your application. You can read more about this in the [TanStack Router File-based Routing Guide](/router/latest/docs/framework/react/routing/file-based-routing#s-or-s). - -## Setting up the entry handler - -Before you can create your API routes, you need to set up the entry handler for your TanStack Start project. This entry handler, similar to `client` and `ssr`, handles the API incoming requests and routes them to the appropriate API route handler. The API entry handler is defined in the `app/api.ts` file in your project. - -Here's an example implementation: - -```ts -// app/api.ts -import { - createStartAPIHandler, - defaultAPIFileRouteHandler, -} from '@tanstack/react-start/api' - -export default createStartAPIHandler(defaultAPIFileRouteHandler) -``` - -This file is responsible for creating the API handler that will be used to route incoming requests to the appropriate API route handler. The `defaultAPIFileRouteHandler` is a helper function that will automatically load and execute the appropriate API route handler based on the incoming request. - -## Defining an API Route - -API Routes export an APIRoute instance by calling the `createAPIFileRoute` function. Similar to other file-based routes in TanStack Router, the first argument to this function is the path of the route. The function returned is called again with an object that defines the route handlers for each HTTP method. - -> [!TIP] -> If you've already got the dev server running, when you create a new API route, it'll automatically have the initial handler set up for you. From there on, you can customize the handler as needed. - -> [!NOTE] -> The export variable must be named `APIRoute` or the resulting response will be a `404 not found`. - -```ts -// routes/api/hello.ts -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/api/hello')({ - GET: async ({ request }) => { - return new Response('Hello, World! from ' + request.url) - }, -}) -``` - -Each HTTP method handler receives an object with the following properties: - -- `request`: The incoming request object. You can read more about the `Request` object in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Request). -- `params`: An object containing the dynamic path parameters of the route. For example, if the route path is `/users/$id`, and the request is made to `/users/123`, then `params` will be `{ id: '123' }`. We'll cover dynamic path parameters and wildcard parameters later in this guide. - -Once you've processed the request, you need to return a `Response` object or `Promise`. This can be done by creating a new `Response` object and returning it from the handler. You can read more about the `Response` object in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Response). - -## Dynamic Path Params - -API Routes support dynamic path parameters, which are denoted by a `$` followed by the parameter name. For example, a file named `routes/api/users/$id.ts` will create an API route at `/api/users/$id` that accepts a dynamic `id` parameter. - -```ts -// routes/api/users/$id.ts -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/users/$id')({ - GET: async ({ params }) => { - const { id } = params - return new Response(`User ID: ${id}`) - }, -}) - -// Visit /api/users/123 to see the response -// User ID: 123 -``` - -You can also have multiple dynamic path parameters in a single route. For example, a file named `routes/api/users/$id/posts/$postId.ts` will create an API route at `/api/users/$id/posts/$postId` that accepts two dynamic parameters. - -```ts -// routes/api/users/$id/posts/$postId.ts -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/users/$id/posts/$postId')({ - GET: async ({ params }) => { - const { id, postId } = params - return new Response(`User ID: ${id}, Post ID: ${postId}`) - }, -}) - -// Visit /api/users/123/posts/456 to see the response -// User ID: 123, Post ID: 456 -``` - -## Wildcard/Splat Param - -API Routes also support wildcard parameters at the end of the path, which are denoted by a `$` followed by nothing. For example, a file named `routes/api/file/$.ts` will create an API route at `/api/file/$` that accepts a wildcard parameter. - -```ts -// routes/api/file/$.ts -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/file/$')({ - GET: async ({ params }) => { - const { _splat } = params - return new Response(`File: ${_splat}`) - }, -}) - -// Visit /api/file/hello.txt to see the response -// File: hello.txt -``` - -## Handling requests with a body - -To handle POST requests,you can add a `POST` handler to the route object. The handler will receive the request object as the first argument, and you can access the request body using the `request.json()` method. - -```ts -// routes/api/hello.ts -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/api/hello')({ - POST: async ({ request }) => { - const body = await request.json() - return new Response(`Hello, ${body.name}!`) - }, -}) - -// Send a POST request to /api/hello with a JSON body like { "name": "Tanner" } -// Hello, Tanner! -``` - -This also applies to other HTTP methods like `PUT`, `PATCH`, and `DELETE`. You can add handlers for these methods in the route object and access the request body using the appropriate method. - -It's important to remember that the `request.json()` method returns a `Promise` that resolves to the parsed JSON body of the request. You need to `await` the result to access the body. - -This is a common pattern for handling POST requests in API Routes. You can also use other methods like `request.text()` or `request.formData()` to access the body of the request. - -## Responding with JSON - -When returning JSON using a Response object, this is a common pattern: - -```ts -// routes/api/hello.ts -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/api/hello')({ - GET: async ({ request }) => { - return new Response(JSON.stringify({ message: 'Hello, World!' }), { - headers: { - 'Content-Type': 'application/json', - }, - }) - }, -}) - -// Visit /api/hello to see the response -// {"message":"Hello, World!"} -``` - -## Using the `json` helper function - -Or you can use the `json` helper function to automatically set the `Content-Type` header to `application/json` and serialize the JSON object for you. - -```ts -// routes/api/hello.ts -import { json } from '@tanstack/react-start' -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/api/hello')({ - GET: async ({ request }) => { - return json({ message: 'Hello, World!' }) - }, -}) - -// Visit /api/hello to see the response -// {"message":"Hello, World!"} -``` - -## Responding with a status code - -You can set the status code of the response by either: - -- Passing it as a property of the second argument to the `Response` constructor - - ```ts - // routes/api/hello.ts - import { json } from '@tanstack/react-start' - import { createAPIFileRoute } from '@tanstack/react-start/api' - - export const APIRoute = createAPIFileRoute('/users/$id')({ - GET: async ({ request, params }) => { - const user = await findUser(params.id) - if (!user) { - return new Response('User not found', { - status: 404, - }) - } - return json(user) - }, - }) - ``` - -- Using the `setResponseStatus` helper function from `@tanstack/react-start/server` - - ```ts - // routes/api/hello.ts - import { json } from '@tanstack/react-start' - import { createAPIFileRoute } from '@tanstack/react-start/api' - import { setResponseStatus } from '@tanstack/react-start/server' - - export const APIRoute = createAPIFileRoute('/users/$id')({ - GET: async ({ request, params }) => { - const user = await findUser(params.id) - if (!user) { - setResponseStatus(404) - return new Response('User not found') - } - return json(user) - }, - }) - ``` - -In this example, we're returning a `404` status code if the user is not found. You can set any valid HTTP status code using this method. - -## Setting headers in the response - -Sometimes you may need to set headers in the response. You can do this by either: - -- Passing an object as the second argument to the `Response` constructor. - - ```ts - // routes/api/hello.ts - import { createAPIFileRoute } from '@tanstack/react-start/api' - - export const APIRoute = createAPIFileRoute('/api/hello')({ - GET: async ({ request }) => { - return new Response('Hello, World!', { - headers: { - 'Content-Type': 'text/plain', - }, - }) - }, - }) - - // Visit /api/hello to see the response - // Hello, World! - ``` - -- Or using the `setHeaders` helper function from `@tanstack/react-start/server`. - - ```ts - // routes/api/hello.ts - import { createAPIFileRoute } from '@tanstack/react-start/api' - import { setHeaders } from '@tanstack/react-start/server' - - export const APIRoute = createAPIFileRoute('/api/hello')({ - GET: async ({ request }) => { - setHeaders({ - 'Content-Type': 'text/plain', - }) - return new Response('Hello, World!') - }, - }) - ``` diff --git a/docs/start/framework/react/authentication.md b/docs/start/framework/react/authentication.md index fe90ebbcff..8d4ed86236 100644 --- a/docs/start/framework/react/authentication.md +++ b/docs/start/framework/react/authentication.md @@ -17,9 +17,9 @@ That said, authentication is not something to be taken lightly. After much vetti - - - Clerk logo + + + Clerk logo diff --git a/docs/start/framework/react/build-from-scratch.md b/docs/start/framework/react/build-from-scratch.md index 055526d7f8..6143199b6c 100644 --- a/docs/start/framework/react/build-from-scratch.md +++ b/docs/start/framework/react/build-from-scratch.md @@ -4,7 +4,7 @@ title: Build a Project from Scratch --- > [!NOTE] -> If you chose to quick start with an example or cloned project, you can skip this guide and move on to the [Learn the Basics](../learn-the-basics) guide. +> If you chose to quick start with an example or cloned project, you can skip this guide and move on to the [Learn the Basics](./learn-the-basics.md) guide. _So you want to build a TanStack Start project from scratch?_ @@ -47,85 +47,75 @@ We highly recommend using TypeScript with TanStack Start. Create a `tsconfig.jso ## Install Dependencies -TanStack Start is (currently\*) powered by [Vinxi](https://vinxi.vercel.app/) and [TanStack Router](https://tanstack.com/router) and requires them as dependencies. - -> [!NOTE] > \*Vinxi will be removed before version 1.0.0 is released and TanStack will rely only on Vite and Nitro. The commands and APIs that use Vinxi will likely be replaced with a Vite plugin or dedicated TanStack Start CLI. +TanStack Start is powered by [Vite](https://vite.dev/) and [TanStack Router](https://tanstack.com/router) and requires them as dependencies. To install them, run: ```shell -npm i @tanstack/react-start @tanstack/react-router vinxi +npm i @tanstack/react-start @tanstack/react-router vite ``` -You'll also need React and the Vite React plugin, so install them too: +You'll also need React: ```shell npm i react react-dom -npm i -D @vitejs/plugin-react vite-tsconfig-paths ``` and some TypeScript: ```shell -npm i -D typescript @types/react @types/react-dom +npm i -D typescript @types/react @types/react-dom vite-tsconfig-paths ``` ## Update Configuration Files -We'll then update our `package.json` to use Vinxi's CLI and set `"type": "module"`: +We'll then update our `package.json` to use Vite's CLI and set `"type": "module"`: ```json { // ... "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build" } } ``` -Then configure TanStack Start's `app.config.ts` file: +Then configure TanStack Start's Vite plugin in `vite.config.ts`: -```typescript -// app.config.ts -import { defineConfig } from '@tanstack/react-start/config' +```ts +// vite.config.ts +import { defineConfig } from 'vite' import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/react-start/plugin/vite' export default defineConfig({ - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], + server: { + port: 3000, }, + plugins: [tsConfigPaths(), tanstackStart()], }) ``` ## Add the Basic Templating -There are four required files for TanStack Start usage: +There are 2 required files for TanStack Start usage: 1. The router configuration -2. The server entry point -3. The client entry point -4. The root of your application +2. The root of your application Once configuration is done, we'll have a file tree that looks like the following: ``` . -├── app/ +├── src/ │ ├── routes/ │ │ └── `__root.tsx` -│ ├── `client.tsx` │ ├── `router.tsx` │ ├── `routeTree.gen.ts` -│ └── `ssr.tsx` ├── `.gitignore` -├── `app.config.ts` +├── `vite.config.ts` ├── `package.json` └── `tsconfig.json` ``` @@ -139,7 +129,7 @@ from the default [preloading functionality](/router/latest/docs/framework/react/ > You won't have a `routeTree.gen.ts` file yet. This file will be generated when you run TanStack Start for the first time. ```tsx -// app/router.tsx +// src/router.tsx import { createRouter as createTanStackRouter } from '@tanstack/react-router' import { routeTree } from './routeTree.gen' @@ -159,54 +149,12 @@ declare module '@tanstack/react-router' { } ``` -## The Server Entry Point - -As TanStack Start is an [SSR](https://unicorn-utterances.com/posts/what-is-ssr-and-ssg) framework, we need to pipe this router -information to our server entry point: - -```tsx -// app/ssr.tsx -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) -``` - -This allows us to know what routes and loaders we need to execute when the user hits a given route. - -## The Client Entry Point - -Now we need a way to hydrate our client-side JavaScript once the route resolves to the client. We do this by piping the same -router information to our client entry point: - -```tsx -// app/client.tsx -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) -``` - -This enables us to kick off client-side routing once the user's initial server request has fulfilled. - ## The Root of Your Application Finally, we need to create the root of our application. This is the entry point for all other routes. The code in this file will wrap all other routes in the application. ```tsx -// app/routes/__root.tsx +// src/routes/__root.tsx import type { ReactNode } from 'react' import { Outlet, @@ -258,12 +206,12 @@ function RootDocument({ children }: Readonly<{ children: ReactNode }>) { ## Writing Your First Route -Now that we have the basic templating setup, we can write our first route. This is done by creating a new file in the `app/routes` directory. +Now that we have the basic templating setup, we can write our first route. This is done by creating a new file in the `src/routes` directory. ```tsx -// app/routes/index.tsx +// src/routes/index.tsx import * as fs from 'node:fs' -import { createFileRoute, useRouter } from '@tanstack/react-router' +import { useRouter } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' const filePath = 'count.txt' @@ -287,7 +235,7 @@ const updateCount = createServerFn({ method: 'POST' }) await fs.promises.writeFile(filePath, `${count + data}`) }) -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, loader: async () => await getCount(), }) diff --git a/docs/start/framework/react/databases.md b/docs/start/framework/react/databases.md index 6f6aba34bd..e2a0bc42de 100644 --- a/docs/start/framework/react/databases.md +++ b/docs/start/framework/react/databases.md @@ -41,9 +41,9 @@ While TanStack Start is designed to work with any database provider, we highly r - - - Neon logo + + + Neon logo @@ -65,9 +65,9 @@ Key features that make Neon stand out: - - - Convex logo + + + Convex logo diff --git a/docs/start/framework/react/hosting.md b/docs/start/framework/react/hosting.md index 5241494e80..85d3185d0a 100644 --- a/docs/start/framework/react/hosting.md +++ b/docs/start/framework/react/hosting.md @@ -3,7 +3,7 @@ id: hosting title: Hosting --- -Hosting is the process of deploying your application to the internet so that users can access it. This is a critical part of any web development project, ensuring your application is available to the world. TanStack Start is built on [Nitro](https://nitro.unjs.io/), a powerful server toolkit for deploying web applications anywhere. Nitro allows TanStack Start to provide a unified API for SSR, streaming, and hydration on any hosting provider. +Hosting is the process of deploying your application to the internet so that users can access it. This is a critical part of any web development project, ensuring your application is available to the world. TanStack Start is built on Vite, a powerful dev/build platform that allows us to make it possible to deploy your application to any hosting provider. ## What should I use? @@ -15,9 +15,9 @@ However, since hosting is one of the most crucial aspects of your application's - - - Netlify logo + + + Netlify logo @@ -31,7 +31,7 @@ Netlify is a leading hosting platform that provides a fast, secure, and reliable > [!WARNING] > The page is still a work in progress. We'll keep updating this page with guides on deployment to different hosting providers soon! -When a TanStack Start application is being deployed, the `server.preset` value in the `app.config.ts` file determines the deployment target. The deployment target can be set to one of the following values: +When a TanStack Start application is being deployed, the `target` value in the TanStack Start Vite plugin in the`vite.config.ts` file determines the deployment target. The deployment target can be set to one of the following values: - [`netlify`](#netlify): Deploy to Netlify - [`vercel`](#vercel): Deploy to Vercel @@ -44,48 +44,34 @@ Once you've chosen a deployment target, you can follow the deployment guidelines ### Netlify -Set the `server.preset` value to `netlify` in your `app.config.ts` file. +Set the `target` value to `'netlify'` in the TanStack Start Vite plugin in `vite.config.ts` file. ```ts -// app.config.ts -import { defineConfig } from '@tanstack/react-start/config' +// vite.config.ts +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' export default defineConfig({ - server: { - preset: 'netlify', - }, + plugins: [tanstackStart({ target: 'netlify' })], }) ``` -Or you can use the `--preset` flag with the `build` command to specify the deployment target when building the application: - -```sh -npm run build --preset netlify -``` - Deploy your application to Netlify using their one-click deployment process, and you're ready to go! ### Vercel -Deploying your TanStack Start application to Vercel is easy and straightforward. Just set the `server.preset` value to `vercel` in your `app.config.ts` file, and you're ready to deploy your application to Vercel. +Set the `target` value to `'vercel'` in the TanStack Start Vite plugin in `vite.config.ts` file. ```ts -// app.config.ts -import { defineConfig } from '@tanstack/react-start/config' +// vite.config.ts +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' export default defineConfig({ - server: { - preset: 'vercel', - }, + plugins: [tanstackStart({ target: 'vercel' })], }) ``` -Or you can use the `--preset` flag with the `build` command to specify the deployment target when building the application: - -```sh -npm run build --preset vercel -``` - Deploy your application to Vercel using their one-click deployment process, and you're ready to go! ### Cloudflare Pages diff --git a/docs/start/framework/react/learn-the-basics.md b/docs/start/framework/react/learn-the-basics.md index cc00141883..a3da690428 100644 --- a/docs/start/framework/react/learn-the-basics.md +++ b/docs/start/framework/react/learn-the-basics.md @@ -7,13 +7,10 @@ This guide will help you learn the basics behind how TanStack Start works, regar ## Dependencies -TanStack Start is (currently\*) powered by [Vinxi](https://vinxi.vercel.app/), [Nitro](https://nitro.unjs.io/) and [TanStack Router](https://tanstack.com/router). +TanStack Start is powered by [Vite](https://vite.dev/) and [TanStack Router](https://tanstack.com/router). - **TanStack Router**: A router for building web applications. -- **Nitro**: A framework for building server applications. -- **Vinxi**: A server framework for building web applications. - -> [!NOTE] Vinxi will be removed before version 1.0.0 is released and TanStack will rely only on Vite and Nitro. The commands and APIs that use Vinxi will likely be replaced with a Vite plugin. +- **Vite**: A build tool for bundling your application. ## It all "Starts" with the Router @@ -47,54 +44,60 @@ declare module '@tanstack/react-router' { The `routeTree.gen.ts` file is generated when you run TanStack Start (via `npm run dev` or `npm run start`) for the first time. This file contains the generated route tree and a handful of TS utilities that make TanStack Start fully type-safe. -## The Server Entry Point +## The Server Entry Point (Optional) -Although TanStack Start is designed with client-first APIs, it is by and large, a full-stack framework. This means that all use cases, including both dynamic and static rely on a server or build-time entry to render our application's initial HTML payload. +> [!NOTE] +> The server entry point is **optional** out of the box. If not provided, TanStack Start will automatically handle the server entry point for you using the below as a default. -This is done via the `app/ssr.tsx` file: +This is done via the `src/server.ts` file: ```tsx -// app/ssr.tsx +// src/server.ts import { createStartHandler, defaultStreamHandler, } from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - import { createRouter } from './router' export default createStartHandler({ createRouter, - getRouterManifest, })(defaultStreamHandler) ``` -Whether we are statically generating our app or serving it dynamically, the `ssr.tsx` file is the entry point for doing all SSR-related work. +Whether we are statically generating our app or serving it dynamically, the `server.ts` file is the entry point for doing all SSR-related work. - It's important that a new router is created for each request. This ensures that any data handled by the router is unique to the request. -- The `getRouterManifest` function is used to generate the router manifest, which is used to determine many aspects of asset management and preloading for our application. - The `defaultStreamHandler` function is used to render our application to a stream, allowing us to take advantage of streaming HTML to the client. (This is the default handler, but you can also use other handlers like `defaultRenderHandler`, or even build your own) -## The Client Entry Point +## The Client Entry Point (Optional) + +> [!NOTE] +> The client entry point is **optional** out of the box. If not provided, TanStack Start will automatically handle the client entry point for you using the below as a default. Getting our html to the client is only half the battle. Once there, we need to hydrate our client-side JavaScript once the route resolves to the client. We do this by hydrating the root of our application with the `StartClient` component: ```tsx // app/client.tsx -import { hydrateRoot } from 'react-dom/client' import { StartClient } from '@tanstack/react-start' +import { StrictMode } from 'react' +import { hydrateRoot } from 'react-dom/client' import { createRouter } from './router' const router = createRouter() -hydrateRoot(document, ) +hydrateRoot( + document, + + + , +) ``` This enables us to kick off client-side routing once the user's initial server request has fulfilled. ## The Root of Your Application -Other than the client entry point, the `__root` route of your application is the entry point for your application. The code in this file will wrap all other routes in the app, including your home page. It behaves like a pathless layout route for your whole application. +Other than the client entry point (which is optional by default), the `__root` route of your application is the entry point for your application. The code in this file will wrap all other routes in the app, including your home page. It behaves like a pathless layout route for your whole application. Because it is **always rendered**, it is the perfect place to construct your application shell and take care of any global logic. diff --git a/docs/start/framework/react/middleware.md b/docs/start/framework/react/middleware.md index 7eb75ba032..9877da95fd 100644 --- a/docs/start/framework/react/middleware.md +++ b/docs/start/framework/react/middleware.md @@ -24,12 +24,14 @@ Middleware is defined using the `createMiddleware` function. This function retur ```tsx import { createMiddleware } from '@tanstack/react-start' -const loggingMiddleware = createMiddleware().server(async ({ next, data }) => { - console.log('Request received:', data) - const result = await next() - console.log('Response processed:', result) - return result -}) +const loggingMiddleware = createMiddleware({ type: 'function' }).server( + async ({ next, data }) => { + console.log('Request received:', data) + const result = await next() + console.log('Response processed:', result) + return result + }, +) ``` ## Using Middleware in Your Server Functions @@ -63,7 +65,7 @@ The `middleware` method is used to dependency middleware to the chain that will ```tsx import { createMiddleware } from '@tanstack/react-start' -const loggingMiddleware = createMiddleware().middleware([ +const loggingMiddleware = createMiddleware({ type: 'function' }).middleware([ authMiddleware, loggingMiddleware, ]) @@ -84,7 +86,7 @@ const mySchema = z.object({ workspaceId: z.string(), }) -const workspaceMiddleware = createMiddleware() +const workspaceMiddleware = createMiddleware({ type: 'function' }) .validator(zodValidator(mySchema)) .server(({ next, data }) => { console.log('Workspace ID:', data.workspaceId) @@ -107,12 +109,14 @@ The `next` function is used to execute the next middleware in the chain. **You m ```tsx import { createMiddleware } from '@tanstack/react-start' -const loggingMiddleware = createMiddleware().server(async ({ next }) => { - console.log('Request received') - const result = await next() - console.log('Response processed') - return result -}) +const loggingMiddleware = createMiddleware({ type: 'function' }).server( + async ({ next }) => { + console.log('Request received') + const result = await next() + console.log('Response processed') + return result + }, +) ``` ## Providing context to the next middleware via `next` @@ -122,15 +126,17 @@ The `next` function can be optionally called with an object that has a `context` ```tsx import { createMiddleware } from '@tanstack/react-start' -const awesomeMiddleware = createMiddleware().server(({ next }) => { - return next({ - context: { - isAwesome: Math.random() > 0.5, - }, - }) -}) +const awesomeMiddleware = createMiddleware({ type: 'function' }).server( + ({ next }) => { + return next({ + context: { + isAwesome: Math.random() > 0.5, + }, + }) + }, +) -const loggingMiddleware = createMiddleware().server( +const loggingMiddleware = createMiddleware({ type: 'function' }).server( async ({ next, context }) => { console.log('Is awesome?', context.isAwesome) return next() @@ -180,12 +186,14 @@ Similar to the `server` function, it also receives an object with the following - `context`: An object that stores data from parent middleware. It can be extended with additional data that will be passed to child middleware. ```tsx -const loggingMiddleware = createMiddleware().client(async ({ next }) => { - console.log('Request sent') - const result = await next() - console.log('Response received') - return result -}) +const loggingMiddleware = createMiddleware({ type: 'function' }).client( + async ({ next }) => { + console.log('Request sent') + const result = await next() + console.log('Response received') + return result + }, +) ``` ## Sending client context to the server @@ -193,7 +201,7 @@ const loggingMiddleware = createMiddleware().client(async ({ next }) => { **Client context is NOT sent to the server by default since this could end up unintentionally sending large payloads to the server.** If you need to send client context to the server, you must call the `next` function with a `sendContext` property and object to transmit any data to the server. Any properties passed to `sendContext` will be merged, serialized and sent to the server along with the data and will be available on the normal context object of any nested server middleware. ```tsx -const requestLogger = createMiddleware() +const requestLogger = createMiddleware({ type: 'function' }) .client(async ({ next, context }) => { return next({ sendContext: { @@ -217,7 +225,7 @@ You may have noticed that in the example above that while client-sent context is import { zodValidator } from '@tanstack/zod-adapter' import { z } from 'zod' -const requestLogger = createMiddleware() +const requestLogger = createMiddleware({ type: 'function' }) .client(async ({ next, context }) => { return next({ sendContext: { @@ -241,16 +249,18 @@ Similar to sending client context to the server, you can also send server contex > The return type of `next` in `client` can only be inferred from middleware known in the current middleware chain. Therefore the most accurate return type of `next` is in middleware at the end of the middleware chain ```tsx -const serverTimer = createMiddleware().server(async ({ next }) => { - return next({ - sendContext: { - // Send the current time to the client - timeFromServer: new Date(), - }, - }) -}) +const serverTimer = createMiddleware({ type: 'function' }).server( + async ({ next }) => { + return next({ + sendContext: { + // Send the current time to the client + timeFromServer: new Date(), + }, + }) + }, +) -const requestLogger = createMiddleware() +const requestLogger = createMiddleware({ type: 'function' }) .middleware([serverTimer]) .client(async ({ next }) => { const result = await next() @@ -276,13 +286,15 @@ Here's an example of adding an `Authorization` header any request using this mid ```tsx import { getToken } from 'my-auth-library' -const authMiddleware = createMiddleware().client(async ({ next }) => { - return next({ - headers: { - Authorization: `Bearer ${getToken()}`, - }, - }) -}) +const authMiddleware = createMiddleware({ type: 'function' }).client( + async ({ next }) => { + return next({ + headers: { + Authorization: `Bearer ${getToken()}`, + }, + }) + }, +) ``` ## Using Middleware @@ -323,10 +335,12 @@ registerGlobalMiddleware({ ```tsx // authMiddleware.ts -const authMiddleware = createMiddleware().server(({ next, context }) => { - console.log(context.user) // <-- This will not be typed! - // ... -}) +const authMiddleware = createMiddleware({ type: 'function' }).server( + ({ next, context }) => { + console.log(context.user) // <-- This will not be typed! + // ... + }, +) ``` To solve this, add the global middleware you are trying to reference to the server function's middleware array. **The global middleware will be deduped to a single entry (the global instance), and your server function will receive the correct types.** @@ -356,40 +370,44 @@ Middleware is executed dependency-first, starting with global middleware, follow - `d` ```tsx -const globalMiddleware1 = createMiddleware().server(async ({ next }) => { - console.log('globalMiddleware1') - return next() -}) +const globalMiddleware1 = createMiddleware({ type: 'function' }).server( + async ({ next }) => { + console.log('globalMiddleware1') + return next() + }, +) -const globalMiddleware2 = createMiddleware().server(async ({ next }) => { - console.log('globalMiddleware2') - return next() -}) +const globalMiddleware2 = createMiddleware({ type: 'function' }).server( + async ({ next }) => { + console.log('globalMiddleware2') + return next() + }, +) registerGlobalMiddleware({ middleware: [globalMiddleware1, globalMiddleware2], }) -const a = createMiddleware().server(async ({ next }) => { +const a = createMiddleware({ type: 'function' }).server(async ({ next }) => { console.log('a') return next() }) -const b = createMiddleware() +const b = createMiddleware({ type: 'function' }) .middleware([a]) .server(async ({ next }) => { console.log('b') return next() }) -const c = createMiddleware() +const c = createMiddleware({ type: 'function' }) .middleware() .server(async ({ next }) => { console.log('c') return next() }) -const d = createMiddleware() +const d = createMiddleware({ type: 'function' }) .middleware([b, c]) .server(async () => { console.log('d') diff --git a/docs/start/framework/react/observability.md b/docs/start/framework/react/observability.md index fb483ba814..78e6a2dff3 100644 --- a/docs/start/framework/react/observability.md +++ b/docs/start/framework/react/observability.md @@ -15,9 +15,9 @@ However, for the best observability experience, we highly recommend using [Sentr - - - Convex logo + + + Convex logo diff --git a/docs/start/framework/react/overview.md b/docs/start/framework/react/overview.md index ca4bbac835..30f0388822 100644 --- a/docs/start/framework/react/overview.md +++ b/docs/start/framework/react/overview.md @@ -3,7 +3,7 @@ id: overview title: TanStack Start Overview --- -TanStack Start is a full-stack React framework powered by TanStack Router. It provides a full-document SSR, streaming, server functions, bundling, and more using tools like [Nitro](https://nitro.unjs.io/) and [Vite](https://vitejs.dev/). It is ready to deploy to your favorite hosting provider! +TanStack Start is a full-stack React framework powered by TanStack Router. It provides a full-document SSR, streaming, server functions, bundling, and more. Thanks to [Vite](https://vite.dev/), it's ready to develop and deploy to any hosting provider or runtime you want! ## Router or Start? @@ -39,7 +39,7 @@ What you get with TanStack Start: ## How does it work? -TanStack Start uses [Nitro](https://nitro.unjs.io/) and [Vite](https://vitejs.dev/) to bundle and deploy your application. In fact, these are the same tools that power Solid Start! With these tools, we can do a few things we couldn't do before: +TanStack Start uses [Vite](https://vitejs.dev/) to bundle and deploy your application and empowers amazing features like: - Provide a unified API for SSR, streaming, and hydration - Extract server-only code from your client-side code (e.g. server functions) @@ -71,45 +71,45 @@ TanStack works closely with our partners to provide the best possible developer - **Clerk** - - - Clerk logo + + + Clerk logo The best possible authentication experience for modern web applications, including TanStack Start applications. Clerk provides TanStack Start users with first-class integrations and solutions to auth and collaborates closely with the TanStack team to ensure that TanStack Start provides APIs that are up to date with the latest in auth best practices. - **Netlify** - - - Netlify logo + + + Netlify logo The leading hosting platform for web applications that provides a fast, secure, and reliable environment for deploying your web applications. We work closely with Netlify to ensure that TanStack Start applications not only deploy seamlessly to their platform, but also implement best practices for performance, security, and reliability regardless of where you end up deploying. - **Neon** - - - Neon logo + + + Neon logo A serverless, autoscaling Postgres solution purpose-built for modern full-stack apps. Neon offers rich integration opportunities with TanStack Start, including server functions and database-backed routing. Together, we’re simplifying the database experience for developers using TanStack. - **Convex** - - - Convex logo + + + Convex logo A serverless database platform that integrates seamlessly with TanStack Start. Convex is designed to simplify the process of managing your application's data and provides a real-time, scalable, and transactional data backend that works well with TanStack Start applications. Convex also collaborates closely with the TanStack team to ensure that TanStack Start provides APIs that are up to date with the latest in database best practices. - **Sentry** - - - Sentry logo + + + Sentry logo A powerful, full-featured observability platform that integrates seamlessly with TanStack Start. Sentry helps developers monitor and fix crashes in real-time and provides insights into your application's performance and error tracking. Sentry collaborates closely with the TanStack team to ensure that TanStack Start provides APIs that are up to date with the latest in observability best practices. diff --git a/docs/start/framework/react/server-functions.md b/docs/start/framework/react/server-functions.md index 61c97a5080..e4d8e43a9f 100644 --- a/docs/start/framework/react/server-functions.md +++ b/docs/start/framework/react/server-functions.md @@ -7,8 +7,8 @@ title: Server Functions Server functions allow you to specify logic that can be invoked almost anywhere (even the client), but run **only** on the server. In fact, they are not so different from an API Route, but with a few key differences: -- They do not have stable public URL (but you'll be able to do this very soon!) -- They can be called from anywhere in your application, including loaders, hooks, components, etc., but cannot be called from API Routes. +- They do not have stable public URL. +- They can be called from anywhere in your application, including loaders, hooks, components, server routes etc. However, they are similar to regular API Routes in that: diff --git a/docs/start/framework/react/server-routes.md b/docs/start/framework/react/server-routes.md new file mode 100644 index 0000000000..9b905a1802 --- /dev/null +++ b/docs/start/framework/react/server-routes.md @@ -0,0 +1,382 @@ +--- +id: server-routes +title: Server Routes +--- + +// TODO: Add redirect from api-routes to server-routes + +Server routes are a powerful feature of TanStack Start that allow you to create server-side endpoints in your application and are useful for handling raw HTTP requests, form submissions, user authentication, and much more. + +Server routes can be defined in your `./src/routes` directory of your project **right alongside your TanStack Router routes** and are automatically handled by the TanStack Start server. + +Here's what a simple server route looks like: + +```ts +// routes/hello.ts + +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + return new Response('Hello, World!') + }, +}) +``` + +## Server Routes and App Routes + +Because server routes can be defined in the same directory as your app routes, you can even use the same file for both! + +```tsx +// routes/hello.tsx + +export const ServerRoute = createServerFileRoute().methods({ + POST: async ({ request }) => { + const body = await request.json() + return new Response(JSON.stringify({ message: `Hello, ${body.name}!` })) + }, +}) + +export const Route = createFileRoute({ + component: HelloComponent, +}) + +function HelloComponent() { + const [reply, setReply] = useState('') + + return ( +
+ +
+ ) +} +``` + +## File Route Conventions + +Server routes in TanStack Start, follow the same file-based routing conventions as TanStack Router. This means that each file in your `routes` directory with a `ServerRoute` export will be treated as an API route. Here are a few examples: + +- `/routes/users.ts` will create an API route at `/users` +- `/routes/users.index.ts` will **also** create an API route at `/users` (but will error if duplicate methods are defined) +- `/routes/users/$id.ts` will create an API route at `/users/$id` +- `/routes/users/$id/posts.ts` will create an API route at `/users/$id/posts` +- `/routes/users.$id.posts.ts` will create an API route at `/users/$id/posts` +- `/routes/file/$.ts` will create an API route at `/api/file/$` +- `/routes/my-script[.]js.ts` will create an API route at `/my-script.js` + +## Unique Route Paths + +Each route can only have a single handler file associated with it. So, if you have a file named `routes/users.ts` which'd equal the request path of `/api/users`, you cannot have other files that'd also resolve to the same route. For example, the following files would all resolve to the same route and would error: + +- `/routes/users.index.ts` +- `/routes/users.ts` +- `/routes/users.index.ts` + +## Escaped Matching + +Just as with normal routes, server routes can match on escaped characters. For example, a file named `routes/users[.]json.ts` will create an API route at `/api/users[.]json`. + +## Pathless Layout Routes and Break-out Routes + +Because of the unified routing system, pathless layout routes and break-out routes are supported for similar functionality around server route middleware. + +- Pathless layout routes can be used to add middleware to a group of routes +- Break-out routes can be used to "break out" of parent middleware + +## Nested Directories vs File-names + +In the examples above, you may have noticed that the file naming conventions are flexible and allow you to mix and match directories and file names. This is intentional and allows you to organize your Server routes in a way that makes sense for your application. You can read more about this in the [TanStack Router File-based Routing Guide](/router/latest/docs/framework/react/routing/file-based-routing#s-or-s). + +## Handling Server Route Requests + +Server route requests are handled by Start's `createStartHandler` in your `server.ts` entry file. + +```tsx +// server.ts +import { + createStartHandler, + defaultStreamHandler, +} from '@tanstack/react-start/server' +import { createRouter } from './router' + +export default createStartHandler({ + createRouter, +})(defaultStreamHandler) +``` + +The start handler is responsible for matching an incoming request to a server route and executing the appropriate middleware and handler. + +Remember, if you need to customize the server handler, you can do so by creating a custom handler and then passing the event to the start handler: + +```tsx +// server.ts +import { createStartHandler } from '@tanstack/react-start/server' + +export default defineHandler((event) => { + const startHandler = createStartHandler({ + createRouter, + })(defaultStreamHandler) + + return startHandler(event) +}) +``` + +## Defining an Server Route + +Server routes are created by exporting a `ServerRoute` from a route file. The `ServerRoute` export should be created by calling the `createServerFileRoute` function. The resulting builder object can then be used to: + +- Add route-level middleware +- Define handlers for each HTTP method + +```ts +// routes/hello.ts +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + return new Response('Hello, World! from ' + request.url) + }, +}) +``` + +## Defining a Server Route Handler + +There are two ways to define a handler for a server route. + +- Provide a handler function directly to the method +- By calling the `handler` method on the method builder object for more advanced use cases + +### Providing a handler function directly to the method + +For simple use cases, you can provide a handler function directly to the method. + +```ts +// routes/hello.ts +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + return new Response('Hello, World! from ' + request.url) + }, +}) +``` + +### Providing a handler function via the method builder object + +For more complex use cases, you can provide a handler function via the method builder object. This allows you to add middleware to the method. + +```tsx +// routes/hello.ts +export const ServerRoute = createServerFileRoute().methods((api) => ({ + GET: api.middleware([loggerMiddleware]).handler(async ({ request }) => { + return new Response('Hello, World! from ' + request.url) + }), +})) +``` + +## Handler Context + +Each HTTP method handler receives an object with the following properties: + +- `request`: The incoming request object. You can read more about the `Request` object in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Request). +- `params`: An object containing the dynamic path parameters of the route. For example, if the route path is `/users/$id`, and the request is made to `/users/123`, then `params` will be `{ id: '123' }`. We'll cover dynamic path parameters and wildcard parameters later in this guide. +- `context`: An object containing the context of the request. This is useful for passing data between middleware. + +Once you've processed the request, you can return a `Response` object or `Promise` or even use any of the helpers from `@tanstack/react-start` to manipulate the response. + +## Dynamic Path Params + +Server routes support dynamic path parameters in the same way as TanStack Router. For example, a file named `routes/users/$id.ts` will create an API route at `/users/$id` that accepts a dynamic `id` parameter. + +```ts +// routes/users/$id.ts +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ params }) => { + const { id } = params + return new Response(`User ID: ${id}`) + }, +}) + +// Visit /api/users/123 to see the response +// User ID: 123 +``` + +You can also have multiple dynamic path parameters in a single route. For example, a file named `routes/users/$id/posts/$postId.ts` will create an API route at `/api/users/$id/posts/$postId` that accepts two dynamic parameters. + +```ts +// routes/users/$id/posts/$postId.ts +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ params }) => { + const { id, postId } = params + return new Response(`User ID: ${id}, Post ID: ${postId}`) + }, +}) + +// Visit /api/users/123/posts/456 to see the response +// User ID: 123, Post ID: 456 +``` + +## Wildcard/Splat Param + +Server routes also support wildcard parameters at the end of the path, which are denoted by a `$` followed by nothing. For example, a file named `routes/file/$.ts` will create an API route at `/api/file/$` that accepts a wildcard parameter. + +```ts +// routes/file/$.ts +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ params }) => { + const { _splat } = params + return new Response(`File: ${_splat}`) + }, +}) + +// Visit /api/file/hello.txt to see the response +// File: hello.txt +``` + +## Handling requests with a body + +To handle POST requests,you can add a `POST` handler to the route object. The handler will receive the request object as the first argument, and you can access the request body using the `request.json()` method. + +```ts +// routes/hello.ts +export const ServerRoute = createServerFileRoute().methods({ + POST: async ({ request }) => { + const body = await request.json() + return new Response(`Hello, ${body.name}!`) + }, +}) + +// Send a POST request to /api/hello with a JSON body like { "name": "Tanner" } +// Hello, Tanner! +``` + +This also applies to other HTTP methods like `PUT`, `PATCH`, and `DELETE`. You can add handlers for these methods in the route object and access the request body using the appropriate method. + +It's important to remember that the `request.json()` method returns a `Promise` that resolves to the parsed JSON body of the request. You need to `await` the result to access the body. + +This is a common pattern for handling POST requests in Server routes/ You can also use other methods like `request.text()` or `request.formData()` to access the body of the request. + +## Responding with JSON + +When returning JSON using a Response object, this is a common pattern: + +```ts +// routes/hello.ts +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + return new Response(JSON.stringify({ message: 'Hello, World!' }), { + headers: { + 'Content-Type': 'application/json', + }, + }) + }, +}) + +// Visit /api/hello to see the response +// {"message":"Hello, World!"} +``` + +## Using the `json` helper function + +Or you can use the `json` helper function to automatically set the `Content-Type` header to `application/json` and serialize the JSON object for you. + +```ts +// routes/hello.ts +import { json } from '@tanstack/react-start' + +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + return json({ message: 'Hello, World!' }) + }, +}) + +// Visit /api/hello to see the response +// {"message":"Hello, World!"} +``` + +## Responding with a status code + +You can set the status code of the response by either: + +- Passing it as a property of the second argument to the `Response` constructor + + ```ts + // routes/hello.ts + import { json } from '@tanstack/react-start' + + export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ request, params }) => { + const user = await findUser(params.id) + if (!user) { + return new Response('User not found', { + status: 404, + }) + } + return json(user) + }, + }) + ``` + +- Using the `setResponseStatus` helper function from `@tanstack/react-start/server` + + ```ts + // routes/hello.ts + import { json } from '@tanstack/react-start' + import { setResponseStatus } from '@tanstack/react-start/server' + + export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ request, params }) => { + const user = await findUser(params.id) + if (!user) { + setResponseStatus(404) + return new Response('User not found') + } + return json(user) + }, + }) + ``` + +In this example, we're returning a `404` status code if the user is not found. You can set any valid HTTP status code using this method. + +## Setting headers in the response + +Sometimes you may need to set headers in the response. You can do this by either: + +- Passing an object as the second argument to the `Response` constructor. + + ```ts + // routes/hello.ts + export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + return new Response('Hello, World!', { + headers: { + 'Content-Type': 'text/plain', + }, + }) + }, + }) + + // Visit /api/hello to see the response + // Hello, World! + ``` + +- Or using the `setHeaders` helper function from `@tanstack/react-start/server`. + + ```ts + // routes/hello.ts + import { setHeaders } from '@tanstack/react-start/server' + + export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + setHeaders({ + 'Content-Type': 'text/plain', + }) + return new Response('Hello, World!') + }, + }) + ``` diff --git a/docs/start/framework/react/spa-mode.md b/docs/start/framework/react/spa-mode.md new file mode 100644 index 0000000000..c2d5450c5b --- /dev/null +++ b/docs/start/framework/react/spa-mode.md @@ -0,0 +1,188 @@ +--- +id: spa-mode +title: SPA mode +--- + +## What the heck is SPA mode? + +For applications that do not require SSR for either SEO, crawlers, or performance reasons, it may be desirable to ship static HTML to your users containing the "shell" of your application (or even prerendered HTML for specific routes) that contain the necessary `html`, `head`, and `body` tags to bootstrap your application only on the client. + +## Why use Start without SSR? + +**No SSR doesn't mean giving up server-side features!** SPA modes actually pair very nicely with server-side features like server functions and/or server routes or even other external APIs. It **simply means that the initial document will not contain the fully rendered HTML of your application until it has been rendered on the client using JavaScript**. + +## Benefits of SPA mode + +- **Easier to deploy** - A CDN that can serve static assets is all you need. +- **Cheaper** to host - CDNs are cheap compared to Lambda functions or long-running processes. +- **Client-side Only is simpler** - No SSR means less to go wrong with hydration, rendering, and routing. + +## Caveats of SPA mode + +- **Slower time to full content** - Time to full content is longer since all JS must download and execute before anything below the shell can be rendered. +- **Less SEO friendly** - Robots, crawlers and link unfurlers _may_ have a harder time indexing your application unless they are configured to execute JS and your application can render within a reasonable amount of time. + +## How does it work? + +After enabling the SPA mode, running a Start build will have an additional prerendering step afterwards to generate the shell. This is done by: + +- **Prerendering** your application's **root route only** +- Where your application would normally render your matched routes, your router's configured **pending fallback component is rendered instead**. +- The resulting HTML is stored to a static HTML page called `/_shell.html` (configurable) +- Default rewrites are configured to redirect all 404 requests to the SPA mode shell + +> [!NOTE] +> Other routes may also be prerendered and it is recommended to prerender as much as you can in SPA mode, but this is not required for SPA mode to work. + +## Configuring SPA mode + +To configure SPA mode, there are a few options you can add to your Start plugin's options: + +```tsx +// vite.config.ts +export default defineConfig({ + plugins: [ + TanStackStart({ + spa: { + enabled: true, + }, + }), + ], +}) +``` + +## Use Necessary Redirects + +Deploying a purely client-side SPA to a host or CDN often requires the use of redirects to ensure that urls are properly rewritten to the SPA shell. The goal of any deployment should include these priorities in this order: + +1. Ensure that static assets will always be served if they exist, e.g. /about.html. This is usually the default behavior for most CDNs +2. (Optional) Allow-list specific subpaths to be routed through to any dynamic server handlers, e.g. /api/\*\* (More on this below) +3. Ensure that all 404 requests are rewritten to the SPA shell, e.g. a catch-all redirect to /\_shell.html (or if you have configured your shell output path to be something custom, use that instead) + +## Basic Redirects Example + +Let's use Netlify's `_redirects` file to rewrite all 404 requests to the SPA shell. + +``` +# Catch all other 404 requests and rewrite them to the SPA shell +/* /_shell.html 200 +``` + +## Allowing Server Functions and Server Routes + +Again, using Netlify's `_redirects` file, we can allow-list specific subpaths to be routed through to the server. + +``` +# Allow requests to /_serverFn/* to be routed through to the server (If you have configured your server function base path to be something other than /_serverFn, use that instead) +/_serverFn/* /_serverFn/:splat 200 + +# Allow any requests to /api/* to be routed through to the server (Server routes can be created at any path, so you must ensure that any server routes you want to use are under this path, or simply add additional redirects for each server route base you want to expose) +/api/* /api/:splat 200 + +# Catch all other 404 requests and rewrite them to the SPA shell +/* /_shell.html 200 +``` + +## Shell Mask Path + +The default pathname used to generate the SPA shell is `/`. We call this the **shell mask path**. Since matched routes are not included, the pathname used to generate the shell is mostly irrelevant, but it's still configurable. + +> [!NOTE] +> It's recommended to keep the default value of `/` as the shell mask path. + +```tsx +// vite.config.ts +export default defineConfig({ + plugins: [ + TanStackStart({ + spa: { + maskPath: '/app', + }, + }), + ], +}) +``` + +## Prerendering Options + +The prerender option is used to configure the prerendering behavior of the SPA shell, and accepts the same prerender options as found in our prerendering guide. + +**By default, the following `prerender` options are set:** + +- `outputPath`: `/_shell.html` +- `crawlLinks`: `false` +- `retryCount`: `0` + +This means that by default, the shell will not be crawled for links to follow for additional prerendering, and will not retry prerendering fails. + +You can always override these options by providing your own prerender options: + +```tsx +// vite.config.ts +export default defineConfig({ + plugins: [ + TanStackStart({ + spa: { + prerender: { + outputPath: '/custom-shell', + crawlLinks: true, + retryCount: 3, + }, + }, + }), + ], +}) +``` + +## Customized rendering in SPA mode + +Customizing the HTML output of the SPA shell can be useful if you want to: + +- Provide generic head tags for SPA routes +- Provide a custom pending fallback component +- Change literally anything about the shell's HTML, CSS, and JS + +To make this process simple, an `isShell` boolean can be found on the `router` instance: + +```tsx +// src/routes/root.tsx +export default function Root() { + const isShell = useRouter().isShell + + if (isShell) console.log('Rendering the shell!') +} +``` + +You can use this boolean to conditionally render different UI based on whether the current route is a shell or not, but keep in mind that after hydrating the shell, the router will immediately navigate to the first route and the `isShell` boolean will be `false`. **This could produce flashes of unstyled content if not handled properly.** + +## Dynamic Data in your Shell + +Since the shell is prerendered using the SSR build of your application, any `loader`s, or server-specific functionality defined on your **Root Route** will run during the prerendering process and the data will be included in the shell. + +This means that you can use dynamic data in your shell by using a `loader` or server-specific functionality. + +```tsx +// src/routes/__root.tsx + +export const RootRoute = createRootRoute({ + loader: async () => { + return { + name: 'Tanner', + } + }, + component: Root, +}) + +export default function Root() { + const { name } = useLoaderData() + + return ( + + +

Hello, {name}!

+ + + + ) +} +``` diff --git a/docs/start/framework/react/ssr.md b/docs/start/framework/react/ssr.md deleted file mode 100644 index f509d47f72..0000000000 --- a/docs/start/framework/react/ssr.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -id: ssr -title: SSR ---- - -Server-side rendering (SSR) is the process of rendering your application on the server and sending or streaming the rendered HTML to the client. This can be useful for both improving the performance of your application and improving SEO, as it allows users to see the content of your application faster and allows search engines to crawl your application more easily. - -## SSR Basics - -TanStack Start supports server-side rendering out of the box. To enable server-side rendering, create an `app/ssr.tsx` file in your project: - -```tsx -// app/ssr.tsx - -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) -``` - -This file exports a function that creates a server-side rendering handler. The handler is created using the `createStartHandler` function from `@tanstack/react-start/server`, which takes an object with the following properties: - -- `createRouter`: A function that creates a router for your application. This function should return a new router instance each time it is called. -- `getRouterManifest`: A function that returns a manifest of all the routes in your application. - -The handler is then called with the `defaultStreamHandler` function from `@tanstack/react-start/server`, which is a function that streams the response to the client. diff --git a/docs/start/framework/react/static-prerendering.md b/docs/start/framework/react/static-prerendering.md index 768e11d539..30111f24fb 100644 --- a/docs/start/framework/react/static-prerendering.md +++ b/docs/start/framework/react/static-prerendering.md @@ -3,13 +3,11 @@ id: static-prerendering title: Static Prerendering --- -> Static Prerendering is a feature of Nitro, and while it is available in TanStack Start, we are still exploring the best practices for using it. Tread lightly! - Static prerendering is the process of generating static HTML files for your application. This can be useful for either improving the performance of your application, as it allows you to serve pre-rendered HTML files to users without having to generate them on the fly or for deploying static sites to platforms that do not support server-side rendering. -## Prerendering, powered by Nitro +## Prerendering -TanStack Start is built on Nitro, which means we can take advantage of Nitro's prerendering capabilities. Nitro can prerender your application to static HTML files, which can then be served to users without having to generate them on the fly. To prerender your application, you can add the `server.prerender` option to your `app.config.js` file: +TanStack Start can prerender your application to static HTML files, which can then be served to users without having to generate them on the fly. To prerender your application, you can add the `server.prerender` option to your `app.config.js` file: ```js // app.config.js @@ -25,39 +23,3 @@ export default defineConfig({ }, }) ``` - -Many of the options available for prerendering are documented in the [Nitro config prerender documentation](https://nitro.unjs.io/config#prerender). - -## Prerendering dynamic routes with Nitro - -Nitro ships with some prebuilt hooks that let you customize the prerendering process among other things. One of these hooks is the `prerender:routes` hook. This hook allows you to fetch async data and add routes to a `Set` of routes to be prerendered. - -For this example, let's pretend we have a blog with a list of posts. We want to prerender each post page. Our post route looks like `/posts/$postId`. We can use the `prerender:routes` hook to fetch the all of our posts and add each post path to the routes set. - -```ts -// app.config.ts -import { defineConfig } from '@tanstack/react-start/config' - -export default defineConfig({ - server: { - hooks: { - 'prerender:routes': async (routes) => { - // fetch the pages you want to render - const posts = await fetch('https://api.example.com/posts') - const postsData = await posts.json() - - // add each post path to the routes set - postsData.forEach((post) => { - routes.add(`/posts/${post.id}`) - }) - }, - }, - prerender: { - routes: ['/'], - crawlLinks: true, - }, - }, -}) -``` - -As of writing, the [Nitro hooks documentation](https://nitro.build/config#hooks) does not include any information on the provided hooks. diff --git a/docs/start/framework/solid/api-routes.md b/docs/start/framework/solid/api-routes.md deleted file mode 100644 index fcc7ab4613..0000000000 --- a/docs/start/framework/solid/api-routes.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -ref: docs/start/framework/react/api-routes.md -replace: { 'react': 'solid' } ---- diff --git a/docs/start/framework/solid/authentication.md b/docs/start/framework/solid/authentication.md index 24a74f7316..eee03da9da 100644 --- a/docs/start/framework/solid/authentication.md +++ b/docs/start/framework/solid/authentication.md @@ -17,9 +17,9 @@ That said, authentication is not something to be taken lightly. After much vetti - - - Convex logo + + + Convex logo diff --git a/docs/start/framework/solid/build-from-scratch.md b/docs/start/framework/solid/build-from-scratch.md index c5fcdb3563..4549c6f0ba 100644 --- a/docs/start/framework/solid/build-from-scratch.md +++ b/docs/start/framework/solid/build-from-scratch.md @@ -4,7 +4,7 @@ title: Build a Project from Scratch --- > [!NOTE] -> If you chose to quick start with an example or cloned project, you can skip this guide and move on to the [Learn the Basics](../learn-the-basics) guide. +> If you chose to quick start with an example or cloned project, you can skip this guide and move on to the [Learn the Basics](./learn-the-basics.md) guide. _So you want to build a TanStack Start project from scratch?_ @@ -48,85 +48,75 @@ We highly recommend using TypeScript with TanStack Start. Create a `tsconfig.jso ## Install Dependencies -TanStack Start is (currently\*) powered by [Vinxi](https://vinxi.vercel.app/) and [TanStack Router](https://tanstack.com/router) and requires them as dependencies. - -> [!NOTE] > \*Vinxi will be removed before version 1.0.0 is released and TanStack will rely only on Vite and Nitro. The commands and APIs that use Vinxi will likely be replaced with a Vite plugin or dedicated TanStack Start CLI. +TanStack Start is powered by [Vite](https://vite.dev/) and [TanStack Router](https://tanstack.com/router) and requires them as dependencies. To install them, run: ```shell -npm i @tanstack/solid-start @tanstack/solid-router vinxi +npm i @tanstack/solid-start @tanstack/solid-router vite ``` -You'll also need Solid and the Vite Solid plugin, so install them too: +You'll also need Solid: ```shell npm i solid-js -npm i -D vite-plugin-solid vite-tsconfig-paths ``` and some TypeScript: ```shell -npm i -D typescript +npm i -D typescript vite-tsconfig-paths ``` ## Update Configuration Files -We'll then update our `package.json` to use Vinxi's CLI and set `"type": "module"`: +We'll then update our `package.json` to use Vite's CLI and set `"type": "module"`: ```json { // ... "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build" } } ``` -Then configure TanStack Start's `app.config.ts` file: +Then configure TanStack Start's Vite plugin in `vite.config.ts`: -```typescript -// app.config.ts -import { defineConfig } from '@tanstack/solid-start/config' +```ts +// vite.config.ts +import { defineConfig } from 'vite' import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' export default defineConfig({ - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], + server: { + port: 3000, }, + plugins: [tsConfigPaths(), tanstackStart()], }) ``` ## Add the Basic Templating -There are four required files for TanStack Start usage: +There are 2 required files for TanStack Start usage: 1. The router configuration -2. The server entry point -3. The client entry point -4. The root of your application +2. The root of your application Once configuration is done, we'll have a file tree that looks like the following: ``` . -├── app/ +├── src/ │ ├── routes/ │ │ └── `__root.tsx` -│ ├── `client.tsx` │ ├── `router.tsx` │ ├── `routeTree.gen.ts` -│ └── `ssr.tsx` ├── `.gitignore` -├── `app.config.ts` +├── `vite.config.ts` ├── `package.json` └── `tsconfig.json` ``` @@ -140,7 +130,7 @@ from the default [preloading functionality](/router/latest/docs/framework/solid/ > You won't have a `routeTree.gen.ts` file yet. This file will be generated when you run TanStack Start for the first time. ```tsx -// app/router.tsx +// src/router.tsx import { createRouter as createTanStackRouter } from '@tanstack/solid-router' import { routeTree } from './routeTree.gen' @@ -160,54 +150,15 @@ declare module '@tanstack/solid-router' { } ``` -## The Server Entry Point - -As TanStack Start is an [SSR](https://unicorn-utterances.com/posts/what-is-ssr-and-ssg) framework, we need to pipe this router -information to our server entry point: - -```tsx -// app/ssr.tsx -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/solid-start/server' -import { getRouterManifest } from '@tanstack/solid-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) -``` - -This allows us to know what routes and loaders we need to execute when the user hits a given route. - -## The Client Entry Point - -Now we need a way to hydrate our client-side JavaScript once the route resolves to the client. We do this by piping the same -router information to our client entry point: - -```tsx -// app/client.tsx -/// -import { hydrate } from 'solid-js/web' -import { StartClient } from '@tanstack/solid-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrate(() => , document.body) -``` - -This enables us to kick off client-side routing once the user's initial server request has fulfilled. +> [!NOTE] +> TanStack Start provides **default server and client entry points** to handle requests and client-entry + hydration. You can customize these entry points by adding a `server.ts` and/or `client.tsx` file in the root of your project, but for now, we'll use the defaults. ## The Root of Your Application Finally, we need to create the root of our application. This is the entry point for all other routes. The code in this file will wrap all other routes in the application. ```tsx -// app/routes/__root.tsx +// src/routes/__root.tsx import { Outlet, createRootRoute, @@ -243,9 +194,9 @@ function RootComponent() { Now that we have the basic templating setup, we can write our first route. This is done by creating a new file in the `app/routes` directory. ```tsx -// app/routes/index.tsx +// src/routes/index.tsx import * as fs from 'node:fs' -import { createFileRoute, useRouter } from '@tanstack/solid-router' +import { useRouter } from '@tanstack/solid-router' import { createServerFn } from '@tanstack/solid-start' const filePath = 'count.txt' @@ -269,7 +220,7 @@ const updateCount = createServerFn({ method: 'POST' }) await fs.promises.writeFile(filePath, `${count + data}`) }) -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, loader: async () => await getCount(), }) diff --git a/docs/start/framework/solid/hosting.md b/docs/start/framework/solid/hosting.md index 0acb872b8b..0a1586223e 100644 --- a/docs/start/framework/solid/hosting.md +++ b/docs/start/framework/solid/hosting.md @@ -15,9 +15,9 @@ However, since hosting is one of the most crucial aspects of your application's - - - Netlify logo + + + Netlify logo diff --git a/docs/start/framework/solid/learn-the-basics.md b/docs/start/framework/solid/learn-the-basics.md index 094b965623..a7a7d2c545 100644 --- a/docs/start/framework/solid/learn-the-basics.md +++ b/docs/start/framework/solid/learn-the-basics.md @@ -7,13 +7,10 @@ This guide will help you learn the basics behind how TanStack Start works, regar ## Dependencies -TanStack Start is (currently\*) powered by [Vinxi](https://vinxi.vercel.app/), [Nitro](https://nitro.unjs.io/) and [TanStack Router](https://tanstack.com/router). +TanStack Start is powered by [Vite](https://vite.dev/) and [TanStack Router](https://tanstack.com/router). - **TanStack Router**: A router for building web applications. -- **Nitro**: A framework for building server applications. -- **Vinxi**: A server framework for building web applications. - -> [!NOTE] Vinxi will be removed before version 1.0.0 is released and TanStack will rely only on Vite and Nitro. The commands and APIs that use Vinxi will likely be replaced with a Vite plugin. +- **Vite**: A build tool for bundling your application. ## It all "Starts" with the Router @@ -47,41 +44,41 @@ declare module '@tanstack/solid-router' { The `routeTree.gen.ts` file is generated when you run TanStack Start (via `npm run dev` or `npm run start`) for the first time. This file contains the generated route tree and a handful of TS utilities that make TanStack Start fully type-safe. -## The Server Entry Point +## The Server Entry Point (Optional) -Although TanStack Start is designed with client-first APIs, it is by and large, a full-stack framework. This means that all use cases, including both dynamic and static rely on a server or build-time entry to render our application's initial HTML payload. +> [!NOTE] +> The server entry point is **optional** out of the box. If not provided, TanStack Start will automatically handle the server entry point for you using the below as a default. -This is done via the `app/ssr.tsx` file: +This is done via the `src/server.ts` file: ```tsx -// app/ssr.tsx +// src/server.ts import { createStartHandler, defaultStreamHandler, } from '@tanstack/solid-start/server' -import { getRouterManifest } from '@tanstack/solid-start/router-manifest' import { createRouter } from './router' export default createStartHandler({ createRouter, - getRouterManifest, })(defaultStreamHandler) ``` -Whether we are statically generating our app or serving it dynamically, the `ssr.tsx` file is the entry point for doing all SSR-related work. +Whether we are statically generating our app or serving it dynamically, the `server.ts` file is the entry point for doing all SSR-related work. - It's important that a new router is created for each request. This ensures that any data handled by the router is unique to the request. -- The `getRouterManifest` function is used to generate the router manifest, which is used to determine many aspects of asset management and preloading for our application. - The `defaultStreamHandler` function is used to render our application to a stream, allowing us to take advantage of streaming HTML to the client. (This is the default handler, but you can also use other handlers like `defaultRenderHandler`, or even build your own) -## The Client Entry Point +## The Client Entry Point (Optional) + +> [!NOTE] +> The client entry point is **optional** out of the box. If not provided, TanStack Start will automatically handle the client entry point for you using the below as a default. Getting our html to the client is only half the battle. Once there, we need to hydrate our client-side JavaScript once the route resolves to the client. We do this by hydrating the root of our application with the `StartClient` component: ```tsx // app/client.tsx -/// import { hydrate } from 'solid-js/web' import { StartClient } from '@tanstack/solid-start' import { createRouter } from './router' @@ -95,7 +92,7 @@ This enables us to kick off client-side routing once the user's initial server r ## The Root of Your Application -Other than the client entry point, the `__root` route of your application is the entry point for your application. The code in this file will wrap all other routes in the app, including your home page. It behaves like a pathless layout route for your whole application. +Other than the client entry point (which is optional by default), the `__root` route of your application is the entry point for your application. The code in this file will wrap all other routes in the app, including your home page. It behaves like a pathless layout route for your whole application. Because it is **always rendered**, it is the perfect place to construct your application shell and take care of any global logic. diff --git a/docs/start/framework/solid/server-routes.md b/docs/start/framework/solid/server-routes.md new file mode 100644 index 0000000000..9fe19933d0 --- /dev/null +++ b/docs/start/framework/solid/server-routes.md @@ -0,0 +1,4 @@ +--- +ref: docs/start/framework/react/server-routes.md +replace: { 'react': 'solid' } +--- diff --git a/docs/start/framework/solid/spa-mode.md b/docs/start/framework/solid/spa-mode.md new file mode 100644 index 0000000000..0124b857d2 --- /dev/null +++ b/docs/start/framework/solid/spa-mode.md @@ -0,0 +1,3 @@ +--- +ref: docs/start/framework/react/spa-mode.md +--- diff --git a/docs/start/framework/solid/ssr.md b/docs/start/framework/solid/ssr.md deleted file mode 100644 index c99a3d9280..0000000000 --- a/docs/start/framework/solid/ssr.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -ref: docs/start/framework/react/ssr.md -replace: { 'react': 'solid' } ---- diff --git a/e2e/create-start/.gitignore b/e2e/create-start/.gitignore deleted file mode 100644 index 8354e4d50d..0000000000 --- a/e2e/create-start/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -node_modules -.DS_Store -dist -dist-ssr -*.local - -/test-results/ -/playwright-report/ -/blob-report/ -/playwright/.cache/ \ No newline at end of file diff --git a/e2e/create-start/package.json b/e2e/create-start/package.json deleted file mode 100644 index 1c46410866..0000000000 --- a/e2e/create-start/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "create-start-e2e", - "private": true, - "type": "module", - "scripts": { - "test:e2e": "playwright test --project=chromium" - }, - "devDependencies": { - "@playwright/test": "^1.50.1", - "@tanstack/create-start": "workspace:^", - "get-port-please": "^3.1.2", - "tempy": "^3.1.0", - "terminate": "^2.8.0", - "wait-port": "^1.1.0" - } -} diff --git a/e2e/create-start/playwright.config.ts b/e2e/create-start/playwright.config.ts deleted file mode 100644 index b07c8b268b..0000000000 --- a/e2e/create-start/playwright.config.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { defineConfig, devices } from '@playwright/test' - -/** - * See https://playwright.dev/docs/test-configuration. - */ -export default defineConfig({ - testDir: './tests', - - reporter: [['line']], - timeout: 60000, - use: { - trace: 'on-first-retry', - }, - workers: 1, - - // use: { - // /* Base URL to use in actions like `await page.goto('/')`. */ - // baseURL: 'http://localhost:3001/', - // }, - - // webServer: { - // command: 'pnpm run dev', - // url: 'http://localhost:3001', - // reuseExistingServer: !process.env.CI, - // stdout: 'pipe', - // }, - - projects: [ - { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, - }, - ], -}) diff --git a/e2e/create-start/tests/templates/barebones.test.ts b/e2e/create-start/tests/templates/barebones.test.ts deleted file mode 100644 index 8778ef37d7..0000000000 --- a/e2e/create-start/tests/templates/barebones.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { temporaryDirectory } from 'tempy' -import { getRandomPort } from 'get-port-please' -import { unstable_scaffoldTemplate } from '@tanstack/create-start' -import { test } from '../../utils/setup' - -// Before running any tests - create the project in the temporary directory -const projectPath = temporaryDirectory() -await unstable_scaffoldTemplate({ - cfg: { - packageManager: { - installDeps: true, - packageManager: 'pnpm', - }, - git: { - setupGit: false, - }, - packageJson: { - type: 'new', - name: 'barebones-test', - }, - ide: { - ide: 'vscode', - }, - }, - targetPath: projectPath, - templateId: 'barebones', -}) - -const PORT = await getRandomPort() -test.use({ projectPath }) -test.use({ port: PORT }) -test.use({ baseURL: `http://localhost:${PORT}` }) - -test.describe('barebones template e2e', () => { - test('Navigating to index page', async ({ page }) => { - await page.goto('/') - }) -}) diff --git a/e2e/create-start/tsconfig.json b/e2e/create-start/tsconfig.json deleted file mode 100644 index 44c53edd67..0000000000 --- a/e2e/create-start/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "strict": true, - "esModuleInterop": true, - "jsx": "react-jsx", - "target": "ESNext", - "moduleResolution": "Bundler", - "module": "ESNext", - "skipLibCheck": true - } -} diff --git a/e2e/create-start/utils/setup.ts b/e2e/create-start/utils/setup.ts deleted file mode 100644 index bfb4c1fd53..0000000000 --- a/e2e/create-start/utils/setup.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { exec, execSync } from 'node:child_process' -import { test as baseTest } from '@playwright/test' -import terminate from 'terminate/promise' -import waitPort from 'wait-port' - -async function _setup( - projectPath: string, - port: number, -): Promise<{ - PID: number - ADDR: string - killProcess: () => Promise - deleteTempDir: () => void -}> { - const ADDR = `http://localhost:${port}` - - const childProcess = exec( - `VITE_SERVER_PORT=${port} pnpm vinxi dev --port ${port}`, - { - cwd: projectPath, - }, - ) - - childProcess.stdout?.on('data', (data) => { - const message = data.toString() - console.log('Stdout:', message) - }) - - childProcess.stderr?.on('data', (data) => { - console.error('Stderr:', data.toString()) - }) - - try { - await waitPort({ port, timeout: 30000 }) // Added timeout - } catch (err) { - console.error('Failed to start server:', err) - throw err - } - - const PID = childProcess.pid! - const killProcess = async () => { - console.log('Killing process') - try { - await terminate(PID) - } catch (err) { - console.error('Failed to kill process:', err) - } - } - const deleteTempDir = () => execSync(`rm -rf ${projectPath}`) - - return { PID, ADDR, killProcess, deleteTempDir } -} - -type SetupApp = Awaited> - -export const test = baseTest.extend<{ - setupApp: SetupApp - projectPath: string - port: number - ensureServer: void -}>({ - projectPath: ['', { option: true }], - port: [0, { option: true }], - ensureServer: [ - async ({ projectPath, port }, use) => { - const setup = await _setup(projectPath, port) - await use() - await setup.killProcess() - }, - { auto: true }, - ], -}) diff --git a/e2e/react-router/basic-esbuild-file-based/src/esbuild.config.js b/e2e/react-router/basic-esbuild-file-based/src/esbuild.config.js index 9deed8a53d..5f0f4fce03 100644 --- a/e2e/react-router/basic-esbuild-file-based/src/esbuild.config.js +++ b/e2e/react-router/basic-esbuild-file-based/src/esbuild.config.js @@ -1,9 +1,9 @@ -import { TanStackRouterEsbuild } from '@tanstack/router-plugin/esbuild' +import { tanstackRouter } from '@tanstack/router-plugin/esbuild' export default { // ... plugins: [ - TanStackRouterEsbuild({ + tanstackRouter({ autoCodeSplitting: true, }), ], diff --git a/e2e/react-router/basic-file-based-code-splitting/package.json b/e2e/react-router/basic-file-based-code-splitting/package.json index d3cd1e2425..38efb81ef7 100644 --- a/e2e/react-router/basic-file-based-code-splitting/package.json +++ b/e2e/react-router/basic-file-based-code-splitting/package.json @@ -27,6 +27,6 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/react-router/basic-file-based-code-splitting/src/routeTree.gen.ts b/e2e/react-router/basic-file-based-code-splitting/src/routeTree.gen.ts index 12e3efedb5..4ff69b1e7d 100644 --- a/e2e/react-router/basic-file-based-code-splitting/src/routeTree.gen.ts +++ b/e2e/react-router/basic-file-based-code-splitting/src/routeTree.gen.ts @@ -8,75 +8,77 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as WithoutLoaderImport } from './routes/without-loader' -import { Route as ViewportTestImport } from './routes/viewport-test' -import { Route as PostsImport } from './routes/posts' -import { Route as LayoutImport } from './routes/_layout' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as LayoutLayout2Import } from './routes/_layout/_layout-2' -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 WithoutLoaderRouteImport } from './routes/without-loader' +import { Route as ViewportTestRouteImport } from './routes/viewport-test' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as LayoutRouteImport } from './routes/_layout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2' +import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b' +import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' // Create/Update Routes -const WithoutLoaderRoute = WithoutLoaderImport.update({ +const WithoutLoaderRoute = WithoutLoaderRouteImport.update({ id: '/without-loader', path: '/without-loader', getParentRoute: () => rootRoute, } as any) -const ViewportTestRoute = ViewportTestImport.update({ +const ViewportTestRoute = ViewportTestRouteImport.update({ id: '/viewport-test', path: '/viewport-test', getParentRoute: () => rootRoute, } as any) -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const LayoutRoute = LayoutImport.update({ +const LayoutRoute = LayoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const LayoutLayout2Route = LayoutLayout2Import.update({ +const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) -const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBImport.update({ +const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => LayoutLayout2Route, } as any) -const LayoutLayout2LayoutARoute = LayoutLayout2LayoutAImport.update({ +const LayoutLayout2LayoutARoute = LayoutLayout2LayoutARouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => LayoutLayout2Route, @@ -90,75 +92,168 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/viewport-test': { id: '/viewport-test' path: '/viewport-test' fullPath: '/viewport-test' - preLoaderRoute: typeof ViewportTestImport + preLoaderRoute: typeof ViewportTestRouteImport parentRoute: typeof rootRoute } '/without-loader': { id: '/without-loader' path: '/without-loader' fullPath: '/without-loader' - preLoaderRoute: typeof WithoutLoaderImport + preLoaderRoute: typeof WithoutLoaderRouteImport parentRoute: typeof rootRoute } '/_layout/_layout-2': { id: '/_layout/_layout-2' path: '' fullPath: '' - preLoaderRoute: typeof LayoutLayout2Import - parentRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutLayout2RouteImport + parentRoute: typeof LayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/_layout/_layout-2/layout-a': { id: '/_layout/_layout-2/layout-a' path: '/layout-a' fullPath: '/layout-a' - preLoaderRoute: typeof LayoutLayout2LayoutAImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutARouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/_layout/_layout-2/layout-b': { id: '/_layout/_layout-2/layout-b' path: '/layout-b' fullPath: '/layout-b' - preLoaderRoute: typeof LayoutLayout2LayoutBImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutBRouteImport + parentRoute: typeof LayoutLayout2RouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_layout' { + const createFileRoute: CreateFileRoute< + '/_layout', + FileRoutesByPath['/_layout']['parentRoute'], + FileRoutesByPath['/_layout']['id'], + FileRoutesByPath['/_layout']['path'], + FileRoutesByPath['/_layout']['fullPath'] + > +} +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/viewport-test' { + const createFileRoute: CreateFileRoute< + '/viewport-test', + FileRoutesByPath['/viewport-test']['parentRoute'], + FileRoutesByPath['/viewport-test']['id'], + FileRoutesByPath['/viewport-test']['path'], + FileRoutesByPath['/viewport-test']['fullPath'] + > +} +declare module './routes/without-loader' { + const createFileRoute: CreateFileRoute< + '/without-loader', + FileRoutesByPath['/without-loader']['parentRoute'], + FileRoutesByPath['/without-loader']['id'], + FileRoutesByPath['/without-loader']['path'], + FileRoutesByPath['/without-loader']['fullPath'] + > +} +declare module './routes/_layout/_layout-2' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2', + FileRoutesByPath['/_layout/_layout-2']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2']['id'], + FileRoutesByPath['/_layout/_layout-2']['path'], + FileRoutesByPath['/_layout/_layout-2']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-a' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-a', + FileRoutesByPath['/_layout/_layout-2/layout-a']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-b' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-b', + FileRoutesByPath['/_layout/_layout-2/layout-b']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['fullPath'] + > +} + // Create and export the route tree interface LayoutLayout2RouteChildren { diff --git a/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout.tsx b/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout.tsx index 02ddbb1cd9..5c4a461d8d 100644 --- a/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout.tsx +++ b/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2.tsx b/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2.tsx index 3b7dbf2903..483b910862 100644 --- a/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2.tsx +++ b/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout/_layout-2')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-a.tsx b/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-a.tsx index 61e19b4d9f..a190b24202 100644 --- a/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-a.tsx +++ b/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-a.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ +export const Route = createFileRoute({ component: LayoutAComponent, }) diff --git a/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-b.tsx b/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-b.tsx index cceed1fb9a..505f8f6fbf 100644 --- a/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-b.tsx +++ b/e2e/react-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-b.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ +export const Route = createFileRoute({ component: LayoutBComponent, }) diff --git a/e2e/react-router/basic-file-based-code-splitting/src/routes/index.tsx b/e2e/react-router/basic-file-based-code-splitting/src/routes/index.tsx index eac82a9174..b23956ae17 100644 --- a/e2e/react-router/basic-file-based-code-splitting/src/routes/index.tsx +++ b/e2e/react-router/basic-file-based-code-splitting/src/routes/index.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/react-router/basic-file-based-code-splitting/src/routes/posts.$postId.tsx b/e2e/react-router/basic-file-based-code-splitting/src/routes/posts.$postId.tsx index 47d1148be2..805fa37ed3 100644 --- a/e2e/react-router/basic-file-based-code-splitting/src/routes/posts.$postId.tsx +++ b/e2e/react-router/basic-file-based-code-splitting/src/routes/posts.$postId.tsx @@ -1,9 +1,9 @@ import * as React from 'react' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import { fetchPost } from '../posts' import type { ErrorComponentProps } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost(postId), errorComponent: PostErrorComponent as any, notFoundComponent: () => { diff --git a/e2e/react-router/basic-file-based-code-splitting/src/routes/posts.index.tsx b/e2e/react-router/basic-file-based-code-splitting/src/routes/posts.index.tsx index 056433ca0a..fdbe5865e5 100644 --- a/e2e/react-router/basic-file-based-code-splitting/src/routes/posts.index.tsx +++ b/e2e/react-router/basic-file-based-code-splitting/src/routes/posts.index.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/e2e/react-router/basic-file-based-code-splitting/src/routes/posts.tsx b/e2e/react-router/basic-file-based-code-splitting/src/routes/posts.tsx index c7a09ed7f8..4469b2216a 100644 --- a/e2e/react-router/basic-file-based-code-splitting/src/routes/posts.tsx +++ b/e2e/react-router/basic-file-based-code-splitting/src/routes/posts.tsx @@ -1,8 +1,8 @@ import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: fetchPosts, component: PostsComponent, }) diff --git a/e2e/react-router/basic-file-based-code-splitting/src/routes/viewport-test.tsx b/e2e/react-router/basic-file-based-code-splitting/src/routes/viewport-test.tsx index d60bf062d3..b182feb7b1 100644 --- a/e2e/react-router/basic-file-based-code-splitting/src/routes/viewport-test.tsx +++ b/e2e/react-router/basic-file-based-code-splitting/src/routes/viewport-test.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/viewport-test')({ +export const Route = createFileRoute({ component: () =>
Hello /viewport-test!
, }) diff --git a/e2e/react-router/basic-file-based-code-splitting/src/routes/without-loader.tsx b/e2e/react-router/basic-file-based-code-splitting/src/routes/without-loader.tsx index 9dddcfe5f4..af692bdaca 100644 --- a/e2e/react-router/basic-file-based-code-splitting/src/routes/without-loader.tsx +++ b/e2e/react-router/basic-file-based-code-splitting/src/routes/without-loader.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/without-loader')({ +export const Route = createFileRoute({ component: () =>
Hello /without-loader!
, }) diff --git a/e2e/react-router/basic-file-based-code-splitting/vite.config.ts b/e2e/react-router/basic-file-based-code-splitting/vite.config.ts index 3b36b81fe1..dfe060a574 100644 --- a/e2e/react-router/basic-file-based-code-splitting/vite.config.ts +++ b/e2e/react-router/basic-file-based-code-splitting/vite.config.ts @@ -1,13 +1,14 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'react', autoCodeSplitting: true, + verboseFileRoutes: false, codeSplittingOptions: { splitBehavior: ({ routeId }) => { if (routeId === '/posts') { diff --git a/e2e/react-router/basic-file-based/package.json b/e2e/react-router/basic-file-based/package.json index 33c69421d1..8d61ceed9a 100644 --- a/e2e/react-router/basic-file-based/package.json +++ b/e2e/react-router/basic-file-based/package.json @@ -30,6 +30,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "combinate": "^1.1.11", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/react-router/basic-file-based/src/routeTree.gen.ts b/e2e/react-router/basic-file-based/src/routeTree.gen.ts index 0cc7397492..ace129c465 100644 --- a/e2e/react-router/basic-file-based/src/routeTree.gen.ts +++ b/e2e/react-router/basic-file-based/src/routeTree.gen.ts @@ -13,117 +13,133 @@ import { createFileRoute } from '@tanstack/react-router' // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PostsImport } from './routes/posts' -import { Route as EditingBImport } from './routes/editing-b' -import { Route as EditingAImport } from './routes/editing-a' -import { Route as AnchorImport } from './routes/anchor' -import { Route as LayoutImport } from './routes/_layout' -import { Route as IndexImport } from './routes/index' -import { Route as RedirectIndexImport } from './routes/redirect/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as StructuralSharingEnabledImport } from './routes/structural-sharing.$enabled' -import { Route as RedirectTargetImport } from './routes/redirect/$target' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as LayoutLayout2Import } from './routes/_layout/_layout-2' -import { Route as groupLazyinsideImport } from './routes/(group)/lazyinside' -import { Route as groupInsideImport } from './routes/(group)/inside' -import { Route as groupLayoutImport } from './routes/(group)/_layout' -import { Route as anotherGroupOnlyrouteinsideImport } from './routes/(another-group)/onlyrouteinside' -import { Route as RedirectTargetIndexImport } from './routes/redirect/$target/index' -import { Route as RedirectPreloadThirdImport } from './routes/redirect/preload/third' -import { Route as RedirectPreloadSecondImport } from './routes/redirect/preload/second' -import { Route as RedirectPreloadFirstImport } from './routes/redirect/preload/first' -import { Route as RedirectTargetViaLoaderImport } from './routes/redirect/$target/via-loader' -import { Route as RedirectTargetViaBeforeLoadImport } from './routes/redirect/$target/via-beforeLoad' -import { Route as PostsPostIdEditImport } from './routes/posts_.$postId.edit' -import { Route as ParamsSingleValueImport } from './routes/params.single.$value' -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 groupSubfolderInsideImport } from './routes/(group)/subfolder/inside' -import { Route as groupLayoutInsidelayoutImport } from './routes/(group)/_layout.insidelayout' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as EditingBRouteImport } from './routes/editing-b' +import { Route as EditingARouteImport } from './routes/editing-a' +import { Route as AnchorRouteImport } from './routes/anchor' +import { Route as LayoutRouteImport } from './routes/_layout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as RedirectIndexRouteImport } from './routes/redirect/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as ParamsPsIndexRouteImport } from './routes/params-ps/index' +import { Route as StructuralSharingEnabledRouteImport } from './routes/structural-sharing.$enabled' +import { Route as RedirectTargetRouteImport } from './routes/redirect/$target' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2' +import { Route as groupLazyinsideRouteImport } from './routes/(group)/lazyinside' +import { Route as groupInsideRouteImport } from './routes/(group)/inside' +import { Route as groupLayoutRouteImport } from './routes/(group)/_layout' +import { Route as anotherGroupOnlyrouteinsideRouteImport } from './routes/(another-group)/onlyrouteinside' +import { Route as RedirectTargetIndexRouteImport } from './routes/redirect/$target/index' +import { Route as ParamsPsWildcardIndexRouteImport } from './routes/params-ps/wildcard/index' +import { Route as ParamsPsNamedIndexRouteImport } from './routes/params-ps/named/index' +import { Route as RedirectPreloadThirdRouteImport } from './routes/redirect/preload/third' +import { Route as RedirectPreloadSecondRouteImport } from './routes/redirect/preload/second' +import { Route as RedirectPreloadFirstRouteImport } from './routes/redirect/preload/first' +import { Route as RedirectTargetViaLoaderRouteImport } from './routes/redirect/$target/via-loader' +import { Route as RedirectTargetViaBeforeLoadRouteImport } from './routes/redirect/$target/via-beforeLoad' +import { Route as PostsPostIdEditRouteImport } from './routes/posts_.$postId.edit' +import { Route as ParamsSingleValueRouteImport } from './routes/params.single.$value' +import { Route as ParamsPsWildcardChar123Char125suffixRouteImport } from './routes/params-ps/wildcard/{$}suffix' +import { Route as ParamsPsWildcardPrefixChar123Char125RouteImport } from './routes/params-ps/wildcard/prefix{$}' +import { Route as ParamsPsWildcardSplatRouteImport } from './routes/params-ps/wildcard/$' +import { Route as ParamsPsNamedChar123fooChar125suffixRouteImport } from './routes/params-ps/named/{$foo}suffix' +import { Route as ParamsPsNamedPrefixChar123fooChar125RouteImport } from './routes/params-ps/named/prefix{$foo}' +import { Route as ParamsPsNamedFooRouteImport } from './routes/params-ps/named/$foo' +import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b' +import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' +import { Route as groupSubfolderInsideRouteImport } from './routes/(group)/subfolder/inside' +import { Route as groupLayoutInsidelayoutRouteImport } from './routes/(group)/_layout.insidelayout' // Create Virtual Routes -const groupImport = createFileRoute('/(group)')() +const groupRouteImport = createFileRoute('/(group)')() // Create/Update Routes -const groupRoute = groupImport.update({ +const groupRoute = groupRouteImport.update({ id: '/(group)', getParentRoute: () => rootRoute, } as any) -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const EditingBRoute = EditingBImport.update({ +const EditingBRoute = EditingBRouteImport.update({ id: '/editing-b', path: '/editing-b', getParentRoute: () => rootRoute, } as any) -const EditingARoute = EditingAImport.update({ +const EditingARoute = EditingARouteImport.update({ id: '/editing-a', path: '/editing-a', getParentRoute: () => rootRoute, } as any) -const AnchorRoute = AnchorImport.update({ +const AnchorRoute = AnchorRouteImport.update({ id: '/anchor', path: '/anchor', getParentRoute: () => rootRoute, } as any) -const LayoutRoute = LayoutImport.update({ +const LayoutRoute = LayoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const RedirectIndexRoute = RedirectIndexImport.update({ +const RedirectIndexRoute = RedirectIndexRouteImport.update({ id: '/redirect/', path: '/redirect/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const StructuralSharingEnabledRoute = StructuralSharingEnabledImport.update({ - id: '/structural-sharing/$enabled', - path: '/structural-sharing/$enabled', +const ParamsPsIndexRoute = ParamsPsIndexRouteImport.update({ + id: '/params-ps/', + path: '/params-ps/', getParentRoute: () => rootRoute, } as any) -const RedirectTargetRoute = RedirectTargetImport.update({ +const StructuralSharingEnabledRoute = + StructuralSharingEnabledRouteImport.update({ + id: '/structural-sharing/$enabled', + path: '/structural-sharing/$enabled', + getParentRoute: () => rootRoute, + } as any) + +const RedirectTargetRoute = RedirectTargetRouteImport.update({ id: '/redirect/$target', path: '/redirect/$target', getParentRoute: () => rootRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const LayoutLayout2Route = LayoutLayout2Import.update({ +const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) -const groupLazyinsideRoute = groupLazyinsideImport +const groupLazyinsideRoute = groupLazyinsideRouteImport .update({ id: '/lazyinside', path: '/lazyinside', @@ -131,92 +147,144 @@ const groupLazyinsideRoute = groupLazyinsideImport } as any) .lazy(() => import('./routes/(group)/lazyinside.lazy').then((d) => d.Route)) -const groupInsideRoute = groupInsideImport.update({ +const groupInsideRoute = groupInsideRouteImport.update({ id: '/inside', path: '/inside', getParentRoute: () => groupRoute, } as any) -const groupLayoutRoute = groupLayoutImport.update({ +const groupLayoutRoute = groupLayoutRouteImport.update({ id: '/_layout', getParentRoute: () => groupRoute, } as any) const anotherGroupOnlyrouteinsideRoute = - anotherGroupOnlyrouteinsideImport.update({ + anotherGroupOnlyrouteinsideRouteImport.update({ id: '/(another-group)/onlyrouteinside', path: '/onlyrouteinside', getParentRoute: () => rootRoute, } as any) -const RedirectTargetIndexRoute = RedirectTargetIndexImport.update({ +const RedirectTargetIndexRoute = RedirectTargetIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => RedirectTargetRoute, } as any) -const RedirectPreloadThirdRoute = RedirectPreloadThirdImport.update({ +const ParamsPsWildcardIndexRoute = ParamsPsWildcardIndexRouteImport.update({ + id: '/params-ps/wildcard/', + path: '/params-ps/wildcard/', + getParentRoute: () => rootRoute, +} as any) + +const ParamsPsNamedIndexRoute = ParamsPsNamedIndexRouteImport.update({ + id: '/params-ps/named/', + path: '/params-ps/named/', + getParentRoute: () => rootRoute, +} as any) + +const RedirectPreloadThirdRoute = RedirectPreloadThirdRouteImport.update({ id: '/redirect/preload/third', path: '/redirect/preload/third', getParentRoute: () => rootRoute, } as any) -const RedirectPreloadSecondRoute = RedirectPreloadSecondImport.update({ +const RedirectPreloadSecondRoute = RedirectPreloadSecondRouteImport.update({ id: '/redirect/preload/second', path: '/redirect/preload/second', getParentRoute: () => rootRoute, } as any) -const RedirectPreloadFirstRoute = RedirectPreloadFirstImport.update({ +const RedirectPreloadFirstRoute = RedirectPreloadFirstRouteImport.update({ id: '/redirect/preload/first', path: '/redirect/preload/first', getParentRoute: () => rootRoute, } as any) -const RedirectTargetViaLoaderRoute = RedirectTargetViaLoaderImport.update({ +const RedirectTargetViaLoaderRoute = RedirectTargetViaLoaderRouteImport.update({ id: '/via-loader', path: '/via-loader', getParentRoute: () => RedirectTargetRoute, } as any) const RedirectTargetViaBeforeLoadRoute = - RedirectTargetViaBeforeLoadImport.update({ + RedirectTargetViaBeforeLoadRouteImport.update({ id: '/via-beforeLoad', path: '/via-beforeLoad', getParentRoute: () => RedirectTargetRoute, } as any) -const PostsPostIdEditRoute = PostsPostIdEditImport.update({ +const PostsPostIdEditRoute = PostsPostIdEditRouteImport.update({ id: '/posts_/$postId/edit', path: '/posts/$postId/edit', getParentRoute: () => rootRoute, } as any) -const ParamsSingleValueRoute = ParamsSingleValueImport.update({ +const ParamsSingleValueRoute = ParamsSingleValueRouteImport.update({ id: '/params/single/$value', path: '/params/single/$value', getParentRoute: () => rootRoute, } as any) -const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBImport.update({ +const ParamsPsWildcardChar123Char125suffixRoute = + ParamsPsWildcardChar123Char125suffixRouteImport.update({ + id: '/params-ps/wildcard/{$}suffix', + path: '/params-ps/wildcard/{$}suffix', + getParentRoute: () => rootRoute, + } as any) + +const ParamsPsWildcardPrefixChar123Char125Route = + ParamsPsWildcardPrefixChar123Char125RouteImport.update({ + id: '/params-ps/wildcard/prefix{$}', + path: '/params-ps/wildcard/prefix{$}', + getParentRoute: () => rootRoute, + } as any) + +const ParamsPsWildcardSplatRoute = ParamsPsWildcardSplatRouteImport.update({ + id: '/params-ps/wildcard/$', + path: '/params-ps/wildcard/$', + getParentRoute: () => rootRoute, +} as any) + +const ParamsPsNamedChar123fooChar125suffixRoute = + ParamsPsNamedChar123fooChar125suffixRouteImport.update({ + id: '/params-ps/named/{$foo}suffix', + path: '/params-ps/named/{$foo}suffix', + getParentRoute: () => rootRoute, + } as any) + +const ParamsPsNamedPrefixChar123fooChar125Route = + ParamsPsNamedPrefixChar123fooChar125RouteImport.update({ + id: '/params-ps/named/prefix{$foo}', + path: '/params-ps/named/prefix{$foo}', + getParentRoute: () => rootRoute, + } as any) + +const ParamsPsNamedFooRoute = ParamsPsNamedFooRouteImport.update({ + id: '/params-ps/named/$foo', + path: '/params-ps/named/$foo', + getParentRoute: () => rootRoute, +} as any) + +const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => LayoutLayout2Route, } as any) -const LayoutLayout2LayoutARoute = LayoutLayout2LayoutAImport.update({ +const LayoutLayout2LayoutARoute = LayoutLayout2LayoutARouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => LayoutLayout2Route, } as any) -const groupSubfolderInsideRoute = groupSubfolderInsideImport.update({ +const groupSubfolderInsideRoute = groupSubfolderInsideRouteImport.update({ id: '/subfolder/inside', path: '/subfolder/inside', getParentRoute: () => groupRoute, } as any) -const groupLayoutInsidelayoutRoute = groupLayoutInsidelayoutImport.update({ +const groupLayoutInsidelayoutRoute = groupLayoutInsidelayoutRouteImport.update({ id: '/insidelayout', path: '/insidelayout', getParentRoute: () => groupLayoutRoute, @@ -230,204 +298,267 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutRouteImport parentRoute: typeof rootRoute } '/anchor': { id: '/anchor' path: '/anchor' fullPath: '/anchor' - preLoaderRoute: typeof AnchorImport + preLoaderRoute: typeof AnchorRouteImport parentRoute: typeof rootRoute } '/editing-a': { id: '/editing-a' path: '/editing-a' fullPath: '/editing-a' - preLoaderRoute: typeof EditingAImport + preLoaderRoute: typeof EditingARouteImport parentRoute: typeof rootRoute } '/editing-b': { id: '/editing-b' path: '/editing-b' fullPath: '/editing-b' - preLoaderRoute: typeof EditingBImport + preLoaderRoute: typeof EditingBRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/(another-group)/onlyrouteinside': { id: '/(another-group)/onlyrouteinside' path: '/onlyrouteinside' fullPath: '/onlyrouteinside' - preLoaderRoute: typeof anotherGroupOnlyrouteinsideImport + preLoaderRoute: typeof anotherGroupOnlyrouteinsideRouteImport parentRoute: typeof rootRoute } '/(group)': { id: '/(group)' path: '/' fullPath: '/' - preLoaderRoute: typeof groupImport + preLoaderRoute: typeof groupRouteImport parentRoute: typeof rootRoute } '/(group)/_layout': { id: '/(group)/_layout' path: '/' fullPath: '/' - preLoaderRoute: typeof groupLayoutImport + preLoaderRoute: typeof groupLayoutRouteImport parentRoute: typeof groupRoute } '/(group)/inside': { id: '/(group)/inside' path: '/inside' fullPath: '/inside' - preLoaderRoute: typeof groupInsideImport - parentRoute: typeof groupImport + preLoaderRoute: typeof groupInsideRouteImport + parentRoute: typeof groupRouteImport } '/(group)/lazyinside': { id: '/(group)/lazyinside' path: '/lazyinside' fullPath: '/lazyinside' - preLoaderRoute: typeof groupLazyinsideImport - parentRoute: typeof groupImport + preLoaderRoute: typeof groupLazyinsideRouteImport + parentRoute: typeof groupRouteImport } '/_layout/_layout-2': { id: '/_layout/_layout-2' path: '' fullPath: '' - preLoaderRoute: typeof LayoutLayout2Import - parentRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutLayout2RouteImport + parentRoute: typeof LayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/redirect/$target': { id: '/redirect/$target' path: '/redirect/$target' fullPath: '/redirect/$target' - preLoaderRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetRouteImport parentRoute: typeof rootRoute } '/structural-sharing/$enabled': { id: '/structural-sharing/$enabled' path: '/structural-sharing/$enabled' fullPath: '/structural-sharing/$enabled' - preLoaderRoute: typeof StructuralSharingEnabledImport + preLoaderRoute: typeof StructuralSharingEnabledRouteImport + parentRoute: typeof rootRoute + } + '/params-ps/': { + id: '/params-ps/' + path: '/params-ps' + fullPath: '/params-ps' + preLoaderRoute: typeof ParamsPsIndexRouteImport parentRoute: typeof rootRoute } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/redirect/': { id: '/redirect/' path: '/redirect' fullPath: '/redirect' - preLoaderRoute: typeof RedirectIndexImport + preLoaderRoute: typeof RedirectIndexRouteImport parentRoute: typeof rootRoute } '/(group)/_layout/insidelayout': { id: '/(group)/_layout/insidelayout' path: '/insidelayout' fullPath: '/insidelayout' - preLoaderRoute: typeof groupLayoutInsidelayoutImport - parentRoute: typeof groupLayoutImport + preLoaderRoute: typeof groupLayoutInsidelayoutRouteImport + parentRoute: typeof groupLayoutRouteImport } '/(group)/subfolder/inside': { id: '/(group)/subfolder/inside' path: '/subfolder/inside' fullPath: '/subfolder/inside' - preLoaderRoute: typeof groupSubfolderInsideImport - parentRoute: typeof groupImport + preLoaderRoute: typeof groupSubfolderInsideRouteImport + parentRoute: typeof groupRouteImport } '/_layout/_layout-2/layout-a': { id: '/_layout/_layout-2/layout-a' path: '/layout-a' fullPath: '/layout-a' - preLoaderRoute: typeof LayoutLayout2LayoutAImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutARouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/_layout/_layout-2/layout-b': { id: '/_layout/_layout-2/layout-b' path: '/layout-b' fullPath: '/layout-b' - preLoaderRoute: typeof LayoutLayout2LayoutBImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutBRouteImport + parentRoute: typeof LayoutLayout2RouteImport + } + '/params-ps/named/$foo': { + id: '/params-ps/named/$foo' + path: '/params-ps/named/$foo' + fullPath: '/params-ps/named/$foo' + preLoaderRoute: typeof ParamsPsNamedFooRouteImport + parentRoute: typeof rootRoute + } + '/params-ps/named/prefix{$foo}': { + id: '/params-ps/named/prefix{$foo}' + path: '/params-ps/named/prefix{$foo}' + fullPath: '/params-ps/named/prefix{$foo}' + preLoaderRoute: typeof ParamsPsNamedPrefixChar123fooChar125RouteImport + parentRoute: typeof rootRoute + } + '/params-ps/named/{$foo}suffix': { + id: '/params-ps/named/{$foo}suffix' + path: '/params-ps/named/{$foo}suffix' + fullPath: '/params-ps/named/{$foo}suffix' + preLoaderRoute: typeof ParamsPsNamedChar123fooChar125suffixRouteImport + parentRoute: typeof rootRoute + } + '/params-ps/wildcard/$': { + id: '/params-ps/wildcard/$' + path: '/params-ps/wildcard/$' + fullPath: '/params-ps/wildcard/$' + preLoaderRoute: typeof ParamsPsWildcardSplatRouteImport + parentRoute: typeof rootRoute + } + '/params-ps/wildcard/prefix{$}': { + id: '/params-ps/wildcard/prefix{$}' + path: '/params-ps/wildcard/prefix{$}' + fullPath: '/params-ps/wildcard/prefix{$}' + preLoaderRoute: typeof ParamsPsWildcardPrefixChar123Char125RouteImport + parentRoute: typeof rootRoute + } + '/params-ps/wildcard/{$}suffix': { + id: '/params-ps/wildcard/{$}suffix' + path: '/params-ps/wildcard/{$}suffix' + fullPath: '/params-ps/wildcard/{$}suffix' + preLoaderRoute: typeof ParamsPsWildcardChar123Char125suffixRouteImport + parentRoute: typeof rootRoute } '/params/single/$value': { id: '/params/single/$value' path: '/params/single/$value' fullPath: '/params/single/$value' - preLoaderRoute: typeof ParamsSingleValueImport + preLoaderRoute: typeof ParamsSingleValueRouteImport parentRoute: typeof rootRoute } '/posts_/$postId/edit': { id: '/posts_/$postId/edit' path: '/posts/$postId/edit' fullPath: '/posts/$postId/edit' - preLoaderRoute: typeof PostsPostIdEditImport + preLoaderRoute: typeof PostsPostIdEditRouteImport parentRoute: typeof rootRoute } '/redirect/$target/via-beforeLoad': { id: '/redirect/$target/via-beforeLoad' path: '/via-beforeLoad' fullPath: '/redirect/$target/via-beforeLoad' - preLoaderRoute: typeof RedirectTargetViaBeforeLoadImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetViaBeforeLoadRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/via-loader': { id: '/redirect/$target/via-loader' path: '/via-loader' fullPath: '/redirect/$target/via-loader' - preLoaderRoute: typeof RedirectTargetViaLoaderImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetViaLoaderRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/preload/first': { id: '/redirect/preload/first' path: '/redirect/preload/first' fullPath: '/redirect/preload/first' - preLoaderRoute: typeof RedirectPreloadFirstImport + preLoaderRoute: typeof RedirectPreloadFirstRouteImport parentRoute: typeof rootRoute } '/redirect/preload/second': { id: '/redirect/preload/second' path: '/redirect/preload/second' fullPath: '/redirect/preload/second' - preLoaderRoute: typeof RedirectPreloadSecondImport + preLoaderRoute: typeof RedirectPreloadSecondRouteImport parentRoute: typeof rootRoute } '/redirect/preload/third': { id: '/redirect/preload/third' path: '/redirect/preload/third' fullPath: '/redirect/preload/third' - preLoaderRoute: typeof RedirectPreloadThirdImport + preLoaderRoute: typeof RedirectPreloadThirdRouteImport + parentRoute: typeof rootRoute + } + '/params-ps/named/': { + id: '/params-ps/named/' + path: '/params-ps/named' + fullPath: '/params-ps/named' + preLoaderRoute: typeof ParamsPsNamedIndexRouteImport + parentRoute: typeof rootRoute + } + '/params-ps/wildcard/': { + id: '/params-ps/wildcard/' + path: '/params-ps/wildcard' + fullPath: '/params-ps/wildcard' + preLoaderRoute: typeof ParamsPsWildcardIndexRouteImport parentRoute: typeof rootRoute } '/redirect/$target/': { id: '/redirect/$target/' path: '/' fullPath: '/redirect/$target/' - preLoaderRoute: typeof RedirectTargetIndexImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetIndexRouteImport + parentRoute: typeof RedirectTargetRouteImport } } } @@ -528,12 +659,19 @@ export interface FileRoutesByFullPath { '/posts/$postId': typeof PostsPostIdRoute '/redirect/$target': typeof RedirectTargetRouteWithChildren '/structural-sharing/$enabled': typeof StructuralSharingEnabledRoute + '/params-ps': typeof ParamsPsIndexRoute '/posts/': typeof PostsIndexRoute '/redirect': typeof RedirectIndexRoute '/insidelayout': typeof groupLayoutInsidelayoutRoute '/subfolder/inside': typeof groupSubfolderInsideRoute '/layout-a': typeof LayoutLayout2LayoutARoute '/layout-b': typeof LayoutLayout2LayoutBRoute + '/params-ps/named/$foo': typeof ParamsPsNamedFooRoute + '/params-ps/named/prefix{$foo}': typeof ParamsPsNamedPrefixChar123fooChar125Route + '/params-ps/named/{$foo}suffix': typeof ParamsPsNamedChar123fooChar125suffixRoute + '/params-ps/wildcard/$': typeof ParamsPsWildcardSplatRoute + '/params-ps/wildcard/prefix{$}': typeof ParamsPsWildcardPrefixChar123Char125Route + '/params-ps/wildcard/{$}suffix': typeof ParamsPsWildcardChar123Char125suffixRoute '/params/single/$value': typeof ParamsSingleValueRoute '/posts/$postId/edit': typeof PostsPostIdEditRoute '/redirect/$target/via-beforeLoad': typeof RedirectTargetViaBeforeLoadRoute @@ -541,6 +679,8 @@ export interface FileRoutesByFullPath { '/redirect/preload/first': typeof RedirectPreloadFirstRoute '/redirect/preload/second': typeof RedirectPreloadSecondRoute '/redirect/preload/third': typeof RedirectPreloadThirdRoute + '/params-ps/named': typeof ParamsPsNamedIndexRoute + '/params-ps/wildcard': typeof ParamsPsWildcardIndexRoute '/redirect/$target/': typeof RedirectTargetIndexRoute } @@ -555,12 +695,19 @@ export interface FileRoutesByTo { '/lazyinside': typeof groupLazyinsideRoute '/posts/$postId': typeof PostsPostIdRoute '/structural-sharing/$enabled': typeof StructuralSharingEnabledRoute + '/params-ps': typeof ParamsPsIndexRoute '/posts': typeof PostsIndexRoute '/redirect': typeof RedirectIndexRoute '/insidelayout': typeof groupLayoutInsidelayoutRoute '/subfolder/inside': typeof groupSubfolderInsideRoute '/layout-a': typeof LayoutLayout2LayoutARoute '/layout-b': typeof LayoutLayout2LayoutBRoute + '/params-ps/named/$foo': typeof ParamsPsNamedFooRoute + '/params-ps/named/prefix{$foo}': typeof ParamsPsNamedPrefixChar123fooChar125Route + '/params-ps/named/{$foo}suffix': typeof ParamsPsNamedChar123fooChar125suffixRoute + '/params-ps/wildcard/$': typeof ParamsPsWildcardSplatRoute + '/params-ps/wildcard/prefix{$}': typeof ParamsPsWildcardPrefixChar123Char125Route + '/params-ps/wildcard/{$}suffix': typeof ParamsPsWildcardChar123Char125suffixRoute '/params/single/$value': typeof ParamsSingleValueRoute '/posts/$postId/edit': typeof PostsPostIdEditRoute '/redirect/$target/via-beforeLoad': typeof RedirectTargetViaBeforeLoadRoute @@ -568,6 +715,8 @@ export interface FileRoutesByTo { '/redirect/preload/first': typeof RedirectPreloadFirstRoute '/redirect/preload/second': typeof RedirectPreloadSecondRoute '/redirect/preload/third': typeof RedirectPreloadThirdRoute + '/params-ps/named': typeof ParamsPsNamedIndexRoute + '/params-ps/wildcard': typeof ParamsPsWildcardIndexRoute '/redirect/$target': typeof RedirectTargetIndexRoute } @@ -588,12 +737,19 @@ export interface FileRoutesById { '/posts/$postId': typeof PostsPostIdRoute '/redirect/$target': typeof RedirectTargetRouteWithChildren '/structural-sharing/$enabled': typeof StructuralSharingEnabledRoute + '/params-ps/': typeof ParamsPsIndexRoute '/posts/': typeof PostsIndexRoute '/redirect/': typeof RedirectIndexRoute '/(group)/_layout/insidelayout': typeof groupLayoutInsidelayoutRoute '/(group)/subfolder/inside': typeof groupSubfolderInsideRoute '/_layout/_layout-2/layout-a': typeof LayoutLayout2LayoutARoute '/_layout/_layout-2/layout-b': typeof LayoutLayout2LayoutBRoute + '/params-ps/named/$foo': typeof ParamsPsNamedFooRoute + '/params-ps/named/prefix{$foo}': typeof ParamsPsNamedPrefixChar123fooChar125Route + '/params-ps/named/{$foo}suffix': typeof ParamsPsNamedChar123fooChar125suffixRoute + '/params-ps/wildcard/$': typeof ParamsPsWildcardSplatRoute + '/params-ps/wildcard/prefix{$}': typeof ParamsPsWildcardPrefixChar123Char125Route + '/params-ps/wildcard/{$}suffix': typeof ParamsPsWildcardChar123Char125suffixRoute '/params/single/$value': typeof ParamsSingleValueRoute '/posts_/$postId/edit': typeof PostsPostIdEditRoute '/redirect/$target/via-beforeLoad': typeof RedirectTargetViaBeforeLoadRoute @@ -601,6 +757,8 @@ export interface FileRoutesById { '/redirect/preload/first': typeof RedirectPreloadFirstRoute '/redirect/preload/second': typeof RedirectPreloadSecondRoute '/redirect/preload/third': typeof RedirectPreloadThirdRoute + '/params-ps/named/': typeof ParamsPsNamedIndexRoute + '/params-ps/wildcard/': typeof ParamsPsWildcardIndexRoute '/redirect/$target/': typeof RedirectTargetIndexRoute } @@ -619,12 +777,19 @@ export interface FileRouteTypes { | '/posts/$postId' | '/redirect/$target' | '/structural-sharing/$enabled' + | '/params-ps' | '/posts/' | '/redirect' | '/insidelayout' | '/subfolder/inside' | '/layout-a' | '/layout-b' + | '/params-ps/named/$foo' + | '/params-ps/named/prefix{$foo}' + | '/params-ps/named/{$foo}suffix' + | '/params-ps/wildcard/$' + | '/params-ps/wildcard/prefix{$}' + | '/params-ps/wildcard/{$}suffix' | '/params/single/$value' | '/posts/$postId/edit' | '/redirect/$target/via-beforeLoad' @@ -632,6 +797,8 @@ export interface FileRouteTypes { | '/redirect/preload/first' | '/redirect/preload/second' | '/redirect/preload/third' + | '/params-ps/named' + | '/params-ps/wildcard' | '/redirect/$target/' fileRoutesByTo: FileRoutesByTo to: @@ -645,12 +812,19 @@ export interface FileRouteTypes { | '/lazyinside' | '/posts/$postId' | '/structural-sharing/$enabled' + | '/params-ps' | '/posts' | '/redirect' | '/insidelayout' | '/subfolder/inside' | '/layout-a' | '/layout-b' + | '/params-ps/named/$foo' + | '/params-ps/named/prefix{$foo}' + | '/params-ps/named/{$foo}suffix' + | '/params-ps/wildcard/$' + | '/params-ps/wildcard/prefix{$}' + | '/params-ps/wildcard/{$}suffix' | '/params/single/$value' | '/posts/$postId/edit' | '/redirect/$target/via-beforeLoad' @@ -658,6 +832,8 @@ export interface FileRouteTypes { | '/redirect/preload/first' | '/redirect/preload/second' | '/redirect/preload/third' + | '/params-ps/named' + | '/params-ps/wildcard' | '/redirect/$target' id: | '__root__' @@ -676,12 +852,19 @@ export interface FileRouteTypes { | '/posts/$postId' | '/redirect/$target' | '/structural-sharing/$enabled' + | '/params-ps/' | '/posts/' | '/redirect/' | '/(group)/_layout/insidelayout' | '/(group)/subfolder/inside' | '/_layout/_layout-2/layout-a' | '/_layout/_layout-2/layout-b' + | '/params-ps/named/$foo' + | '/params-ps/named/prefix{$foo}' + | '/params-ps/named/{$foo}suffix' + | '/params-ps/wildcard/$' + | '/params-ps/wildcard/prefix{$}' + | '/params-ps/wildcard/{$}suffix' | '/params/single/$value' | '/posts_/$postId/edit' | '/redirect/$target/via-beforeLoad' @@ -689,6 +872,8 @@ export interface FileRouteTypes { | '/redirect/preload/first' | '/redirect/preload/second' | '/redirect/preload/third' + | '/params-ps/named/' + | '/params-ps/wildcard/' | '/redirect/$target/' fileRoutesById: FileRoutesById } @@ -704,12 +889,21 @@ export interface RootRouteChildren { groupRoute: typeof groupRouteWithChildren RedirectTargetRoute: typeof RedirectTargetRouteWithChildren StructuralSharingEnabledRoute: typeof StructuralSharingEnabledRoute + ParamsPsIndexRoute: typeof ParamsPsIndexRoute RedirectIndexRoute: typeof RedirectIndexRoute + ParamsPsNamedFooRoute: typeof ParamsPsNamedFooRoute + ParamsPsNamedPrefixChar123fooChar125Route: typeof ParamsPsNamedPrefixChar123fooChar125Route + ParamsPsNamedChar123fooChar125suffixRoute: typeof ParamsPsNamedChar123fooChar125suffixRoute + ParamsPsWildcardSplatRoute: typeof ParamsPsWildcardSplatRoute + ParamsPsWildcardPrefixChar123Char125Route: typeof ParamsPsWildcardPrefixChar123Char125Route + ParamsPsWildcardChar123Char125suffixRoute: typeof ParamsPsWildcardChar123Char125suffixRoute ParamsSingleValueRoute: typeof ParamsSingleValueRoute PostsPostIdEditRoute: typeof PostsPostIdEditRoute RedirectPreloadFirstRoute: typeof RedirectPreloadFirstRoute RedirectPreloadSecondRoute: typeof RedirectPreloadSecondRoute RedirectPreloadThirdRoute: typeof RedirectPreloadThirdRoute + ParamsPsNamedIndexRoute: typeof ParamsPsNamedIndexRoute + ParamsPsWildcardIndexRoute: typeof ParamsPsWildcardIndexRoute } const rootRouteChildren: RootRouteChildren = { @@ -723,12 +917,25 @@ const rootRouteChildren: RootRouteChildren = { groupRoute: groupRouteWithChildren, RedirectTargetRoute: RedirectTargetRouteWithChildren, StructuralSharingEnabledRoute: StructuralSharingEnabledRoute, + ParamsPsIndexRoute: ParamsPsIndexRoute, RedirectIndexRoute: RedirectIndexRoute, + ParamsPsNamedFooRoute: ParamsPsNamedFooRoute, + ParamsPsNamedPrefixChar123fooChar125Route: + ParamsPsNamedPrefixChar123fooChar125Route, + ParamsPsNamedChar123fooChar125suffixRoute: + ParamsPsNamedChar123fooChar125suffixRoute, + ParamsPsWildcardSplatRoute: ParamsPsWildcardSplatRoute, + ParamsPsWildcardPrefixChar123Char125Route: + ParamsPsWildcardPrefixChar123Char125Route, + ParamsPsWildcardChar123Char125suffixRoute: + ParamsPsWildcardChar123Char125suffixRoute, ParamsSingleValueRoute: ParamsSingleValueRoute, PostsPostIdEditRoute: PostsPostIdEditRoute, RedirectPreloadFirstRoute: RedirectPreloadFirstRoute, RedirectPreloadSecondRoute: RedirectPreloadSecondRoute, RedirectPreloadThirdRoute: RedirectPreloadThirdRoute, + ParamsPsNamedIndexRoute: ParamsPsNamedIndexRoute, + ParamsPsWildcardIndexRoute: ParamsPsWildcardIndexRoute, } export const routeTree = rootRoute @@ -751,12 +958,21 @@ export const routeTree = rootRoute "/(group)", "/redirect/$target", "/structural-sharing/$enabled", + "/params-ps/", "/redirect/", + "/params-ps/named/$foo", + "/params-ps/named/prefix{$foo}", + "/params-ps/named/{$foo}suffix", + "/params-ps/wildcard/$", + "/params-ps/wildcard/prefix{$}", + "/params-ps/wildcard/{$}suffix", "/params/single/$value", "/posts_/$postId/edit", "/redirect/preload/first", "/redirect/preload/second", - "/redirect/preload/third" + "/redirect/preload/third", + "/params-ps/named/", + "/params-ps/wildcard/" ] }, "/": { @@ -834,6 +1050,9 @@ export const routeTree = rootRoute "/structural-sharing/$enabled": { "filePath": "structural-sharing.$enabled.tsx" }, + "/params-ps/": { + "filePath": "params-ps/index.tsx" + }, "/posts/": { "filePath": "posts.index.tsx", "parent": "/posts" @@ -857,6 +1076,24 @@ export const routeTree = rootRoute "filePath": "_layout/_layout-2/layout-b.tsx", "parent": "/_layout/_layout-2" }, + "/params-ps/named/$foo": { + "filePath": "params-ps/named/$foo.tsx" + }, + "/params-ps/named/prefix{$foo}": { + "filePath": "params-ps/named/prefix{$foo}.tsx" + }, + "/params-ps/named/{$foo}suffix": { + "filePath": "params-ps/named/{$foo}suffix.tsx" + }, + "/params-ps/wildcard/$": { + "filePath": "params-ps/wildcard/$.tsx" + }, + "/params-ps/wildcard/prefix{$}": { + "filePath": "params-ps/wildcard/prefix{$}.tsx" + }, + "/params-ps/wildcard/{$}suffix": { + "filePath": "params-ps/wildcard/{$}suffix.tsx" + }, "/params/single/$value": { "filePath": "params.single.$value.tsx" }, @@ -880,6 +1117,12 @@ export const routeTree = rootRoute "/redirect/preload/third": { "filePath": "redirect/preload/third.tsx" }, + "/params-ps/named/": { + "filePath": "params-ps/named/index.tsx" + }, + "/params-ps/wildcard/": { + "filePath": "params-ps/wildcard/index.tsx" + }, "/redirect/$target/": { "filePath": "redirect/$target/index.tsx", "parent": "/redirect/$target" diff --git a/e2e/react-router/basic-file-based/src/routes/(another-group)/onlyrouteinside.tsx b/e2e/react-router/basic-file-based/src/routes/(another-group)/onlyrouteinside.tsx index bbd1eedb6f..07794d4fe0 100644 --- a/e2e/react-router/basic-file-based/src/routes/(another-group)/onlyrouteinside.tsx +++ b/e2e/react-router/basic-file-based/src/routes/(another-group)/onlyrouteinside.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, getRouteApi, useSearch } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { getRouteApi, useSearch } from '@tanstack/react-router' import { z } from 'zod' import { zodValidator } from '@tanstack/zod-adapter' diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/_layout.insidelayout.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/_layout.insidelayout.tsx index 2975baedc9..f2c70bb248 100644 --- a/e2e/react-router/basic-file-based/src/routes/(group)/_layout.insidelayout.tsx +++ b/e2e/react-router/basic-file-based/src/routes/(group)/_layout.insidelayout.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, getRouteApi, useSearch } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { getRouteApi, useSearch } from '@tanstack/react-router' import { z } from 'zod' import { zodValidator } from '@tanstack/zod-adapter' diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/_layout.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/_layout.tsx index 4b755791c0..c8b874997b 100644 --- a/e2e/react-router/basic-file-based/src/routes/(group)/_layout.tsx +++ b/e2e/react-router/basic-file-based/src/routes/(group)/_layout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/(group)/_layout')({ component: () => ( diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/inside.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/inside.tsx index 356ff96003..429967fd33 100644 --- a/e2e/react-router/basic-file-based/src/routes/(group)/inside.tsx +++ b/e2e/react-router/basic-file-based/src/routes/(group)/inside.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, getRouteApi, useSearch } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { getRouteApi, useSearch } from '@tanstack/react-router' import { z } from 'zod' import { zodValidator } from '@tanstack/zod-adapter' diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx index 527be4f520..7112ca410e 100644 --- a/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx +++ b/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx @@ -1,8 +1,5 @@ -import { - createLazyFileRoute, - getRouteApi, - useSearch, -} from '@tanstack/react-router' +import { createLazyFileRoute } from '@tanstack/react-router' +import { getRouteApi, useSearch } from '@tanstack/react-router' const routeApi = getRouteApi('/(group)/lazyinside') diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/subfolder/inside.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/subfolder/inside.tsx index 3a4a051e8a..456aaa006d 100644 --- a/e2e/react-router/basic-file-based/src/routes/(group)/subfolder/inside.tsx +++ b/e2e/react-router/basic-file-based/src/routes/(group)/subfolder/inside.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, getRouteApi, useSearch } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { getRouteApi, useSearch } from '@tanstack/react-router' import { z } from 'zod' import { zodValidator } from '@tanstack/zod-adapter' diff --git a/e2e/react-router/basic-file-based/src/routes/_layout.tsx b/e2e/react-router/basic-file-based/src/routes/_layout.tsx index 02ddbb1cd9..0fcaac3a52 100644 --- a/e2e/react-router/basic-file-based/src/routes/_layout.tsx +++ b/e2e/react-router/basic-file-based/src/routes/_layout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_layout')({ component: LayoutComponent, diff --git a/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2.tsx b/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2.tsx index 3b7dbf2903..388d0b3b87 100644 --- a/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2.tsx +++ b/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_layout/_layout-2')({ component: LayoutComponent, diff --git a/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx b/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx index 61e19b4d9f..ed2dea8800 100644 --- a/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx +++ b/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ component: LayoutAComponent, }) diff --git a/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx b/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx index cceed1fb9a..4799d403e9 100644 --- a/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx +++ b/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ component: LayoutBComponent, }) diff --git a/e2e/react-router/basic-file-based/src/routes/anchor.tsx b/e2e/react-router/basic-file-based/src/routes/anchor.tsx index 93975ba621..d674230db4 100644 --- a/e2e/react-router/basic-file-based/src/routes/anchor.tsx +++ b/e2e/react-router/basic-file-based/src/routes/anchor.tsx @@ -1,10 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import { useLayoutEffect, useRef, useState } from 'react' -import { - Link, - createFileRoute, - useLocation, - useNavigate, -} from '@tanstack/react-router' +import { Link, useLocation, useNavigate } from '@tanstack/react-router' export const Route = createFileRoute('/anchor')({ component: AnchorComponent, diff --git a/e2e/react-router/basic-file-based/src/routes/editing-a.tsx b/e2e/react-router/basic-file-based/src/routes/editing-a.tsx index cecd0dfed1..bf98108848 100644 --- a/e2e/react-router/basic-file-based/src/routes/editing-a.tsx +++ b/e2e/react-router/basic-file-based/src/routes/editing-a.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { createFileRoute, useBlocker } from '@tanstack/react-router' +import { useBlocker } from '@tanstack/react-router' export const Route = createFileRoute('/editing-a')({ component: RouteComponent, diff --git a/e2e/react-router/basic-file-based/src/routes/editing-b.tsx b/e2e/react-router/basic-file-based/src/routes/editing-b.tsx index 1a85e72e26..1f3c2f1f2a 100644 --- a/e2e/react-router/basic-file-based/src/routes/editing-b.tsx +++ b/e2e/react-router/basic-file-based/src/routes/editing-b.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { createFileRoute, useBlocker } from '@tanstack/react-router' +import { useBlocker } from '@tanstack/react-router' export const Route = createFileRoute('/editing-b')({ component: RouteComponent, diff --git a/e2e/react-router/basic-file-based/src/routes/index.tsx b/e2e/react-router/basic-file-based/src/routes/index.tsx index eac82a9174..0a5b7572ba 100644 --- a/e2e/react-router/basic-file-based/src/routes/index.tsx +++ b/e2e/react-router/basic-file-based/src/routes/index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/')({ component: Home, diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/index.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/index.tsx new file mode 100644 index 0000000000..67893d7d23 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/index.tsx @@ -0,0 +1,74 @@ +import { createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' + +export const Route = createFileRoute('/params-ps/')({ + component: RouteComponent, +}) + +function RouteComponent() { + return ( +
+

Named path params

+
    +
  • + + /params-ps/named/$foo + +
  • +
  • + + /params-ps/named/{'prefix{$foo}'} + +
  • +
  • + + /params-ps/named/{'{$foo}suffix'} + +
  • +
+
+

Wildcard path params

+
    +
  • + + /params-ps/wildcard/$ + +
  • +
  • + + /params-ps/wildcard/{'prefix{$}'} + +
  • +
  • + + /params-ps/wildcard/{'{$}suffix'} + +
  • +
+
+ ) +} diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/named/$foo.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/named/$foo.tsx new file mode 100644 index 0000000000..dae4251e29 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/named/$foo.tsx @@ -0,0 +1,14 @@ +import { createFileRoute } from '@tanstack/react-router' +export const Route = createFileRoute('/params-ps/named/$foo')({ + component: RouteComponent, +}) + +function RouteComponent() { + const p = Route.useParams() + return ( +
+

ParamsNamedFoo

+
{JSON.stringify(p)}
+
+ ) +} diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/named/index.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/named/index.tsx new file mode 100644 index 0000000000..f9a9a7ac06 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/named/index.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' + +export const Route = createFileRoute('/params-ps/named/')({ + beforeLoad: () => { + throw redirect({ to: '/params-ps' }) + }, +}) diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/named/prefix{$foo}.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/named/prefix{$foo}.tsx new file mode 100644 index 0000000000..69f6163299 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/named/prefix{$foo}.tsx @@ -0,0 +1,14 @@ +import { createFileRoute } from '@tanstack/react-router' +export const Route = createFileRoute('/params-ps/named/prefix{$foo}')({ + component: RouteComponent, +}) + +function RouteComponent() { + const p = Route.useParams() + return ( +
+

ParamsNamedFooPrefix

+
{JSON.stringify(p)}
+
+ ) +} diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/named/{$foo}suffix.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/named/{$foo}suffix.tsx new file mode 100644 index 0000000000..f98b9cc57a --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/named/{$foo}suffix.tsx @@ -0,0 +1,14 @@ +import { createFileRoute } from '@tanstack/react-router' +export const Route = createFileRoute('/params-ps/named/{$foo}suffix')({ + component: RouteComponent, +}) + +function RouteComponent() { + const p = Route.useParams() + return ( +
+

ParamsNamedFooSuffix

+
{JSON.stringify(p)}
+
+ ) +} diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/wildcard/$.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/wildcard/$.tsx new file mode 100644 index 0000000000..603dff0d59 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/wildcard/$.tsx @@ -0,0 +1,14 @@ +import { createFileRoute } from '@tanstack/react-router' +export const Route = createFileRoute('/params-ps/wildcard/$')({ + component: RouteComponent, +}) + +function RouteComponent() { + const p = Route.useParams() + return ( +
+

ParamsWildcardSplat

+
{JSON.stringify(p)}
+
+ ) +} diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/wildcard/index.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/wildcard/index.tsx new file mode 100644 index 0000000000..62415d5ac4 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/wildcard/index.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' + +export const Route = createFileRoute('/params-ps/wildcard/')({ + beforeLoad: () => { + throw redirect({ to: '/params-ps' }) + }, +}) diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/wildcard/prefix{$}.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/wildcard/prefix{$}.tsx new file mode 100644 index 0000000000..dc994cb8ec --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/wildcard/prefix{$}.tsx @@ -0,0 +1,14 @@ +import { createFileRoute } from '@tanstack/react-router' +export const Route = createFileRoute('/params-ps/wildcard/prefix{$}')({ + component: RouteComponent, +}) + +function RouteComponent() { + const p = Route.useParams() + return ( +
+

ParamsWildcardSplatPrefix

+
{JSON.stringify(p)}
+
+ ) +} diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/wildcard/{$}suffix.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/wildcard/{$}suffix.tsx new file mode 100644 index 0000000000..a7a2995771 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/wildcard/{$}suffix.tsx @@ -0,0 +1,14 @@ +import { createFileRoute } from '@tanstack/react-router' +export const Route = createFileRoute('/params-ps/wildcard/{$}suffix')({ + component: RouteComponent, +}) + +function RouteComponent() { + const p = Route.useParams() + return ( +
+

ParamsWildcardSplatSuffix

+
{JSON.stringify(p)}
+
+ ) +} diff --git a/e2e/react-router/basic-file-based/src/routes/params.single.$value.tsx b/e2e/react-router/basic-file-based/src/routes/params.single.$value.tsx index b5761e839e..7ee38c0db8 100644 --- a/e2e/react-router/basic-file-based/src/routes/params.single.$value.tsx +++ b/e2e/react-router/basic-file-based/src/routes/params.single.$value.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' export const Route = createFileRoute('/params/single/$value')({ component: RouteComponent, diff --git a/e2e/react-router/basic-file-based/src/routes/posts.$postId.tsx b/e2e/react-router/basic-file-based/src/routes/posts.$postId.tsx index df51873ddf..3466bd9d9d 100644 --- a/e2e/react-router/basic-file-based/src/routes/posts.$postId.tsx +++ b/e2e/react-router/basic-file-based/src/routes/posts.$postId.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import { fetchPost } from '../posts' import type { ErrorComponentProps } from '@tanstack/react-router' diff --git a/e2e/react-router/basic-file-based/src/routes/posts.index.tsx b/e2e/react-router/basic-file-based/src/routes/posts.index.tsx index ab89fb5a62..90a8777a52 100644 --- a/e2e/react-router/basic-file-based/src/routes/posts.index.tsx +++ b/e2e/react-router/basic-file-based/src/routes/posts.index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, diff --git a/e2e/react-router/basic-file-based/src/routes/posts.tsx b/e2e/react-router/basic-file-based/src/routes/posts.tsx index 9eabdd5b33..39b3328366 100644 --- a/e2e/react-router/basic-file-based/src/routes/posts.tsx +++ b/e2e/react-router/basic-file-based/src/routes/posts.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../posts' export const Route = createFileRoute('/posts')({ diff --git a/e2e/react-router/basic-file-based/src/routes/posts_.$postId.edit.tsx b/e2e/react-router/basic-file-based/src/routes/posts_.$postId.edit.tsx index 44a62b0004..7ddf02cc21 100644 --- a/e2e/react-router/basic-file-based/src/routes/posts_.$postId.edit.tsx +++ b/e2e/react-router/basic-file-based/src/routes/posts_.$postId.edit.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, getRouteApi, useParams } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { getRouteApi, useParams } from '@tanstack/react-router' export const Route = createFileRoute('/posts_/$postId/edit')({ component: PostEditPage, diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/$target.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/$target.tsx index 686f1c7056..37e4729107 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/$target.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/$target.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, retainSearchParams } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { retainSearchParams } from '@tanstack/react-router' import z from 'zod' export const Route = createFileRoute('/redirect/$target')({ diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/$target/index.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/$target/index.tsx index 57760cec88..65d3a1d827 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/$target/index.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/$target/index.tsx @@ -1,4 +1,5 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' export const Route = createFileRoute('/redirect/$target/')({ component: () => { diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-beforeLoad.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-beforeLoad.tsx index 14a2492331..1f4a1a9e50 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-beforeLoad.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-beforeLoad.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' export const Route = createFileRoute('/redirect/$target/via-beforeLoad')({ beforeLoad: ({ @@ -9,8 +10,7 @@ export const Route = createFileRoute('/redirect/$target/via-beforeLoad')({ case 'internal': throw redirect({ to: '/posts', reloadDocument }) case 'external': - const href = externalHost ?? 'http://example.com' - throw redirect({ href }) + throw redirect({ href: externalHost ?? 'http://example.com' }) } }, component: () =>
{Route.fullPath}
, diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-loader.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-loader.tsx index 9e6a3fc9db..4b111c62de 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-loader.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-loader.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' export const Route = createFileRoute('/redirect/$target/via-loader')({ loaderDeps: ({ search: { reloadDocument, externalHost } }) => ({ diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/index.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/index.tsx index c0b26a1df4..816065decd 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/index.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/index.tsx @@ -1,4 +1,5 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' export const Route = createFileRoute('/redirect/')({ component: () => ( diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/preload/first.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/preload/first.tsx index a997c60a9e..f004c427d9 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/preload/first.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/preload/first.tsx @@ -1,4 +1,5 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' export const Route = createFileRoute('/redirect/preload/first')({ component: RouteComponent, diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/preload/second.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/preload/second.tsx index 3c97522ac8..b0c04a2fb0 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/preload/second.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/preload/second.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' export const Route = createFileRoute('/redirect/preload/second')({ loader: async () => { diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/preload/third.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/preload/third.tsx index e882d29e69..5d429a67d3 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/preload/third.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/preload/third.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/redirect/preload/third')({ component: RouteComponent, }) diff --git a/e2e/react-router/basic-file-based/src/routes/structural-sharing.$enabled.tsx b/e2e/react-router/basic-file-based/src/routes/structural-sharing.$enabled.tsx index 4a477f7ccd..1aa8a1e5b4 100644 --- a/e2e/react-router/basic-file-based/src/routes/structural-sharing.$enabled.tsx +++ b/e2e/react-router/basic-file-based/src/routes/structural-sharing.$enabled.tsx @@ -1,9 +1,5 @@ -import { - Link, - createFileRoute, - getRouteApi, - useSearch, -} from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link, getRouteApi, useSearch } from '@tanstack/react-router' import React from 'react' import { z } from 'zod' diff --git a/e2e/react-router/basic-file-based/tests/params.spec.ts b/e2e/react-router/basic-file-based/tests/params.spec.ts index e95bc56c59..5d4c6111b7 100644 --- a/e2e/react-router/basic-file-based/tests/params.spec.ts +++ b/e2e/react-router/basic-file-based/tests/params.spec.ts @@ -54,3 +54,151 @@ test.describe('ensure single params have been parsed correctly whilst being stab }) } }) + +test.describe('params operations + prefix/suffix', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/params-ps') + }) + + test.describe('named params', () => { + const NAMED_PARAMS_PAIRS = [ + // Test ID | Expected href + { + id: 'l-to-named-foo', + pathname: '/params-ps/named/foo', + params: { foo: 'foo' }, + destHeadingId: 'ParamsNamedFoo', + }, + { + id: 'l-to-named-prefixfoo', + pathname: '/params-ps/named/prefixfoo', + params: { foo: 'foo' }, + destHeadingId: 'ParamsNamedFooPrefix', + }, + { + id: 'l-to-named-foosuffix', + pathname: '/params-ps/named/foosuffix', + params: { foo: 'foo' }, + destHeadingId: 'ParamsNamedFooSuffix', + }, + ] satisfies Array<{ + id: string + pathname: string + params: Record + destHeadingId: string + }> + + test.describe('Link', () => { + NAMED_PARAMS_PAIRS.forEach(({ id, pathname }) => { + test(`interpolation for testid="${id}" has href="${pathname}"`, async ({ + page, + }) => { + const link = page.getByTestId(id) + await expect(link).toHaveAttribute('href', pathname) + }) + }) + + NAMED_PARAMS_PAIRS.forEach(({ id, pathname }) => { + test(`navigation for testid="${id}" succeeds to href="${pathname}"`, async ({ + page, + }) => { + const link = page.getByTestId(id) + await link.click() + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe(pathname) + }) + }) + }) + + NAMED_PARAMS_PAIRS.forEach(({ pathname, params, destHeadingId }) => { + test(`on first-load to "${pathname}" has correct params`, async ({ + page, + }) => { + await page.goto(pathname) + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe(pathname) + + const headingEl = page.getByRole('heading', { name: destHeadingId }) + await expect(headingEl).toBeVisible() + + const paramsEl = page.getByTestId('params-output') + const paramsText = await paramsEl.innerText() + const paramsObj = JSON.parse(paramsText) + expect(paramsObj).toEqual(params) + }) + }) + }) + + test.describe('wildcard param', () => { + const WILDCARD_PARAM_PAIRS = [ + // Test ID | Expected href + { + id: 'l-to-wildcard-foo', + pathname: '/params-ps/wildcard/foo', + params: { '*': 'foo', _splat: 'foo' }, + destHeadingId: 'ParamsWildcardSplat', + }, + { + id: 'l-to-wildcard-prefixfoo', + pathname: '/params-ps/wildcard/prefixfoo', + params: { '*': 'foo', _splat: 'foo' }, + destHeadingId: 'ParamsWildcardSplatPrefix', + }, + { + id: 'l-to-wildcard-foosuffix', + pathname: '/params-ps/wildcard/foosuffix', + params: { '*': 'foo', _splat: 'foo' }, + destHeadingId: 'ParamsWildcardSplatSuffix', + }, + ] satisfies Array<{ + id: string + pathname: string + params: Record + destHeadingId: string + }> + + test.describe('Link', () => { + WILDCARD_PARAM_PAIRS.forEach(({ id, pathname }) => { + test(`interpolation for testid="${id}" has href="${pathname}"`, async ({ + page, + }) => { + const link = page.getByTestId(id) + await expect(link).toHaveAttribute('href', pathname) + }) + }) + + WILDCARD_PARAM_PAIRS.forEach(({ id, pathname }) => { + test(`navigation for testid="${id}" succeeds to href="${pathname}"`, async ({ + page, + }) => { + const link = page.getByTestId(id) + await link.click() + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe(pathname) + }) + }) + }) + + WILDCARD_PARAM_PAIRS.forEach(({ pathname, params, destHeadingId }) => { + test(`on first-load to "${pathname}" has correct params`, async ({ + page, + }) => { + await page.goto(pathname) + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe(pathname) + + const headingEl = page.getByRole('heading', { name: destHeadingId }) + await expect(headingEl).toBeVisible() + + const paramsEl = page.getByTestId('params-output') + const paramsText = await paramsEl.innerText() + const paramsObj = JSON.parse(paramsText) + expect(paramsObj).toEqual(params) + }) + }) + }) +}) diff --git a/e2e/react-router/basic-file-based/vite.config.js b/e2e/react-router/basic-file-based/vite.config.js index 1a57a64b22..172112dd72 100644 --- a/e2e/react-router/basic-file-based/vite.config.js +++ b/e2e/react-router/basic-file-based/vite.config.js @@ -1,8 +1,8 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ - plugins: [TanStackRouterVite({ target: 'react' }), react()], + plugins: [tanstackRouter({ target: 'react' }), react()], }) diff --git a/e2e/react-router/basic-react-query-file-based/package.json b/e2e/react-router/basic-react-query-file-based/package.json index 444b508488..e7c7d75f4d 100644 --- a/e2e/react-router/basic-react-query-file-based/package.json +++ b/e2e/react-router/basic-react-query-file-based/package.json @@ -30,6 +30,6 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/react-router/basic-react-query-file-based/src/routeTree.gen.ts b/e2e/react-router/basic-react-query-file-based/src/routeTree.gen.ts index 375fe8dc91..6d8fa1bd79 100644 --- a/e2e/react-router/basic-react-query-file-based/src/routeTree.gen.ts +++ b/e2e/react-router/basic-react-query-file-based/src/routeTree.gen.ts @@ -11,58 +11,58 @@ // 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 PostsIndexImport } from './routes/posts.index' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as LayoutLayout2Import } from './routes/_layout/_layout-2' -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 PostsRouteImport } from './routes/posts' +import { Route as LayoutRouteImport } from './routes/_layout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2' +import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b' +import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' // Create/Update Routes -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const LayoutRoute = LayoutImport.update({ +const LayoutRoute = LayoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const LayoutLayout2Route = LayoutLayout2Import.update({ +const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) -const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBImport.update({ +const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => LayoutLayout2Route, } as any) -const LayoutLayout2LayoutARoute = LayoutLayout2LayoutAImport.update({ +const LayoutLayout2LayoutARoute = LayoutLayout2LayoutARouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => LayoutLayout2Route, @@ -76,57 +76,57 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/_layout/_layout-2': { id: '/_layout/_layout-2' path: '' fullPath: '' - preLoaderRoute: typeof LayoutLayout2Import - parentRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutLayout2RouteImport + parentRoute: typeof LayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/_layout/_layout-2/layout-a': { id: '/_layout/_layout-2/layout-a' path: '/layout-a' fullPath: '/layout-a' - preLoaderRoute: typeof LayoutLayout2LayoutAImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutARouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/_layout/_layout-2/layout-b': { id: '/_layout/_layout-2/layout-b' path: '/layout-b' fullPath: '/layout-b' - preLoaderRoute: typeof LayoutLayout2LayoutBImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutBRouteImport + parentRoute: typeof LayoutLayout2RouteImport } } } diff --git a/e2e/react-router/basic-react-query-file-based/src/routes/_layout.tsx b/e2e/react-router/basic-react-query-file-based/src/routes/_layout.tsx index 02ddbb1cd9..0fcaac3a52 100644 --- a/e2e/react-router/basic-react-query-file-based/src/routes/_layout.tsx +++ b/e2e/react-router/basic-react-query-file-based/src/routes/_layout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_layout')({ component: LayoutComponent, diff --git a/e2e/react-router/basic-react-query-file-based/src/routes/_layout/_layout-2.tsx b/e2e/react-router/basic-react-query-file-based/src/routes/_layout/_layout-2.tsx index 3b7dbf2903..388d0b3b87 100644 --- a/e2e/react-router/basic-react-query-file-based/src/routes/_layout/_layout-2.tsx +++ b/e2e/react-router/basic-react-query-file-based/src/routes/_layout/_layout-2.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_layout/_layout-2')({ component: LayoutComponent, diff --git a/e2e/react-router/basic-react-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx b/e2e/react-router/basic-react-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx index 61e19b4d9f..ed2dea8800 100644 --- a/e2e/react-router/basic-react-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx +++ b/e2e/react-router/basic-react-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ component: LayoutAComponent, }) diff --git a/e2e/react-router/basic-react-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx b/e2e/react-router/basic-react-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx index cceed1fb9a..4799d403e9 100644 --- a/e2e/react-router/basic-react-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx +++ b/e2e/react-router/basic-react-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ component: LayoutBComponent, }) diff --git a/e2e/react-router/basic-react-query-file-based/src/routes/index.tsx b/e2e/react-router/basic-react-query-file-based/src/routes/index.tsx index eac82a9174..0a5b7572ba 100644 --- a/e2e/react-router/basic-react-query-file-based/src/routes/index.tsx +++ b/e2e/react-router/basic-react-query-file-based/src/routes/index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/')({ component: Home, diff --git a/e2e/react-router/basic-react-query-file-based/src/routes/posts.$postId.tsx b/e2e/react-router/basic-react-query-file-based/src/routes/posts.$postId.tsx index 4cf6beca88..9c7e89fbce 100644 --- a/e2e/react-router/basic-react-query-file-based/src/routes/posts.$postId.tsx +++ b/e2e/react-router/basic-react-query-file-based/src/routes/posts.$postId.tsx @@ -1,9 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { - ErrorComponent, - createFileRoute, - useRouter, -} from '@tanstack/react-router' +import { ErrorComponent, useRouter } from '@tanstack/react-router' import { useQueryErrorResetBoundary, useSuspenseQuery, diff --git a/e2e/react-router/basic-react-query-file-based/src/routes/posts.index.tsx b/e2e/react-router/basic-react-query-file-based/src/routes/posts.index.tsx index 056433ca0a..c6b65f1892 100644 --- a/e2e/react-router/basic-react-query-file-based/src/routes/posts.index.tsx +++ b/e2e/react-router/basic-react-query-file-based/src/routes/posts.index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, diff --git a/e2e/react-router/basic-react-query-file-based/src/routes/posts.tsx b/e2e/react-router/basic-react-query-file-based/src/routes/posts.tsx index 86701f982c..eed69e28aa 100644 --- a/e2e/react-router/basic-react-query-file-based/src/routes/posts.tsx +++ b/e2e/react-router/basic-react-query-file-based/src/routes/posts.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { useSuspenseQuery } from '@tanstack/react-query' import { postsQueryOptions } from '../postsQueryOptions' diff --git a/e2e/react-router/basic-react-query-file-based/vite.config.js b/e2e/react-router/basic-react-query-file-based/vite.config.js index b819774577..ab615485ae 100644 --- a/e2e/react-router/basic-react-query-file-based/vite.config.js +++ b/e2e/react-router/basic-react-query-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ target: 'react', autoCodeSplitting: true }), react(), ], }) diff --git a/e2e/react-router/basic-react-query/package.json b/e2e/react-router/basic-react-query/package.json index cabb1a5fd0..998c71bf16 100644 --- a/e2e/react-router/basic-react-query/package.json +++ b/e2e/react-router/basic-react-query/package.json @@ -28,6 +28,6 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/react-router/basic-scroll-restoration/package.json b/e2e/react-router/basic-scroll-restoration/package.json index ca4a82c5b0..e57df26a06 100644 --- a/e2e/react-router/basic-scroll-restoration/package.json +++ b/e2e/react-router/basic-scroll-restoration/package.json @@ -27,6 +27,6 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/react-router/basic-virtual-file-based/package.json b/e2e/react-router/basic-virtual-file-based/package.json index 5d881fc0a4..86b1081710 100644 --- a/e2e/react-router/basic-virtual-file-based/package.json +++ b/e2e/react-router/basic-virtual-file-based/package.json @@ -29,6 +29,6 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/react-router/basic-virtual-file-based/src/routeTree.gen.ts b/e2e/react-router/basic-virtual-file-based/src/routeTree.gen.ts index 01132459aa..d7f7c489f7 100644 --- a/e2e/react-router/basic-virtual-file-based/src/routeTree.gen.ts +++ b/e2e/react-router/basic-virtual-file-based/src/routeTree.gen.ts @@ -8,89 +8,91 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-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' +import { Route as postsPostsRouteImport } from './routes/posts/posts' +import { Route as layoutFirstLayoutRouteImport } from './routes/layout/first-layout' +import { Route as homeRouteImport } from './routes/home' +import { Route as postsPostsDetailRouteImport } from './routes/posts/posts-detail' +import { Route as layoutSecondLayoutRouteImport } from './routes/layout/second-layout' +import { Route as postsPostsHomeRouteImport } from './routes/posts/posts-home' +import { Route as ClassicHelloRouteRouteImport } from './routes/file-based-subtree/hello/route' +import { Route as ClassicHelloIndexRouteImport } from './routes/file-based-subtree/hello/index' +import { Route as ClassicHelloWorldRouteImport } from './routes/file-based-subtree/hello/world' +import { Route as ClassicHelloUniverseRouteImport } from './routes/file-based-subtree/hello/universe' +import { Route as bRouteImport } from './routes/b' +import { Route as aRouteImport } from './routes/a' // Create/Update Routes -const postsPostsRoute = postsPostsImport.update({ +const postsPostsRoute = postsPostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const layoutFirstLayoutRoute = layoutFirstLayoutImport.update({ +const layoutFirstLayoutRoute = layoutFirstLayoutRouteImport.update({ id: '/_first', getParentRoute: () => rootRoute, } as any) -const homeRoute = homeImport.update({ +const homeRoute = homeRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const postsPostsDetailRoute = postsPostsDetailImport.update({ +const postsPostsDetailRoute = postsPostsDetailRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => postsPostsRoute, } as any) -const layoutSecondLayoutRoute = layoutSecondLayoutImport.update({ +const layoutSecondLayoutRoute = layoutSecondLayoutRouteImport.update({ id: '/_second', getParentRoute: () => layoutFirstLayoutRoute, } as any) -const postsPostsHomeRoute = postsPostsHomeImport.update({ +const postsPostsHomeRoute = postsPostsHomeRouteImport.update({ id: '/', path: '/', getParentRoute: () => postsPostsRoute, } as any) -const ClassicHelloRouteRoute = ClassicHelloRouteImport.update({ +const ClassicHelloRouteRoute = ClassicHelloRouteRouteImport.update({ id: '/classic/hello', path: '/classic/hello', getParentRoute: () => rootRoute, } as any) -const ClassicHelloIndexRoute = ClassicHelloIndexImport.update({ +const ClassicHelloIndexRoute = ClassicHelloIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => ClassicHelloRouteRoute, } as any) -const ClassicHelloWorldRoute = ClassicHelloWorldImport.update({ +const ClassicHelloWorldRoute = ClassicHelloWorldRouteImport.update({ id: '/world', path: '/world', getParentRoute: () => ClassicHelloRouteRoute, } as any) -const ClassicHelloUniverseRoute = ClassicHelloUniverseImport.update({ +const ClassicHelloUniverseRoute = ClassicHelloUniverseRouteImport.update({ id: '/universe', path: '/universe', getParentRoute: () => ClassicHelloRouteRoute, } as any) -const bRoute = bImport.update({ +const bRoute = bRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => layoutSecondLayoutRoute, } as any) -const aRoute = aImport.update({ +const aRoute = aRouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => layoutSecondLayoutRoute, @@ -104,89 +106,200 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof homeImport + preLoaderRoute: typeof homeRouteImport parentRoute: typeof rootRoute } '/_first': { id: '/_first' path: '' fullPath: '' - preLoaderRoute: typeof layoutFirstLayoutImport + preLoaderRoute: typeof layoutFirstLayoutRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof postsPostsImport + preLoaderRoute: typeof postsPostsRouteImport parentRoute: typeof rootRoute } '/classic/hello': { id: '/classic/hello' path: '/classic/hello' fullPath: '/classic/hello' - preLoaderRoute: typeof ClassicHelloRouteImport + preLoaderRoute: typeof ClassicHelloRouteRouteImport parentRoute: typeof rootRoute } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof postsPostsHomeImport - parentRoute: typeof postsPostsImport + preLoaderRoute: typeof postsPostsHomeRouteImport + parentRoute: typeof postsPostsRouteImport } '/_first/_second': { id: '/_first/_second' path: '' fullPath: '' - preLoaderRoute: typeof layoutSecondLayoutImport - parentRoute: typeof layoutFirstLayoutImport + preLoaderRoute: typeof layoutSecondLayoutRouteImport + parentRoute: typeof layoutFirstLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof postsPostsDetailImport - parentRoute: typeof postsPostsImport + preLoaderRoute: typeof postsPostsDetailRouteImport + parentRoute: typeof postsPostsRouteImport } '/_first/_second/layout-a': { id: '/_first/_second/layout-a' path: '/layout-a' fullPath: '/layout-a' - preLoaderRoute: typeof aImport - parentRoute: typeof layoutSecondLayoutImport + preLoaderRoute: typeof aRouteImport + parentRoute: typeof layoutSecondLayoutRouteImport } '/_first/_second/layout-b': { id: '/_first/_second/layout-b' path: '/layout-b' fullPath: '/layout-b' - preLoaderRoute: typeof bImport - parentRoute: typeof layoutSecondLayoutImport + preLoaderRoute: typeof bRouteImport + parentRoute: typeof layoutSecondLayoutRouteImport } '/classic/hello/universe': { id: '/classic/hello/universe' path: '/universe' fullPath: '/classic/hello/universe' - preLoaderRoute: typeof ClassicHelloUniverseImport - parentRoute: typeof ClassicHelloRouteImport + preLoaderRoute: typeof ClassicHelloUniverseRouteImport + parentRoute: typeof ClassicHelloRouteRouteImport } '/classic/hello/world': { id: '/classic/hello/world' path: '/world' fullPath: '/classic/hello/world' - preLoaderRoute: typeof ClassicHelloWorldImport - parentRoute: typeof ClassicHelloRouteImport + preLoaderRoute: typeof ClassicHelloWorldRouteImport + parentRoute: typeof ClassicHelloRouteRouteImport } '/classic/hello/': { id: '/classic/hello/' path: '/' fullPath: '/classic/hello/' - preLoaderRoute: typeof ClassicHelloIndexImport - parentRoute: typeof ClassicHelloRouteImport + preLoaderRoute: typeof ClassicHelloIndexRouteImport + parentRoute: typeof ClassicHelloRouteRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/home' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/layout/first-layout' { + const createFileRoute: CreateFileRoute< + '/_first', + FileRoutesByPath['/_first']['parentRoute'], + FileRoutesByPath['/_first']['id'], + FileRoutesByPath['/_first']['path'], + FileRoutesByPath['/_first']['fullPath'] + > +} +declare module './routes/posts/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/route' { + const createFileRoute: CreateFileRoute< + '/classic/hello', + FileRoutesByPath['/classic/hello']['parentRoute'], + FileRoutesByPath['/classic/hello']['id'], + FileRoutesByPath['/classic/hello']['path'], + FileRoutesByPath['/classic/hello']['fullPath'] + > +} +declare module './routes/posts/posts-home' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/layout/second-layout' { + const createFileRoute: CreateFileRoute< + '/_first/_second', + FileRoutesByPath['/_first/_second']['parentRoute'], + FileRoutesByPath['/_first/_second']['id'], + FileRoutesByPath['/_first/_second']['path'], + FileRoutesByPath['/_first/_second']['fullPath'] + > +} +declare module './routes/posts/posts-detail' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/a' { + const createFileRoute: CreateFileRoute< + '/_first/_second/layout-a', + FileRoutesByPath['/_first/_second/layout-a']['parentRoute'], + FileRoutesByPath['/_first/_second/layout-a']['id'], + FileRoutesByPath['/_first/_second/layout-a']['path'], + FileRoutesByPath['/_first/_second/layout-a']['fullPath'] + > +} +declare module './routes/b' { + const createFileRoute: CreateFileRoute< + '/_first/_second/layout-b', + FileRoutesByPath['/_first/_second/layout-b']['parentRoute'], + FileRoutesByPath['/_first/_second/layout-b']['id'], + FileRoutesByPath['/_first/_second/layout-b']['path'], + FileRoutesByPath['/_first/_second/layout-b']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/universe' { + const createFileRoute: CreateFileRoute< + '/classic/hello/universe', + FileRoutesByPath['/classic/hello/universe']['parentRoute'], + FileRoutesByPath['/classic/hello/universe']['id'], + FileRoutesByPath['/classic/hello/universe']['path'], + FileRoutesByPath['/classic/hello/universe']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/world' { + const createFileRoute: CreateFileRoute< + '/classic/hello/world', + FileRoutesByPath['/classic/hello/world']['parentRoute'], + FileRoutesByPath['/classic/hello/world']['id'], + FileRoutesByPath['/classic/hello/world']['path'], + FileRoutesByPath['/classic/hello/world']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/index' { + const createFileRoute: CreateFileRoute< + '/classic/hello/', + FileRoutesByPath['/classic/hello/']['parentRoute'], + FileRoutesByPath['/classic/hello/']['id'], + FileRoutesByPath['/classic/hello/']['path'], + FileRoutesByPath['/classic/hello/']['fullPath'] + > +} + // Create and export the route tree interface layoutSecondLayoutRouteChildren { diff --git a/e2e/react-router/basic-virtual-file-based/src/routes/a.tsx b/e2e/react-router/basic-virtual-file-based/src/routes/a.tsx index 6cccd02950..a190b24202 100644 --- a/e2e/react-router/basic-virtual-file-based/src/routes/a.tsx +++ b/e2e/react-router/basic-virtual-file-based/src/routes/a.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_first/_second/layout-a')({ +export const Route = createFileRoute({ component: LayoutAComponent, }) diff --git a/e2e/react-router/basic-virtual-file-based/src/routes/b.tsx b/e2e/react-router/basic-virtual-file-based/src/routes/b.tsx index 98bb842612..505f8f6fbf 100644 --- a/e2e/react-router/basic-virtual-file-based/src/routes/b.tsx +++ b/e2e/react-router/basic-virtual-file-based/src/routes/b.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_first/_second/layout-b')({ +export const Route = createFileRoute({ component: LayoutBComponent, }) diff --git a/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/index.tsx b/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/index.tsx index c7417e5eeb..f86335e291 100644 --- a/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/index.tsx +++ b/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/classic/hello/')({ +export const Route = createFileRoute({ component: () =>
This is the index
, }) diff --git a/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/route.tsx b/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/route.tsx index 566efc8777..620dd2b76b 100644 --- a/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/route.tsx +++ b/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/route.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/classic/hello')({ +export const Route = createFileRoute({ component: () => (
Hello! diff --git a/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/universe.tsx b/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/universe.tsx index e00c47d74b..20b07c41cc 100644 --- a/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/universe.tsx +++ b/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/universe.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/classic/hello/universe')({ +export const Route = createFileRoute({ component: () =>
Hello /classic/hello/universe!
, }) diff --git a/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/world.tsx b/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/world.tsx index 9783557342..4af11357a2 100644 --- a/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/world.tsx +++ b/e2e/react-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/world.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/classic/hello/world')({ +export const Route = createFileRoute({ component: () =>
Hello /classic/hello/world!
, }) diff --git a/e2e/react-router/basic-virtual-file-based/src/routes/home.tsx b/e2e/react-router/basic-virtual-file-based/src/routes/home.tsx index eac82a9174..b23956ae17 100644 --- a/e2e/react-router/basic-virtual-file-based/src/routes/home.tsx +++ b/e2e/react-router/basic-virtual-file-based/src/routes/home.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/react-router/basic-virtual-file-based/src/routes/layout/first-layout.tsx b/e2e/react-router/basic-virtual-file-based/src/routes/layout/first-layout.tsx index d39e206f2d..5c4a461d8d 100644 --- a/e2e/react-router/basic-virtual-file-based/src/routes/layout/first-layout.tsx +++ b/e2e/react-router/basic-virtual-file-based/src/routes/layout/first-layout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_first')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-router/basic-virtual-file-based/src/routes/layout/second-layout.tsx b/e2e/react-router/basic-virtual-file-based/src/routes/layout/second-layout.tsx index ef178a6e16..483b910862 100644 --- a/e2e/react-router/basic-virtual-file-based/src/routes/layout/second-layout.tsx +++ b/e2e/react-router/basic-virtual-file-based/src/routes/layout/second-layout.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_first/_second')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-router/basic-virtual-file-based/src/routes/posts/posts-detail.tsx b/e2e/react-router/basic-virtual-file-based/src/routes/posts/posts-detail.tsx index 948d52d6d6..654f3cfd18 100644 --- a/e2e/react-router/basic-virtual-file-based/src/routes/posts/posts-detail.tsx +++ b/e2e/react-router/basic-virtual-file-based/src/routes/posts/posts-detail.tsx @@ -1,9 +1,9 @@ import * as React from 'react' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import { fetchPost } from '../../posts' import type { ErrorComponentProps } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost(postId), errorComponent: PostErrorComponent as any, notFoundComponent: () => { diff --git a/e2e/react-router/basic-virtual-file-based/src/routes/posts/posts-home.tsx b/e2e/react-router/basic-virtual-file-based/src/routes/posts/posts-home.tsx index 056433ca0a..fdbe5865e5 100644 --- a/e2e/react-router/basic-virtual-file-based/src/routes/posts/posts-home.tsx +++ b/e2e/react-router/basic-virtual-file-based/src/routes/posts/posts-home.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/e2e/react-router/basic-virtual-file-based/src/routes/posts/posts.tsx b/e2e/react-router/basic-virtual-file-based/src/routes/posts/posts.tsx index a2ab1ee388..f92c37f537 100644 --- a/e2e/react-router/basic-virtual-file-based/src/routes/posts/posts.tsx +++ b/e2e/react-router/basic-virtual-file-based/src/routes/posts/posts.tsx @@ -1,8 +1,8 @@ import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../../posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: fetchPosts, component: PostsComponent, }) diff --git a/e2e/react-router/basic-virtual-file-based/vite.config.ts b/e2e/react-router/basic-virtual-file-based/vite.config.ts index 937f1f853c..8a28af1709 100644 --- a/e2e/react-router/basic-virtual-file-based/vite.config.ts +++ b/e2e/react-router/basic-virtual-file-based/vite.config.ts @@ -1,14 +1,15 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' import { routes } from './routes' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'react', autoCodeSplitting: true, + verboseFileRoutes: false, virtualRouteConfig: routes, }), react(), diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/package.json b/e2e/react-router/basic-virtual-named-export-config-file-based/package.json index e8548b0db3..ebf75bc3b7 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/package.json +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/package.json @@ -29,6 +29,6 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/a.tsx b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/a.tsx index 6cccd02950..a190b24202 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/a.tsx +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/a.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_first/_second/layout-a')({ +export const Route = createFileRoute({ component: LayoutAComponent, }) diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/b.tsx b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/b.tsx index 98bb842612..505f8f6fbf 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/b.tsx +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/b.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_first/_second/layout-b')({ +export const Route = createFileRoute({ component: LayoutBComponent, }) diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx index c7417e5eeb..f86335e291 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/classic/hello/')({ +export const Route = createFileRoute({ component: () =>
This is the index
, }) diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx index 566efc8777..620dd2b76b 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/classic/hello')({ +export const Route = createFileRoute({ component: () => (
Hello! diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx index e00c47d74b..20b07c41cc 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/classic/hello/universe')({ +export const Route = createFileRoute({ component: () =>
Hello /classic/hello/universe!
, }) diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx index 9783557342..4af11357a2 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/classic/hello/world')({ +export const Route = createFileRoute({ component: () =>
Hello /classic/hello/world!
, }) diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/home.tsx b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/home.tsx index eac82a9174..b23956ae17 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/home.tsx +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/home.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx index d39e206f2d..5c4a461d8d 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_first')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx index ef178a6e16..483b910862 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_first/_second')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx index 948d52d6d6..654f3cfd18 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx @@ -1,9 +1,9 @@ import * as React from 'react' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import { fetchPost } from '../../posts' import type { ErrorComponentProps } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost(postId), errorComponent: PostErrorComponent as any, notFoundComponent: () => { diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx index 056433ca0a..fdbe5865e5 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx index a2ab1ee388..f92c37f537 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx @@ -1,8 +1,8 @@ import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../../posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: fetchPosts, component: PostsComponent, }) diff --git a/e2e/react-router/basic-virtual-named-export-config-file-based/vite.config.ts b/e2e/react-router/basic-virtual-named-export-config-file-based/vite.config.ts index a04fbc2dcb..ea7fb55e88 100644 --- a/e2e/react-router/basic-virtual-named-export-config-file-based/vite.config.ts +++ b/e2e/react-router/basic-virtual-named-export-config-file-based/vite.config.ts @@ -1,13 +1,14 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'react', autoCodeSplitting: true, + verboseFileRoutes: false, virtualRouteConfig: './routes.ts', }), react(), diff --git a/e2e/react-router/basic/package.json b/e2e/react-router/basic/package.json index 74d93cc3b2..33cfccc9d8 100644 --- a/e2e/react-router/basic/package.json +++ b/e2e/react-router/basic/package.json @@ -26,6 +26,6 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/react-router/basic/src/main.tsx b/e2e/react-router/basic/src/main.tsx index 2ffee37679..8bd8d5afcf 100644 --- a/e2e/react-router/basic/src/main.tsx +++ b/e2e/react-router/basic/src/main.tsx @@ -7,6 +7,7 @@ import { createRootRoute, createRoute, createRouter, + redirect, } from '@tanstack/react-router' import { TanStackRouterDevtools } from '@tanstack/react-router-devtools' import { NotFoundError, fetchPost, fetchPosts } from './posts' @@ -205,11 +206,213 @@ function LayoutBComponent() { return
I'm layout B!
} +const paramsPsRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/params-ps', +}) + +const paramsPsIndexRoute = createRoute({ + getParentRoute: () => paramsPsRoute, + path: '/', + component: function ParamsIndex() { + return ( +
+

Named path params

+
    +
  • + + /params-ps/named/$foo + +
  • +
  • + + /params-ps/named/{'prefix{$foo}'} + +
  • +
  • + + /params-ps/named/{'{$foo}suffix'} + +
  • +
+
+

Wildcard path params

+
    +
  • + + /params-ps/wildcard/$ + +
  • +
  • + + /params-ps/wildcard/{'prefix{$}'} + +
  • +
  • + + /params-ps/wildcard/{'{$}suffix'} + +
  • +
+
+ ) + }, +}) + +const paramsPsNamedRoute = createRoute({ + getParentRoute: () => paramsPsRoute, + path: '/named', +}) + +const paramsPsNamedIndexRoute = createRoute({ + getParentRoute: () => paramsPsNamedRoute, + path: '/', + beforeLoad: () => { + throw redirect({ to: '/params-ps' }) + }, +}) + +const paramsPsNamedFooRoute = createRoute({ + getParentRoute: () => paramsPsNamedRoute, + path: '/$foo', + component: function ParamsNamedFoo() { + const p = paramsPsNamedFooRoute.useParams() + return ( +
+

ParamsNamedFoo

+
{JSON.stringify(p)}
+
+ ) + }, +}) + +const paramsPsNamedFooPrefixRoute = createRoute({ + getParentRoute: () => paramsPsNamedRoute, + path: '/prefix{$foo}', + component: function ParamsNamedFooMarkdown() { + const p = paramsPsNamedFooPrefixRoute.useParams() + return ( +
+

ParamsNamedFooPrefix

+
{JSON.stringify(p)}
+
+ ) + }, +}) + +const paramsPsNamedFooSuffixRoute = createRoute({ + getParentRoute: () => paramsPsNamedRoute, + path: '/{$foo}suffix', + component: function ParamsNamedFooSuffix() { + const p = paramsPsNamedFooSuffixRoute.useParams() + return ( +
+

ParamsNamedFooSuffix

+
{JSON.stringify(p)}
+
+ ) + }, +}) + +const paramsPsWildcardRoute = createRoute({ + getParentRoute: () => paramsPsRoute, + path: '/wildcard', +}) + +const paramsPsWildcardIndexRoute = createRoute({ + getParentRoute: () => paramsPsWildcardRoute, + path: '/', + beforeLoad: () => { + throw redirect({ to: '/params-ps' }) + }, +}) + +const paramsPsWildcardSplatRoute = createRoute({ + getParentRoute: () => paramsPsWildcardRoute, + path: '$', + component: function ParamsWildcardSplat() { + const p = paramsPsWildcardSplatRoute.useParams() + return ( +
+

ParamsWildcardSplat

+
{JSON.stringify(p)}
+
+ ) + }, +}) + +const paramsPsWildcardSplatPrefixRoute = createRoute({ + getParentRoute: () => paramsPsWildcardRoute, + path: 'prefix{$}', + component: function ParamsWildcardSplatPrefix() { + const p = paramsPsWildcardSplatPrefixRoute.useParams() + return ( +
+

ParamsWildcardSplatPrefix

+
{JSON.stringify(p)}
+
+ ) + }, +}) + +const paramsPsWildcardSplatSuffixRoute = createRoute({ + getParentRoute: () => paramsPsWildcardRoute, + path: '{$}suffix', + component: function ParamsWildcardSplatSuffix() { + const p = paramsPsWildcardSplatSuffixRoute.useParams() + return ( +
+

ParamsWildcardSplatSuffix

+
{JSON.stringify(p)}
+
+ ) + }, +}) + const routeTree = rootRoute.addChildren([ postsRoute.addChildren([postRoute, postsIndexRoute]), layoutRoute.addChildren([ layout2Route.addChildren([layoutARoute, layoutBRoute]), ]), + paramsPsRoute.addChildren([ + paramsPsNamedRoute.addChildren([ + paramsPsNamedFooPrefixRoute, + paramsPsNamedFooSuffixRoute, + paramsPsNamedFooRoute, + paramsPsNamedIndexRoute, + ]), + paramsPsWildcardRoute.addChildren([ + paramsPsWildcardSplatRoute, + paramsPsWildcardSplatPrefixRoute, + paramsPsWildcardSplatSuffixRoute, + paramsPsWildcardIndexRoute, + ]), + paramsPsIndexRoute, + ]), indexRoute, ]) diff --git a/e2e/react-router/basic/tests/params.spec.ts b/e2e/react-router/basic/tests/params.spec.ts new file mode 100644 index 0000000000..ac18f39864 --- /dev/null +++ b/e2e/react-router/basic/tests/params.spec.ts @@ -0,0 +1,149 @@ +import { expect, test } from '@playwright/test' + +test.describe('params operations + prefix/suffix', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/params-ps') + }) + + test.describe('named params', () => { + const NAMED_PARAMS_PAIRS = [ + // Test ID | Expected href + { + id: 'l-to-named-foo', + pathname: '/params-ps/named/foo', + params: { foo: 'foo' }, + destHeadingId: 'ParamsNamedFoo', + }, + { + id: 'l-to-named-prefixfoo', + pathname: '/params-ps/named/prefixfoo', + params: { foo: 'foo' }, + destHeadingId: 'ParamsNamedFooPrefix', + }, + { + id: 'l-to-named-foosuffix', + pathname: '/params-ps/named/foosuffix', + params: { foo: 'foo' }, + destHeadingId: 'ParamsNamedFooSuffix', + }, + ] satisfies Array<{ + id: string + pathname: string + params: Record + destHeadingId: string + }> + + test.describe('Link', () => { + NAMED_PARAMS_PAIRS.forEach(({ id, pathname }) => { + test(`interpolation for testid="${id}" has href="${pathname}"`, async ({ + page, + }) => { + const link = page.getByTestId(id) + await expect(link).toHaveAttribute('href', pathname) + }) + }) + + NAMED_PARAMS_PAIRS.forEach(({ id, pathname }) => { + test(`navigation for testid="${id}" succeeds to href="${pathname}"`, async ({ + page, + }) => { + const link = page.getByTestId(id) + await link.click() + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe(pathname) + }) + }) + }) + + NAMED_PARAMS_PAIRS.forEach(({ pathname, params, destHeadingId }) => { + test(`on first-load to "${pathname}" has correct params`, async ({ + page, + }) => { + await page.goto(pathname) + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe(pathname) + + const headingEl = page.getByRole('heading', { name: destHeadingId }) + await expect(headingEl).toBeVisible() + + const paramsEl = page.getByTestId('params-output') + const paramsText = await paramsEl.innerText() + const paramsObj = JSON.parse(paramsText) + expect(paramsObj).toEqual(params) + }) + }) + }) + + test.describe('wildcard param', () => { + const WILDCARD_PARAM_PAIRS = [ + // Test ID | Expected href + { + id: 'l-to-wildcard-foo', + pathname: '/params-ps/wildcard/foo', + params: { '*': 'foo', _splat: 'foo' }, + destHeadingId: 'ParamsWildcardSplat', + }, + { + id: 'l-to-wildcard-prefixfoo', + pathname: '/params-ps/wildcard/prefixfoo', + params: { '*': 'foo', _splat: 'foo' }, + destHeadingId: 'ParamsWildcardSplatPrefix', + }, + { + id: 'l-to-wildcard-foosuffix', + pathname: '/params-ps/wildcard/foosuffix', + params: { '*': 'foo', _splat: 'foo' }, + destHeadingId: 'ParamsWildcardSplatSuffix', + }, + ] satisfies Array<{ + id: string + pathname: string + params: Record + destHeadingId: string + }> + + test.describe('Link', () => { + WILDCARD_PARAM_PAIRS.forEach(({ id, pathname }) => { + test(`interpolation for testid="${id}" has href="${pathname}"`, async ({ + page, + }) => { + const link = page.getByTestId(id) + await expect(link).toHaveAttribute('href', pathname) + }) + }) + + WILDCARD_PARAM_PAIRS.forEach(({ id, pathname }) => { + test(`navigation for testid="${id}" succeeds to href="${pathname}"`, async ({ + page, + }) => { + const link = page.getByTestId(id) + await link.click() + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe(pathname) + }) + }) + }) + + WILDCARD_PARAM_PAIRS.forEach(({ pathname, params, destHeadingId }) => { + test(`on first-load to "${pathname}" has correct params`, async ({ + page, + }) => { + await page.goto(pathname) + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe(pathname) + + const headingEl = page.getByRole('heading', { name: destHeadingId }) + await expect(headingEl).toBeVisible() + + const paramsEl = page.getByTestId('params-output') + const paramsText = await paramsEl.innerText() + const paramsObj = JSON.parse(paramsText) + expect(paramsObj).toEqual(params) + }) + }) + }) +}) diff --git a/e2e/react-router/generator-cli-only/package.json b/e2e/react-router/generator-cli-only/package.json index b2877d0483..2a6a1359fb 100644 --- a/e2e/react-router/generator-cli-only/package.json +++ b/e2e/react-router/generator-cli-only/package.json @@ -27,6 +27,6 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/react-router/generator-cli-only/src/routeTree.gen.ts b/e2e/react-router/generator-cli-only/src/routeTree.gen.ts index 1ecbd67da9..b1a2b0fa0a 100644 --- a/e2e/react-router/generator-cli-only/src/routeTree.gen.ts +++ b/e2e/react-router/generator-cli-only/src/routeTree.gen.ts @@ -11,62 +11,61 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as PostsRouteImport } from './routes/posts.route' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as PathlessLayoutNestedLayoutImport } from './routes/_pathlessLayout/_nested-layout' -import { Route as PathlessLayoutNestedLayoutRouteBImport } from './routes/_pathlessLayout/_nested-layout/route-b' -import { Route as PathlessLayoutNestedLayoutRouteAImport } from './routes/_pathlessLayout/_nested-layout/route-a' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as PostsRouteRouteImport } from './routes/posts.route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' +import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' +import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' // Create/Update Routes -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const PostsRouteRoute = PostsRouteImport.update({ +const PostsRouteRoute = PostsRouteRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRouteRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRouteRoute, } as any) -const PathlessLayoutNestedLayoutRoute = PathlessLayoutNestedLayoutImport.update( - { +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ id: '/_nested-layout', getParentRoute: () => PathlessLayoutRoute, - } as any, -) + } as any) const PathlessLayoutNestedLayoutRouteBRoute = - PathlessLayoutNestedLayoutRouteBImport.update({ + PathlessLayoutNestedLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutNestedLayoutRoute, } as any) const PathlessLayoutNestedLayoutRouteARoute = - PathlessLayoutNestedLayoutRouteAImport.update({ + PathlessLayoutNestedLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutNestedLayoutRoute, @@ -80,57 +79,57 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsRouteRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout/_nested-layout': { id: '/_pathlessLayout/_nested-layout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutNestedLayoutImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteRouteImport } '/_pathlessLayout/_nested-layout/route-a': { id: '/_pathlessLayout/_nested-layout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteAImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/_pathlessLayout/_nested-layout/route-b': { id: '/_pathlessLayout/_nested-layout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } } } diff --git a/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout.tsx b/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout.tsx index 202070f1ff..1e1ef2ebe1 100644 --- a/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout.tsx +++ b/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_pathlessLayout')({ component: LayoutComponent, diff --git a/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout/_nested-layout.tsx b/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout/_nested-layout.tsx index c5bcffd5a4..9c345694ab 100644 --- a/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout/_nested-layout.tsx +++ b/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout/_nested-layout.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({ component: LayoutComponent, diff --git a/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout/_nested-layout/route-a.tsx index 5649f77d8e..6b59dbc46f 100644 --- a/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +++ b/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout/_nested-layout/route-a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')( { component: LayoutAComponent, diff --git a/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout/_nested-layout/route-b.tsx index 742e48bfb4..50f864f617 100644 --- a/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +++ b/e2e/react-router/generator-cli-only/src/routes/_pathlessLayout/_nested-layout/route-b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')( { component: LayoutBComponent, diff --git a/e2e/react-router/generator-cli-only/src/routes/index.tsx b/e2e/react-router/generator-cli-only/src/routes/index.tsx index eac82a9174..0a5b7572ba 100644 --- a/e2e/react-router/generator-cli-only/src/routes/index.tsx +++ b/e2e/react-router/generator-cli-only/src/routes/index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/')({ component: Home, diff --git a/e2e/react-router/generator-cli-only/src/routes/posts.$postId.tsx b/e2e/react-router/generator-cli-only/src/routes/posts.$postId.tsx index cded91ef96..956ca50ecd 100644 --- a/e2e/react-router/generator-cli-only/src/routes/posts.$postId.tsx +++ b/e2e/react-router/generator-cli-only/src/routes/posts.$postId.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import { fetchPost } from '../posts' import type { ErrorComponentProps } from '@tanstack/react-router' diff --git a/e2e/react-router/generator-cli-only/src/routes/posts.index.tsx b/e2e/react-router/generator-cli-only/src/routes/posts.index.tsx index 056433ca0a..c6b65f1892 100644 --- a/e2e/react-router/generator-cli-only/src/routes/posts.index.tsx +++ b/e2e/react-router/generator-cli-only/src/routes/posts.index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, diff --git a/e2e/react-router/generator-cli-only/src/routes/posts.route.tsx b/e2e/react-router/generator-cli-only/src/routes/posts.route.tsx index 0115fc8063..ab5c2ac99f 100644 --- a/e2e/react-router/generator-cli-only/src/routes/posts.route.tsx +++ b/e2e/react-router/generator-cli-only/src/routes/posts.route.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../posts' export const Route = createFileRoute('/posts')({ diff --git a/e2e/react-router/js-only-file-based/package.json b/e2e/react-router/js-only-file-based/package.json index bd2286b5bb..e53f0521d1 100644 --- a/e2e/react-router/js-only-file-based/package.json +++ b/e2e/react-router/js-only-file-based/package.json @@ -27,6 +27,6 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/react-router/js-only-file-based/src/routeTree.gen.js b/e2e/react-router/js-only-file-based/src/routeTree.gen.js index c98d6e89eb..d730c68ee9 100644 --- a/e2e/react-router/js-only-file-based/src/routeTree.gen.js +++ b/e2e/react-router/js-only-file-based/src/routeTree.gen.js @@ -11,62 +11,61 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as PostsRouteImport } from './routes/posts.route' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as PathlessLayoutNestedLayoutImport } from './routes/_pathlessLayout/_nested-layout' -import { Route as PathlessLayoutNestedLayoutRouteBImport } from './routes/_pathlessLayout/_nested-layout/route-b' -import { Route as PathlessLayoutNestedLayoutRouteAImport } from './routes/_pathlessLayout/_nested-layout/route-a' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as PostsRouteRouteImport } from './routes/posts.route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' +import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' +import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' // Create/Update Routes -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, }) -const PostsRouteRoute = PostsRouteImport.update({ +const PostsRouteRoute = PostsRouteRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, }) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, }) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRouteRoute, }) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRouteRoute, }) -const PathlessLayoutNestedLayoutRoute = PathlessLayoutNestedLayoutImport.update( - { +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ id: '/_nested-layout', getParentRoute: () => PathlessLayoutRoute, - }, -) + }) const PathlessLayoutNestedLayoutRouteBRoute = - PathlessLayoutNestedLayoutRouteBImport.update({ + PathlessLayoutNestedLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutNestedLayoutRoute, }) const PathlessLayoutNestedLayoutRouteARoute = - PathlessLayoutNestedLayoutRouteAImport.update({ + PathlessLayoutNestedLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutNestedLayoutRoute, diff --git a/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout.jsx b/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout.jsx index 202070f1ff..1e1ef2ebe1 100644 --- a/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout.jsx +++ b/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout.jsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_pathlessLayout')({ component: LayoutComponent, diff --git a/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout/_nested-layout.jsx b/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout/_nested-layout.jsx index c5bcffd5a4..9c345694ab 100644 --- a/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout/_nested-layout.jsx +++ b/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout/_nested-layout.jsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({ component: LayoutComponent, diff --git a/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.jsx b/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.jsx index 5649f77d8e..6b59dbc46f 100644 --- a/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.jsx +++ b/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.jsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')( { component: LayoutAComponent, diff --git a/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.jsx b/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.jsx index 742e48bfb4..50f864f617 100644 --- a/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.jsx +++ b/e2e/react-router/js-only-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.jsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')( { component: LayoutBComponent, diff --git a/e2e/react-router/js-only-file-based/src/routes/index.jsx b/e2e/react-router/js-only-file-based/src/routes/index.jsx index eac82a9174..0a5b7572ba 100644 --- a/e2e/react-router/js-only-file-based/src/routes/index.jsx +++ b/e2e/react-router/js-only-file-based/src/routes/index.jsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/')({ component: Home, diff --git a/e2e/react-router/js-only-file-based/src/routes/posts.$postId.jsx b/e2e/react-router/js-only-file-based/src/routes/posts.$postId.jsx index d26d271b9d..0d4b989053 100644 --- a/e2e/react-router/js-only-file-based/src/routes/posts.$postId.jsx +++ b/e2e/react-router/js-only-file-based/src/routes/posts.$postId.jsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import { fetchPost } from '../posts' export const Route = createFileRoute('/posts/$postId')({ diff --git a/e2e/react-router/js-only-file-based/src/routes/posts.index.jsx b/e2e/react-router/js-only-file-based/src/routes/posts.index.jsx index 056433ca0a..c6b65f1892 100644 --- a/e2e/react-router/js-only-file-based/src/routes/posts.index.jsx +++ b/e2e/react-router/js-only-file-based/src/routes/posts.index.jsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, diff --git a/e2e/react-router/js-only-file-based/src/routes/posts.route.jsx b/e2e/react-router/js-only-file-based/src/routes/posts.route.jsx index 0115fc8063..ab5c2ac99f 100644 --- a/e2e/react-router/js-only-file-based/src/routes/posts.route.jsx +++ b/e2e/react-router/js-only-file-based/src/routes/posts.route.jsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../posts' export const Route = createFileRoute('/posts')({ diff --git a/e2e/react-router/js-only-file-based/vite.config.js b/e2e/react-router/js-only-file-based/vite.config.js index 412b7c6338..926b55a02e 100644 --- a/e2e/react-router/js-only-file-based/vite.config.js +++ b/e2e/react-router/js-only-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'react', disableTypes: true, disableManifestGeneration: true, diff --git a/e2e/react-router/rspack-basic-file-based/rsbuild.config.ts b/e2e/react-router/rspack-basic-file-based/rsbuild.config.ts index 0bdde399a7..f52856821e 100644 --- a/e2e/react-router/rspack-basic-file-based/rsbuild.config.ts +++ b/e2e/react-router/rspack-basic-file-based/rsbuild.config.ts @@ -1,13 +1,13 @@ import { defineConfig } from '@rsbuild/core' import { pluginReact } from '@rsbuild/plugin-react' -import { TanStackRouterRspack } from '@tanstack/router-plugin/rspack' +import { tanstackRouter } from '@tanstack/router-plugin/rspack' export default defineConfig({ plugins: [pluginReact()], tools: { rspack: { plugins: [ - TanStackRouterRspack({ + tanstackRouter({ target: 'react', autoCodeSplitting: true, }), diff --git a/e2e/react-router/rspack-basic-file-based/src/routes/_layout.tsx b/e2e/react-router/rspack-basic-file-based/src/routes/_layout.tsx index 02ddbb1cd9..0fcaac3a52 100644 --- a/e2e/react-router/rspack-basic-file-based/src/routes/_layout.tsx +++ b/e2e/react-router/rspack-basic-file-based/src/routes/_layout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_layout')({ component: LayoutComponent, diff --git a/e2e/react-router/rspack-basic-file-based/src/routes/_layout/_layout-2.tsx b/e2e/react-router/rspack-basic-file-based/src/routes/_layout/_layout-2.tsx index 3b7dbf2903..388d0b3b87 100644 --- a/e2e/react-router/rspack-basic-file-based/src/routes/_layout/_layout-2.tsx +++ b/e2e/react-router/rspack-basic-file-based/src/routes/_layout/_layout-2.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_layout/_layout-2')({ component: LayoutComponent, diff --git a/e2e/react-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx b/e2e/react-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx index 61e19b4d9f..ed2dea8800 100644 --- a/e2e/react-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx +++ b/e2e/react-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ component: LayoutAComponent, }) diff --git a/e2e/react-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx b/e2e/react-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx index cceed1fb9a..4799d403e9 100644 --- a/e2e/react-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx +++ b/e2e/react-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ component: LayoutBComponent, }) diff --git a/e2e/react-router/rspack-basic-file-based/src/routes/index.tsx b/e2e/react-router/rspack-basic-file-based/src/routes/index.tsx index eac82a9174..0a5b7572ba 100644 --- a/e2e/react-router/rspack-basic-file-based/src/routes/index.tsx +++ b/e2e/react-router/rspack-basic-file-based/src/routes/index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/')({ component: Home, diff --git a/e2e/react-router/rspack-basic-file-based/src/routes/posts.$postId.tsx b/e2e/react-router/rspack-basic-file-based/src/routes/posts.$postId.tsx index cded91ef96..956ca50ecd 100644 --- a/e2e/react-router/rspack-basic-file-based/src/routes/posts.$postId.tsx +++ b/e2e/react-router/rspack-basic-file-based/src/routes/posts.$postId.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import { fetchPost } from '../posts' import type { ErrorComponentProps } from '@tanstack/react-router' diff --git a/e2e/react-router/rspack-basic-file-based/src/routes/posts.index.tsx b/e2e/react-router/rspack-basic-file-based/src/routes/posts.index.tsx index 056433ca0a..c6b65f1892 100644 --- a/e2e/react-router/rspack-basic-file-based/src/routes/posts.index.tsx +++ b/e2e/react-router/rspack-basic-file-based/src/routes/posts.index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, diff --git a/e2e/react-router/rspack-basic-file-based/src/routes/posts.tsx b/e2e/react-router/rspack-basic-file-based/src/routes/posts.tsx index c7a09ed7f8..295205ac1c 100644 --- a/e2e/react-router/rspack-basic-file-based/src/routes/posts.tsx +++ b/e2e/react-router/rspack-basic-file-based/src/routes/posts.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../posts' export const Route = createFileRoute('/posts')({ diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/rsbuild.config.ts b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/rsbuild.config.ts index 7cff654e20..61be0d3631 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/rsbuild.config.ts +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/rsbuild.config.ts @@ -1,13 +1,13 @@ import { defineConfig } from '@rsbuild/core' import { pluginReact } from '@rsbuild/plugin-react' -import { TanStackRouterRspack } from '@tanstack/router-plugin/rspack' +import { tanstackRouter } from '@tanstack/router-plugin/rspack' export default defineConfig({ plugins: [pluginReact()], tools: { rspack: { plugins: [ - TanStackRouterRspack({ + tanstackRouter({ target: 'react', autoCodeSplitting: true, virtualRouteConfig: './routes.ts', diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/a.tsx b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/a.tsx index 6cccd02950..b36784f0de 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/a.tsx +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_first/_second/layout-a')({ component: LayoutAComponent, }) diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/b.tsx b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/b.tsx index 98bb842612..eb440b9eb3 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/b.tsx +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_first/_second/layout-b')({ component: LayoutBComponent, }) diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx index c7417e5eeb..0cc76f4a69 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/classic/hello/')({ component: () =>
This is the index
, }) diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx index 566efc8777..9485ec5954 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/classic/hello')({ component: () => ( diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx index e00c47d74b..5aaa7d4fa0 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/classic/hello/universe')({ component: () =>
Hello /classic/hello/universe!
, }) diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx index 9783557342..790d33a838 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/classic/hello/world')({ component: () =>
Hello /classic/hello/world!
, }) diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/home.tsx b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/home.tsx index eac82a9174..0a5b7572ba 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/home.tsx +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/home.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/')({ component: Home, diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx index d39e206f2d..b9551e996d 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_first')({ component: LayoutComponent, diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx index ef178a6e16..7c058919b1 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_first/_second')({ component: LayoutComponent, diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx index 948d52d6d6..d955b379fb 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import { fetchPost } from '../../posts' import type { ErrorComponentProps } from '@tanstack/react-router' diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx index 056433ca0a..c6b65f1892 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, diff --git a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx index a2ab1ee388..3ebc75f079 100644 --- a/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx +++ b/e2e/react-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../../posts' export const Route = createFileRoute('/posts')({ diff --git a/e2e/react-router/scroll-restoration-sandbox-vite/package.json b/e2e/react-router/scroll-restoration-sandbox-vite/package.json index 9382a05e28..86a029d6f0 100644 --- a/e2e/react-router/scroll-restoration-sandbox-vite/package.json +++ b/e2e/react-router/scroll-restoration-sandbox-vite/package.json @@ -32,6 +32,6 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/react-router/scroll-restoration-sandbox-vite/src/routeTree.gen.ts b/e2e/react-router/scroll-restoration-sandbox-vite/src/routeTree.gen.ts index ae605007e3..f2c2f4f72f 100644 --- a/e2e/react-router/scroll-restoration-sandbox-vite/src/routeTree.gen.ts +++ b/e2e/react-router/scroll-restoration-sandbox-vite/src/routeTree.gen.ts @@ -13,25 +13,27 @@ import { createFileRoute } from '@tanstack/react-router' // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' -import { Route as testsPageWithSearchImport } from './routes/(tests)/page-with-search' -import { Route as testsNormalPageImport } from './routes/(tests)/normal-page' -import { Route as testsLazyWithLoaderPageImport } from './routes/(tests)/lazy-with-loader-page' -import { Route as testsLazyPageImport } from './routes/(tests)/lazy-page' +import { Route as IndexRouteImport } from './routes/index' +import { Route as testsPageWithSearchRouteImport } from './routes/(tests)/page-with-search' +import { Route as testsNormalPageRouteImport } from './routes/(tests)/normal-page' +import { Route as testsLazyWithLoaderPageRouteImport } from './routes/(tests)/lazy-with-loader-page' +import { Route as testsLazyPageRouteImport } from './routes/(tests)/lazy-page' // Create Virtual Routes -const testsVirtualPageLazyImport = createFileRoute('/(tests)/virtual-page')() +const testsVirtualPageLazyRouteImport = createFileRoute( + '/(tests)/virtual-page', +)() // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const testsVirtualPageLazyRoute = testsVirtualPageLazyImport +const testsVirtualPageLazyRoute = testsVirtualPageLazyRouteImport .update({ id: '/(tests)/virtual-page', path: '/virtual-page', @@ -39,19 +41,19 @@ const testsVirtualPageLazyRoute = testsVirtualPageLazyImport } as any) .lazy(() => import('./routes/(tests)/virtual-page.lazy').then((d) => d.Route)) -const testsPageWithSearchRoute = testsPageWithSearchImport.update({ +const testsPageWithSearchRoute = testsPageWithSearchRouteImport.update({ id: '/(tests)/page-with-search', path: '/page-with-search', getParentRoute: () => rootRoute, } as any) -const testsNormalPageRoute = testsNormalPageImport.update({ +const testsNormalPageRoute = testsNormalPageRouteImport.update({ id: '/(tests)/normal-page', path: '/normal-page', getParentRoute: () => rootRoute, } as any) -const testsLazyWithLoaderPageRoute = testsLazyWithLoaderPageImport +const testsLazyWithLoaderPageRoute = testsLazyWithLoaderPageRouteImport .update({ id: '/(tests)/lazy-with-loader-page', path: '/lazy-with-loader-page', @@ -61,7 +63,7 @@ const testsLazyWithLoaderPageRoute = testsLazyWithLoaderPageImport import('./routes/(tests)/lazy-with-loader-page.lazy').then((d) => d.Route), ) -const testsLazyPageRoute = testsLazyPageImport +const testsLazyPageRoute = testsLazyPageRouteImport .update({ id: '/(tests)/lazy-page', path: '/lazy-page', @@ -77,42 +79,42 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/(tests)/lazy-page': { id: '/(tests)/lazy-page' path: '/lazy-page' fullPath: '/lazy-page' - preLoaderRoute: typeof testsLazyPageImport + preLoaderRoute: typeof testsLazyPageRouteImport parentRoute: typeof rootRoute } '/(tests)/lazy-with-loader-page': { id: '/(tests)/lazy-with-loader-page' path: '/lazy-with-loader-page' fullPath: '/lazy-with-loader-page' - preLoaderRoute: typeof testsLazyWithLoaderPageImport + preLoaderRoute: typeof testsLazyWithLoaderPageRouteImport parentRoute: typeof rootRoute } '/(tests)/normal-page': { id: '/(tests)/normal-page' path: '/normal-page' fullPath: '/normal-page' - preLoaderRoute: typeof testsNormalPageImport + preLoaderRoute: typeof testsNormalPageRouteImport parentRoute: typeof rootRoute } '/(tests)/page-with-search': { id: '/(tests)/page-with-search' path: '/page-with-search' fullPath: '/page-with-search' - preLoaderRoute: typeof testsPageWithSearchImport + preLoaderRoute: typeof testsPageWithSearchRouteImport parentRoute: typeof rootRoute } '/(tests)/virtual-page': { id: '/(tests)/virtual-page' path: '/virtual-page' fullPath: '/virtual-page' - preLoaderRoute: typeof testsVirtualPageLazyImport + preLoaderRoute: typeof testsVirtualPageLazyRouteImport parentRoute: typeof rootRoute } } diff --git a/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/lazy-page.lazy.tsx b/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/lazy-page.lazy.tsx index d774a43935..e3125409c0 100644 --- a/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/lazy-page.lazy.tsx +++ b/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/lazy-page.lazy.tsx @@ -1,5 +1,6 @@ -import * as React from 'react' import { createLazyFileRoute } from '@tanstack/react-router' +import * as React from 'react' + import { ScrollBlock } from '../-components/scroll-block' export const Route = createLazyFileRoute('/(tests)/lazy-page')({ diff --git a/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/lazy-page.tsx b/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/lazy-page.tsx index 9c59a0d1f1..29e40169bb 100644 --- a/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/lazy-page.tsx +++ b/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/lazy-page.tsx @@ -1,3 +1,2 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/(tests)/lazy-page')({}) diff --git a/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/normal-page.tsx b/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/normal-page.tsx index 95fb7e119e..e8fc66cad9 100644 --- a/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/normal-page.tsx +++ b/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/normal-page.tsx @@ -1,5 +1,6 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' + import { ScrollBlock } from '../-components/scroll-block' export const Route = createFileRoute('/(tests)/normal-page')({ diff --git a/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/virtual-page.lazy.tsx b/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/virtual-page.lazy.tsx index aa446121f4..ae144463e8 100644 --- a/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/virtual-page.lazy.tsx +++ b/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/(tests)/virtual-page.lazy.tsx @@ -1,5 +1,6 @@ -import * as React from 'react' import { createLazyFileRoute } from '@tanstack/react-router' +import * as React from 'react' + import { ScrollBlock } from '../-components/scroll-block' export const Route = createLazyFileRoute('/(tests)/virtual-page')({ diff --git a/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/index.tsx b/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/index.tsx index 49f6d4bff0..9b0474a02f 100644 --- a/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/index.tsx +++ b/e2e/react-router/scroll-restoration-sandbox-vite/src/routes/index.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, createFileRoute, linkOptions } from '@tanstack/react-router' +import { Link, linkOptions } from '@tanstack/react-router' export const Route = createFileRoute('/')({ component: HomeComponent, diff --git a/e2e/react-router/scroll-restoration-sandbox-vite/vite.config.js b/e2e/react-router/scroll-restoration-sandbox-vite/vite.config.js index 1a57a64b22..172112dd72 100644 --- a/e2e/react-router/scroll-restoration-sandbox-vite/vite.config.js +++ b/e2e/react-router/scroll-restoration-sandbox-vite/vite.config.js @@ -1,8 +1,8 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ - plugins: [TanStackRouterVite({ target: 'react' }), react()], + plugins: [tanstackRouter({ target: 'react' }), react()], }) diff --git a/e2e/react-router/sentry-integration/package.json b/e2e/react-router/sentry-integration/package.json index 9842315379..75298bba90 100644 --- a/e2e/react-router/sentry-integration/package.json +++ b/e2e/react-router/sentry-integration/package.json @@ -29,6 +29,6 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/react-start/basic-auth/.gitignore b/e2e/react-start/basic-auth/.gitignore index b15fed94e2..75a469e80c 100644 --- a/e2e/react-start/basic-auth/.gitignore +++ b/e2e/react-start/basic-auth/.gitignore @@ -7,13 +7,11 @@ yarn.lock .cache .vercel .output -.vinxi /build/ /api/ /server/build /public/build -.vinxi # Sentry Config File .env.sentry-build-plugin /test-results/ diff --git a/e2e/react-start/basic-auth/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/react-start/basic-auth/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/e2e/react-start/basic-auth/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/react-start/basic-auth/app.config.ts b/e2e/react-start/basic-auth/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/e2e/react-start/basic-auth/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/e2e/react-start/basic-auth/package.json b/e2e/react-start/basic-auth/package.json index bb04401e02..cc62ecd7ff 100644 --- a/e2e/react-start/basic-auth/package.json +++ b/e2e/react-start/basic-auth/package.json @@ -1,13 +1,13 @@ { - "name": "tanstack-start-e2e-basic-auth", + "name": "tanstack-react-start-e2e-basic-auth", "private": true, "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build", + "start": "node .output/server/index.mjs", "prisma-generate": "prisma generate", "test:e2e": "exit 0; pnpm run prisma-generate && playwright test --project=chromium" }, @@ -21,7 +21,7 @@ "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "vite": "^6.3.5" }, "devDependencies": { "@playwright/test": "^1.50.1", @@ -30,8 +30,8 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "postcss": "^8.5.1", "autoprefixer": "^10.4.20", + "postcss": "^8.5.1", "tailwindcss": "^3.4.17", "typescript": "^5.7.2", "vite-tsconfig-paths": "^5.1.4" diff --git a/e2e/react-start/basic-auth/playwright.config.ts b/e2e/react-start/basic-auth/playwright.config.ts index bb77d0cf70..9806e0c136 100644 --- a/e2e/react-start/basic-auth/playwright.config.ts +++ b/e2e/react-start/basic-auth/playwright.config.ts @@ -19,7 +19,7 @@ export default defineConfig({ }, webServer: { - command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm start --port ${PORT}`, + command: `VITE_SERVER_PORT=${PORT} pnpm build && PORT=${PORT} VITE_SERVER_PORT=${PORT} pnpm start`, url: baseURL, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/e2e/react-start/basic-auth/src/client.tsx b/e2e/react-start/basic-auth/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/e2e/react-start/basic-auth/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/basic-auth/src/routeTree.gen.ts b/e2e/react-start/basic-auth/src/routeTree.gen.ts index a37809fd07..664daacd0d 100644 --- a/e2e/react-start/basic-auth/src/routeTree.gen.ts +++ b/e2e/react-start/basic-auth/src/routeTree.gen.ts @@ -8,62 +8,64 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as SignupImport } from './routes/signup' -import { Route as LogoutImport } from './routes/logout' -import { Route as LoginImport } from './routes/login' -import { Route as AuthedImport } from './routes/_authed' -import { Route as IndexImport } from './routes/index' -import { Route as AuthedPostsImport } from './routes/_authed/posts' -import { Route as AuthedPostsIndexImport } from './routes/_authed/posts.index' -import { Route as AuthedPostsPostIdImport } from './routes/_authed/posts.$postId' +import { Route as SignupRouteImport } from './routes/signup' +import { Route as LogoutRouteImport } from './routes/logout' +import { Route as LoginRouteImport } from './routes/login' +import { Route as AuthedRouteImport } from './routes/_authed' +import { Route as IndexRouteImport } from './routes/index' +import { Route as AuthedPostsRouteImport } from './routes/_authed/posts' +import { Route as AuthedPostsIndexRouteImport } from './routes/_authed/posts.index' +import { Route as AuthedPostsPostIdRouteImport } from './routes/_authed/posts.$postId' // Create/Update Routes -const SignupRoute = SignupImport.update({ +const SignupRoute = SignupRouteImport.update({ id: '/signup', path: '/signup', getParentRoute: () => rootRoute, } as any) -const LogoutRoute = LogoutImport.update({ +const LogoutRoute = LogoutRouteImport.update({ id: '/logout', path: '/logout', getParentRoute: () => rootRoute, } as any) -const LoginRoute = LoginImport.update({ +const LoginRoute = LoginRouteImport.update({ id: '/login', path: '/login', getParentRoute: () => rootRoute, } as any) -const AuthedRoute = AuthedImport.update({ +const AuthedRoute = AuthedRouteImport.update({ id: '/_authed', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const AuthedPostsRoute = AuthedPostsImport.update({ +const AuthedPostsRoute = AuthedPostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => AuthedRoute, } as any) -const AuthedPostsIndexRoute = AuthedPostsIndexImport.update({ +const AuthedPostsIndexRoute = AuthedPostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => AuthedPostsRoute, } as any) -const AuthedPostsPostIdRoute = AuthedPostsPostIdImport.update({ +const AuthedPostsPostIdRoute = AuthedPostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => AuthedPostsRoute, @@ -77,61 +79,136 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_authed': { id: '/_authed' path: '' fullPath: '' - preLoaderRoute: typeof AuthedImport + preLoaderRoute: typeof AuthedRouteImport parentRoute: typeof rootRoute } '/login': { id: '/login' path: '/login' fullPath: '/login' - preLoaderRoute: typeof LoginImport + preLoaderRoute: typeof LoginRouteImport parentRoute: typeof rootRoute } '/logout': { id: '/logout' path: '/logout' fullPath: '/logout' - preLoaderRoute: typeof LogoutImport + preLoaderRoute: typeof LogoutRouteImport parentRoute: typeof rootRoute } '/signup': { id: '/signup' path: '/signup' fullPath: '/signup' - preLoaderRoute: typeof SignupImport + preLoaderRoute: typeof SignupRouteImport parentRoute: typeof rootRoute } '/_authed/posts': { id: '/_authed/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof AuthedPostsImport - parentRoute: typeof AuthedImport + preLoaderRoute: typeof AuthedPostsRouteImport + parentRoute: typeof AuthedRouteImport } '/_authed/posts/$postId': { id: '/_authed/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof AuthedPostsPostIdImport - parentRoute: typeof AuthedPostsImport + preLoaderRoute: typeof AuthedPostsPostIdRouteImport + parentRoute: typeof AuthedPostsRouteImport } '/_authed/posts/': { id: '/_authed/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof AuthedPostsIndexImport - parentRoute: typeof AuthedPostsImport + preLoaderRoute: typeof AuthedPostsIndexRouteImport + parentRoute: typeof AuthedPostsRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_authed' { + const createFileRoute: CreateFileRoute< + '/_authed', + FileRoutesByPath['/_authed']['parentRoute'], + FileRoutesByPath['/_authed']['id'], + FileRoutesByPath['/_authed']['path'], + FileRoutesByPath['/_authed']['fullPath'] + > +} +declare module './routes/login' { + const createFileRoute: CreateFileRoute< + '/login', + FileRoutesByPath['/login']['parentRoute'], + FileRoutesByPath['/login']['id'], + FileRoutesByPath['/login']['path'], + FileRoutesByPath['/login']['fullPath'] + > +} +declare module './routes/logout' { + const createFileRoute: CreateFileRoute< + '/logout', + FileRoutesByPath['/logout']['parentRoute'], + FileRoutesByPath['/logout']['id'], + FileRoutesByPath['/logout']['path'], + FileRoutesByPath['/logout']['fullPath'] + > +} +declare module './routes/signup' { + const createFileRoute: CreateFileRoute< + '/signup', + FileRoutesByPath['/signup']['parentRoute'], + FileRoutesByPath['/signup']['id'], + FileRoutesByPath['/signup']['path'], + FileRoutesByPath['/signup']['fullPath'] + > +} +declare module './routes/_authed/posts' { + const createFileRoute: CreateFileRoute< + '/_authed/posts', + FileRoutesByPath['/_authed/posts']['parentRoute'], + FileRoutesByPath['/_authed/posts']['id'], + FileRoutesByPath['/_authed/posts']['path'], + FileRoutesByPath['/_authed/posts']['fullPath'] + > +} +declare module './routes/_authed/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/_authed/posts/$postId', + FileRoutesByPath['/_authed/posts/$postId']['parentRoute'], + FileRoutesByPath['/_authed/posts/$postId']['id'], + FileRoutesByPath['/_authed/posts/$postId']['path'], + FileRoutesByPath['/_authed/posts/$postId']['fullPath'] + > +} +declare module './routes/_authed/posts.index' { + const createFileRoute: CreateFileRoute< + '/_authed/posts/', + FileRoutesByPath['/_authed/posts/']['parentRoute'], + FileRoutesByPath['/_authed/posts/']['id'], + FileRoutesByPath['/_authed/posts/']['path'], + FileRoutesByPath['/_authed/posts/']['fullPath'] + > +} + // Create and export the route tree interface AuthedPostsRouteChildren { diff --git a/e2e/react-start/basic-auth/src/routes/_authed.tsx b/e2e/react-start/basic-auth/src/routes/_authed.tsx index c457cf5e57..10c620a9ae 100644 --- a/e2e/react-start/basic-auth/src/routes/_authed.tsx +++ b/e2e/react-start/basic-auth/src/routes/_authed.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import { hashPassword, prismaClient } from '~/utils/prisma' @@ -45,7 +44,7 @@ export const loginFn = createServerFn({ }) }) -export const Route = createFileRoute('/_authed')({ +export const Route = createFileRoute({ beforeLoad: ({ context }) => { if (!context.user) { throw new Error('Not authenticated') diff --git a/e2e/react-start/basic-auth/src/routes/_authed/posts.$postId.tsx b/e2e/react-start/basic-auth/src/routes/_authed/posts.$postId.tsx index 27296b9658..49cad9b374 100644 --- a/e2e/react-start/basic-auth/src/routes/_authed/posts.$postId.tsx +++ b/e2e/react-start/basic-auth/src/routes/_authed/posts.$postId.tsx @@ -1,10 +1,10 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import type { ErrorComponentProps } from '@tanstack/react-router' import { NotFound } from '~/components/NotFound.js' import { fetchPost } from '~/utils/posts.js' -export const Route = createFileRoute('/_authed/posts/$postId')({ +export const Route = createFileRoute({ loader: ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, diff --git a/e2e/react-start/basic-auth/src/routes/_authed/posts.index.tsx b/e2e/react-start/basic-auth/src/routes/_authed/posts.index.tsx index ea9e667e54..13529228bb 100644 --- a/e2e/react-start/basic-auth/src/routes/_authed/posts.index.tsx +++ b/e2e/react-start/basic-auth/src/routes/_authed/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_authed/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/e2e/react-start/basic-auth/src/routes/_authed/posts.tsx b/e2e/react-start/basic-auth/src/routes/_authed/posts.tsx index c01f12c49a..6c37957e8c 100644 --- a/e2e/react-start/basic-auth/src/routes/_authed/posts.tsx +++ b/e2e/react-start/basic-auth/src/routes/_authed/posts.tsx @@ -1,8 +1,8 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '~/utils/posts.js' -export const Route = createFileRoute('/_authed/posts')({ +export const Route = createFileRoute({ loader: () => fetchPosts(), component: PostsComponent, }) diff --git a/e2e/react-start/basic-auth/src/routes/index.tsx b/e2e/react-start/basic-auth/src/routes/index.tsx index 09a907cb18..f6c5b98b02 100644 --- a/e2e/react-start/basic-auth/src/routes/index.tsx +++ b/e2e/react-start/basic-auth/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/react-start/basic-auth/src/routes/login.tsx b/e2e/react-start/basic-auth/src/routes/login.tsx index 19dc34a439..269ca5e816 100644 --- a/e2e/react-start/basic-auth/src/routes/login.tsx +++ b/e2e/react-start/basic-auth/src/routes/login.tsx @@ -1,8 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' - import { Login } from '~/components/Login' -export const Route = createFileRoute('/login')({ +export const Route = createFileRoute({ component: LoginComp, }) diff --git a/e2e/react-start/basic-auth/src/routes/logout.tsx b/e2e/react-start/basic-auth/src/routes/logout.tsx index 43a14fa39a..43553a6290 100644 --- a/e2e/react-start/basic-auth/src/routes/logout.tsx +++ b/e2e/react-start/basic-auth/src/routes/logout.tsx @@ -1,4 +1,4 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import { useAppSession } from '~/utils/session' @@ -13,7 +13,7 @@ const logoutFn = createServerFn({ method: 'POST' }).handler(async () => { }) }) -export const Route = createFileRoute('/logout')({ +export const Route = createFileRoute({ preload: false, loader: () => logoutFn(), }) diff --git a/e2e/react-start/basic-auth/src/routes/signup.tsx b/e2e/react-start/basic-auth/src/routes/signup.tsx index 5edbb4993f..e852b267e2 100644 --- a/e2e/react-start/basic-auth/src/routes/signup.tsx +++ b/e2e/react-start/basic-auth/src/routes/signup.tsx @@ -1,4 +1,4 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' import { createServerFn, useServerFn } from '@tanstack/react-start' import { hashPassword, prismaClient } from '~/utils/prisma' @@ -65,7 +65,7 @@ export const signupFn = createServerFn({ }) }) -export const Route = createFileRoute('/signup')({ +export const Route = createFileRoute({ component: SignupComp, }) diff --git a/e2e/react-start/basic-auth/src/ssr.tsx b/e2e/react-start/basic-auth/src/ssr.tsx deleted file mode 100644 index 65a580f25e..0000000000 --- a/e2e/react-start/basic-auth/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/e2e/react-start/basic-auth/src/tanstack-start.d.ts b/e2e/react-start/basic-auth/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/e2e/react-start/basic-auth/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/react-start/basic-auth/vite.config.ts b/e2e/react-start/basic-auth/vite.config.ts new file mode 100644 index 0000000000..1df337cd40 --- /dev/null +++ b/e2e/react-start/basic-auth/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/react-start/plugin/vite' + +export default defineConfig({ + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/e2e/react-start/basic-react-query/.gitignore b/e2e/react-start/basic-react-query/.gitignore index be342025da..ca63f49885 100644 --- a/e2e/react-start/basic-react-query/.gitignore +++ b/e2e/react-start/basic-react-query/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/e2e/react-start/basic-react-query/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/react-start/basic-react-query/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..87c0856e21 --- /dev/null +++ b/e2e/react-start/basic-react-query/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,155 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +import { ServerRoute as ApiUsersRouteImport } from './../../src/routes/api.users' +import { ServerRoute as ApiUsersIdRouteImport } from './../../src/routes/api/users.$id' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +const ApiUsersRoute = ApiUsersRouteImport.update({ + id: '/api/users', + path: '/api/users', + getParentRoute: () => rootRoute, +} as any) + +const ApiUsersIdRoute = ApiUsersIdRouteImport.update({ + id: '/$id', + path: '/$id', + getParentRoute: () => ApiUsersRoute, +} as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath { + '/api/users': { + id: '/api/users' + path: '/api/users' + fullPath: '/api/users' + preLoaderRoute: typeof ApiUsersRouteImport + parentRoute: typeof rootRoute + } + '/api/users/$id': { + id: '/api/users/$id' + path: '/$id' + fullPath: '/api/users/$id' + preLoaderRoute: typeof ApiUsersIdRouteImport + parentRoute: typeof ApiUsersRouteImport + } + } +} + +// Add type-safety to the createFileRoute function across the route tree + +declare module './../../src/routes/api.users' { + const createServerFileRoute: CreateServerFileRoute< + FileRoutesByPath['/api/users']['parentRoute'], + FileRoutesByPath['/api/users']['id'], + FileRoutesByPath['/api/users']['path'], + FileRoutesByPath['/api/users']['fullPath'], + ApiUsersRouteChildren + > +} +declare module './../../src/routes/api/users.$id' { + const createServerFileRoute: CreateServerFileRoute< + FileRoutesByPath['/api/users/$id']['parentRoute'], + FileRoutesByPath['/api/users/$id']['id'], + FileRoutesByPath['/api/users/$id']['path'], + FileRoutesByPath['/api/users/$id']['fullPath'], + unknown + > +} + +// Create and export the route tree + +interface ApiUsersRouteChildren { + ApiUsersIdRoute: typeof ApiUsersIdRoute +} + +const ApiUsersRouteChildren: ApiUsersRouteChildren = { + ApiUsersIdRoute: ApiUsersIdRoute, +} + +const ApiUsersRouteWithChildren = ApiUsersRoute._addFileChildren( + ApiUsersRouteChildren, +) + +export interface FileRoutesByFullPath { + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$id': typeof ApiUsersIdRoute +} + +export interface FileRoutesByTo { + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$id': typeof ApiUsersIdRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$id': typeof ApiUsersIdRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/api/users' | '/api/users/$id' + fileRoutesByTo: FileRoutesByTo + to: '/api/users' | '/api/users/$id' + id: '__root__' | '/api/users' | '/api/users/$id' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + ApiUsersRoute: typeof ApiUsersRouteWithChildren +} + +const rootRouteChildren: RootRouteChildren = { + ApiUsersRoute: ApiUsersRouteWithChildren, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/api/users" + ] + }, + "/api/users": { + "filePath": "api.users.ts", + "children": [ + "/api/users/$id" + ] + }, + "/api/users/$id": { + "filePath": "api/users.$id.ts", + "parent": "/api/users" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/react-start/basic-react-query/app.config.ts b/e2e/react-start/basic-react-query/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/e2e/react-start/basic-react-query/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/e2e/react-start/basic-react-query/package.json b/e2e/react-start/basic-react-query/package.json index 4cc7162526..e8e60685eb 100644 --- a/e2e/react-start/basic-react-query/package.json +++ b/e2e/react-start/basic-react-query/package.json @@ -1,27 +1,27 @@ { - "name": "tanstack-start-e2e-basic-react-query", + "name": "tanstack-react-start-e2e-basic-react-query", "private": true, "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "node .output/server/index.mjs", "test:e2e": "playwright test --project=chromium" }, "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", "@tanstack/react-router": "workspace:^", - "@tanstack/react-router-with-query": "workspace:^", "@tanstack/react-router-devtools": "workspace:^", + "@tanstack/react-router-with-query": "workspace:^", "@tanstack/react-start": "workspace:^", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "vite": "^6.3.5" }, "devDependencies": { "@playwright/test": "^1.50.1", @@ -30,8 +30,8 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "postcss": "^8.5.1", "autoprefixer": "^10.4.20", + "postcss": "^8.5.1", "tailwindcss": "^3.4.17", "typescript": "^5.7.2", "vite-tsconfig-paths": "^5.1.4" diff --git a/e2e/react-start/basic-react-query/playwright.config.ts b/e2e/react-start/basic-react-query/playwright.config.ts index bb77d0cf70..9806e0c136 100644 --- a/e2e/react-start/basic-react-query/playwright.config.ts +++ b/e2e/react-start/basic-react-query/playwright.config.ts @@ -19,7 +19,7 @@ export default defineConfig({ }, webServer: { - command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm start --port ${PORT}`, + command: `VITE_SERVER_PORT=${PORT} pnpm build && PORT=${PORT} VITE_SERVER_PORT=${PORT} pnpm start`, url: baseURL, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/e2e/react-start/basic-react-query/src/api.ts b/e2e/react-start/basic-react-query/src/api.ts deleted file mode 100644 index 8b9fef1667..0000000000 --- a/e2e/react-start/basic-react-query/src/api.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { - createStartAPIHandler, - defaultAPIFileRouteHandler, -} from '@tanstack/react-start/api' - -export default createStartAPIHandler(defaultAPIFileRouteHandler) diff --git a/e2e/react-start/basic-react-query/src/client.tsx b/e2e/react-start/basic-react-query/src/client.tsx deleted file mode 100644 index 31385f57f1..0000000000 --- a/e2e/react-start/basic-react-query/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document!, ) diff --git a/e2e/react-start/basic-react-query/src/routeTree.gen.ts b/e2e/react-start/basic-react-query/src/routeTree.gen.ts index 9f7ab8107b..63730586d0 100644 --- a/e2e/react-start/basic-react-query/src/routeTree.gen.ts +++ b/e2e/react-start/basic-react-query/src/routeTree.gen.ts @@ -8,103 +8,105 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as UsersImport } from './routes/users' -import { Route as RedirectImport } from './routes/redirect' -import { Route as PostsImport } from './routes/posts' -import { Route as DeferredImport } from './routes/deferred' -import { Route as LayoutImport } from './routes/_layout' -import { Route as IndexImport } from './routes/index' -import { Route as UsersIndexImport } from './routes/users.index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as UsersUserIdImport } from './routes/users.$userId' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as LayoutLayout2Import } from './routes/_layout/_layout-2' -import { Route as PostsPostIdDeepImport } from './routes/posts_.$postId.deep' -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 UsersRouteImport } from './routes/users' +import { Route as RedirectRouteImport } from './routes/redirect' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as DeferredRouteImport } from './routes/deferred' +import { Route as LayoutRouteImport } from './routes/_layout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as UsersIndexRouteImport } from './routes/users.index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as UsersUserIdRouteImport } from './routes/users.$userId' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts_.$postId.deep' +import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b' +import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' // Create/Update Routes -const UsersRoute = UsersImport.update({ +const UsersRoute = UsersRouteImport.update({ id: '/users', path: '/users', getParentRoute: () => rootRoute, } as any) -const RedirectRoute = RedirectImport.update({ +const RedirectRoute = RedirectRouteImport.update({ id: '/redirect', path: '/redirect', getParentRoute: () => rootRoute, } as any) -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const DeferredRoute = DeferredImport.update({ +const DeferredRoute = DeferredRouteImport.update({ id: '/deferred', path: '/deferred', getParentRoute: () => rootRoute, } as any) -const LayoutRoute = LayoutImport.update({ +const LayoutRoute = LayoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const UsersIndexRoute = UsersIndexImport.update({ +const UsersIndexRoute = UsersIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => UsersRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const UsersUserIdRoute = UsersUserIdImport.update({ +const UsersUserIdRoute = UsersUserIdRouteImport.update({ id: '/$userId', path: '/$userId', getParentRoute: () => UsersRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const LayoutLayout2Route = LayoutLayout2Import.update({ +const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/posts_/$postId/deep', path: '/posts/$postId/deep', getParentRoute: () => rootRoute, } as any) -const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBImport.update({ +const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => LayoutLayout2Route, } as any) -const LayoutLayout2LayoutARoute = LayoutLayout2LayoutAImport.update({ +const LayoutLayout2LayoutARoute = LayoutLayout2LayoutARouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => LayoutLayout2Route, @@ -118,103 +120,232 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutRouteImport parentRoute: typeof rootRoute } '/deferred': { id: '/deferred' path: '/deferred' fullPath: '/deferred' - preLoaderRoute: typeof DeferredImport + preLoaderRoute: typeof DeferredRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/redirect': { id: '/redirect' path: '/redirect' fullPath: '/redirect' - preLoaderRoute: typeof RedirectImport + preLoaderRoute: typeof RedirectRouteImport parentRoute: typeof rootRoute } '/users': { id: '/users' path: '/users' fullPath: '/users' - preLoaderRoute: typeof UsersImport + preLoaderRoute: typeof UsersRouteImport parentRoute: typeof rootRoute } '/_layout/_layout-2': { id: '/_layout/_layout-2' path: '' fullPath: '' - preLoaderRoute: typeof LayoutLayout2Import - parentRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutLayout2RouteImport + parentRoute: typeof LayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/users/$userId': { id: '/users/$userId' path: '/$userId' fullPath: '/users/$userId' - preLoaderRoute: typeof UsersUserIdImport - parentRoute: typeof UsersImport + preLoaderRoute: typeof UsersUserIdRouteImport + parentRoute: typeof UsersRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/users/': { id: '/users/' path: '/' fullPath: '/users/' - preLoaderRoute: typeof UsersIndexImport - parentRoute: typeof UsersImport + preLoaderRoute: typeof UsersIndexRouteImport + parentRoute: typeof UsersRouteImport } '/_layout/_layout-2/layout-a': { id: '/_layout/_layout-2/layout-a' path: '/layout-a' fullPath: '/layout-a' - preLoaderRoute: typeof LayoutLayout2LayoutAImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutARouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/_layout/_layout-2/layout-b': { id: '/_layout/_layout-2/layout-b' path: '/layout-b' fullPath: '/layout-b' - preLoaderRoute: typeof LayoutLayout2LayoutBImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutBRouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/posts_/$postId/deep': { id: '/posts_/$postId/deep' path: '/posts/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport + preLoaderRoute: typeof PostsPostIdDeepRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_layout' { + const createFileRoute: CreateFileRoute< + '/_layout', + FileRoutesByPath['/_layout']['parentRoute'], + FileRoutesByPath['/_layout']['id'], + FileRoutesByPath['/_layout']['path'], + FileRoutesByPath['/_layout']['fullPath'] + > +} +declare module './routes/deferred' { + const createFileRoute: CreateFileRoute< + '/deferred', + FileRoutesByPath['/deferred']['parentRoute'], + FileRoutesByPath['/deferred']['id'], + FileRoutesByPath['/deferred']['path'], + FileRoutesByPath['/deferred']['fullPath'] + > +} +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/redirect' { + const createFileRoute: CreateFileRoute< + '/redirect', + FileRoutesByPath['/redirect']['parentRoute'], + FileRoutesByPath['/redirect']['id'], + FileRoutesByPath['/redirect']['path'], + FileRoutesByPath['/redirect']['fullPath'] + > +} +declare module './routes/users' { + const createFileRoute: CreateFileRoute< + '/users', + FileRoutesByPath['/users']['parentRoute'], + FileRoutesByPath['/users']['id'], + FileRoutesByPath['/users']['path'], + FileRoutesByPath['/users']['fullPath'] + > +} +declare module './routes/_layout/_layout-2' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2', + FileRoutesByPath['/_layout/_layout-2']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2']['id'], + FileRoutesByPath['/_layout/_layout-2']['path'], + FileRoutesByPath['/_layout/_layout-2']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/users.$userId' { + const createFileRoute: CreateFileRoute< + '/users/$userId', + FileRoutesByPath['/users/$userId']['parentRoute'], + FileRoutesByPath['/users/$userId']['id'], + FileRoutesByPath['/users/$userId']['path'], + FileRoutesByPath['/users/$userId']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/users.index' { + const createFileRoute: CreateFileRoute< + '/users/', + FileRoutesByPath['/users/']['parentRoute'], + FileRoutesByPath['/users/']['id'], + FileRoutesByPath['/users/']['path'], + FileRoutesByPath['/users/']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-a' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-a', + FileRoutesByPath['/_layout/_layout-2/layout-a']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-b' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-b', + FileRoutesByPath['/_layout/_layout-2/layout-b']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['fullPath'] + > +} +declare module './routes/posts_.$postId.deep' { + const createFileRoute: CreateFileRoute< + '/posts_/$postId/deep', + FileRoutesByPath['/posts_/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > +} + // Create and export the route tree interface LayoutLayout2RouteChildren { diff --git a/e2e/react-start/basic-react-query/src/routes/_layout.tsx b/e2e/react-start/basic-react-query/src/routes/_layout.tsx index af5585728e..810465a9ba 100644 --- a/e2e/react-start/basic-react-query/src/routes/_layout.tsx +++ b/e2e/react-start/basic-react-query/src/routes/_layout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-start/basic-react-query/src/routes/_layout/_layout-2.tsx b/e2e/react-start/basic-react-query/src/routes/_layout/_layout-2.tsx index 2167ce27ce..a1ed146002 100644 --- a/e2e/react-start/basic-react-query/src/routes/_layout/_layout-2.tsx +++ b/e2e/react-start/basic-react-query/src/routes/_layout/_layout-2.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout/_layout-2')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-start/basic-react-query/src/routes/_layout/_layout-2/layout-a.tsx b/e2e/react-start/basic-react-query/src/routes/_layout/_layout-2/layout-a.tsx index bb8d3d277d..a0bd5240b7 100644 --- a/e2e/react-start/basic-react-query/src/routes/_layout/_layout-2/layout-a.tsx +++ b/e2e/react-start/basic-react-query/src/routes/_layout/_layout-2/layout-a.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ +export const Route = createFileRoute({ component: LayoutAComponent, }) diff --git a/e2e/react-start/basic-react-query/src/routes/_layout/_layout-2/layout-b.tsx b/e2e/react-start/basic-react-query/src/routes/_layout/_layout-2/layout-b.tsx index 69f6158958..2864ec1f28 100644 --- a/e2e/react-start/basic-react-query/src/routes/_layout/_layout-2/layout-b.tsx +++ b/e2e/react-start/basic-react-query/src/routes/_layout/_layout-2/layout-b.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ +export const Route = createFileRoute({ component: LayoutBComponent, }) diff --git a/e2e/react-start/basic-react-query/src/routes/api.users.ts b/e2e/react-start/basic-react-query/src/routes/api.users.ts index 481085ef3f..3a37e5691a 100644 --- a/e2e/react-start/basic-react-query/src/routes/api.users.ts +++ b/e2e/react-start/basic-react-query/src/routes/api.users.ts @@ -1,9 +1,8 @@ import { json } from '@tanstack/react-start' -import { createAPIFileRoute } from '@tanstack/react-start/api' import axios from 'redaxios' import type { User } from '../utils/users' -export const APIRoute = createAPIFileRoute('/api/users')({ +export const ServerRoute = createServerFileRoute().methods({ GET: async ({ request }) => { console.info('Fetching users... @', request.url) const res = await axios.get>( diff --git a/e2e/react-start/basic-react-query/src/routes/api/users.$id.ts b/e2e/react-start/basic-react-query/src/routes/api/users.$id.ts index b1797e7917..81494c2e93 100644 --- a/e2e/react-start/basic-react-query/src/routes/api/users.$id.ts +++ b/e2e/react-start/basic-react-query/src/routes/api/users.$id.ts @@ -1,9 +1,8 @@ import { json } from '@tanstack/react-start' -import { createAPIFileRoute } from '@tanstack/react-start/api' import axios from 'redaxios' import type { User } from '../../utils/users' -export const APIRoute = createAPIFileRoute('/api/users/$id')({ +export const ServerRoute = createServerFileRoute().methods({ GET: async ({ request, params }) => { console.info(`Fetching users by id=${params.id}... @`, request.url) try { diff --git a/e2e/react-start/basic-react-query/src/routes/deferred.tsx b/e2e/react-start/basic-react-query/src/routes/deferred.tsx index 666ae26e49..16a9f72593 100644 --- a/e2e/react-start/basic-react-query/src/routes/deferred.tsx +++ b/e2e/react-start/basic-react-query/src/routes/deferred.tsx @@ -1,5 +1,5 @@ import { queryOptions, useSuspenseQuery } from '@tanstack/react-query' -import { createFileRoute } from '@tanstack/react-router' +import {} from '@tanstack/react-router' import { Suspense, useState } from 'react' const deferredQueryOptions = () => @@ -15,7 +15,7 @@ const deferredQueryOptions = () => }, }) -export const Route = createFileRoute('/deferred')({ +export const Route = createFileRoute({ loader: ({ context }) => { // Kick off loading as early as possible! context.queryClient.prefetchQuery(deferredQueryOptions()) diff --git a/e2e/react-start/basic-react-query/src/routes/index.tsx b/e2e/react-start/basic-react-query/src/routes/index.tsx index 09a907cb18..f6c5b98b02 100644 --- a/e2e/react-start/basic-react-query/src/routes/index.tsx +++ b/e2e/react-start/basic-react-query/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/react-start/basic-react-query/src/routes/posts.$postId.tsx b/e2e/react-start/basic-react-query/src/routes/posts.$postId.tsx index 16a6bf29aa..f3aa0e7201 100644 --- a/e2e/react-start/basic-react-query/src/routes/posts.$postId.tsx +++ b/e2e/react-start/basic-react-query/src/routes/posts.$postId.tsx @@ -1,11 +1,11 @@ -import { ErrorComponent, Link, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent, Link } from '@tanstack/react-router' import { useSuspenseQuery } from '@tanstack/react-query' import type { ErrorComponentProps } from '@tanstack/react-router' import { postQueryOptions } from '~/utils/posts' import { NotFound } from '~/components/NotFound' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId }, context }) => { const data = await context.queryClient.ensureQueryData( postQueryOptions(postId), @@ -43,7 +43,7 @@ function PostComponent() { postId: postQuery.data.id, }} activeProps={{ className: 'text-black font-bold' }} - className="block py-1 text-blue-800 hover:text-blue-600" + className="inline-block py-1 text-blue-800 hover:text-blue-600" > Deep View diff --git a/e2e/react-start/basic-react-query/src/routes/posts.index.tsx b/e2e/react-start/basic-react-query/src/routes/posts.index.tsx index 5b5f08f95b..13529228bb 100644 --- a/e2e/react-start/basic-react-query/src/routes/posts.index.tsx +++ b/e2e/react-start/basic-react-query/src/routes/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/e2e/react-start/basic-react-query/src/routes/posts.tsx b/e2e/react-start/basic-react-query/src/routes/posts.tsx index 3f678ed1f1..00d91fd049 100644 --- a/e2e/react-start/basic-react-query/src/routes/posts.tsx +++ b/e2e/react-start/basic-react-query/src/routes/posts.tsx @@ -1,9 +1,9 @@ import { useSuspenseQuery } from '@tanstack/react-query' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { postsQueryOptions } from '~/utils/posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: async ({ context }) => { await context.queryClient.ensureQueryData(postsQueryOptions()) }, diff --git a/e2e/react-start/basic-react-query/src/routes/posts_.$postId.deep.tsx b/e2e/react-start/basic-react-query/src/routes/posts_.$postId.deep.tsx index 33f6475a55..4d91776273 100644 --- a/e2e/react-start/basic-react-query/src/routes/posts_.$postId.deep.tsx +++ b/e2e/react-start/basic-react-query/src/routes/posts_.$postId.deep.tsx @@ -1,9 +1,9 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { useSuspenseQuery } from '@tanstack/react-query' import { postQueryOptions } from '../utils/posts' import { PostErrorComponent } from './posts.$postId' -export const Route = createFileRoute('/posts_/$postId/deep')({ +export const Route = createFileRoute({ loader: async ({ params: { postId }, context }) => { const data = await context.queryClient.ensureQueryData( postQueryOptions(postId), diff --git a/e2e/react-start/basic-react-query/src/routes/redirect.tsx b/e2e/react-start/basic-react-query/src/routes/redirect.tsx index c9286de13d..68a98d5683 100644 --- a/e2e/react-start/basic-react-query/src/routes/redirect.tsx +++ b/e2e/react-start/basic-react-query/src/routes/redirect.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect')({ +export const Route = createFileRoute({ beforeLoad: async () => { throw redirect({ to: '/posts', diff --git a/e2e/react-start/basic-react-query/src/routes/users.$userId.tsx b/e2e/react-start/basic-react-query/src/routes/users.$userId.tsx index 656fb6dbb8..7f8bab0e1d 100644 --- a/e2e/react-start/basic-react-query/src/routes/users.$userId.tsx +++ b/e2e/react-start/basic-react-query/src/routes/users.$userId.tsx @@ -1,11 +1,11 @@ import { useSuspenseQuery } from '@tanstack/react-query' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import type { ErrorComponentProps } from '@tanstack/react-router' import { NotFound } from '~/components/NotFound' import { userQueryOptions } from '~/utils/users' -export const Route = createFileRoute('/users/$userId')({ +export const Route = createFileRoute({ loader: async ({ context, params: { userId } }) => { await context.queryClient.ensureQueryData(userQueryOptions(userId)) }, diff --git a/e2e/react-start/basic-react-query/src/routes/users.index.tsx b/e2e/react-start/basic-react-query/src/routes/users.index.tsx index b6b0ee67fb..662e8b6c68 100644 --- a/e2e/react-start/basic-react-query/src/routes/users.index.tsx +++ b/e2e/react-start/basic-react-query/src/routes/users.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/users/')({ +export const Route = createFileRoute({ component: UsersIndexComponent, }) diff --git a/e2e/react-start/basic-react-query/src/routes/users.tsx b/e2e/react-start/basic-react-query/src/routes/users.tsx index 1b56bb9890..8a90dd8412 100644 --- a/e2e/react-start/basic-react-query/src/routes/users.tsx +++ b/e2e/react-start/basic-react-query/src/routes/users.tsx @@ -1,9 +1,9 @@ import { useSuspenseQuery } from '@tanstack/react-query' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { usersQueryOptions } from '~/utils/users' -export const Route = createFileRoute('/users')({ +export const Route = createFileRoute({ loader: async ({ context }) => { await context.queryClient.ensureQueryData(usersQueryOptions()) }, diff --git a/e2e/react-start/basic-react-query/src/tanstack-start.d.ts b/e2e/react-start/basic-react-query/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/e2e/react-start/basic-react-query/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/react-start/basic-react-query/vite.config.ts b/e2e/react-start/basic-react-query/vite.config.ts new file mode 100644 index 0000000000..1df337cd40 --- /dev/null +++ b/e2e/react-start/basic-react-query/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/react-start/plugin/vite' + +export default defineConfig({ + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/e2e/react-start/basic-rsc/.gitignore b/e2e/react-start/basic-rsc/.gitignore index d3387e00cd..3c8e6870b3 100644 --- a/e2e/react-start/basic-rsc/.gitignore +++ b/e2e/react-start/basic-rsc/.gitignore @@ -7,12 +7,8 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin diff --git a/e2e/react-start/basic-rsc/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/react-start/basic-rsc/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/e2e/react-start/basic-rsc/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/react-start/basic-rsc/app.config.ts b/e2e/react-start/basic-rsc/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/e2e/react-start/basic-rsc/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/e2e/react-start/basic-rsc/package.json b/e2e/react-start/basic-rsc/package.json index c93361fa88..9c820c9ccd 100644 --- a/e2e/react-start/basic-rsc/package.json +++ b/e2e/react-start/basic-rsc/package.json @@ -1,12 +1,12 @@ { - "name": "tanstack-start-e2e-basic-rsc", + "name": "tanstack-react-start-e2e-basic-rsc", "private": true, "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "node .output/server/index.mjs" }, "dependencies": { "@babel/plugin-syntax-typescript": "^7.25.9", @@ -17,14 +17,14 @@ "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "vite": "^6.3.5" }, "devDependencies": { "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "postcss": "^8.5.1", "autoprefixer": "^10.4.20", + "postcss": "^8.5.1", "tailwindcss": "^3.4.17", "typescript": "^5.7.2", "vite-tsconfig-paths": "^5.1.4" diff --git a/e2e/react-start/basic-rsc/src/client.tsx b/e2e/react-start/basic-rsc/src/client.tsx deleted file mode 100644 index 31385f57f1..0000000000 --- a/e2e/react-start/basic-rsc/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document!, ) diff --git a/e2e/react-start/basic-rsc/src/routeTree.gen.ts b/e2e/react-start/basic-rsc/src/routeTree.gen.ts index 1918b25c80..54e0311d56 100644 --- a/e2e/react-start/basic-rsc/src/routeTree.gen.ts +++ b/e2e/react-start/basic-rsc/src/routeTree.gen.ts @@ -8,68 +8,70 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-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 PostsIndexImport } from './routes/posts.index' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as LayoutLayout2Import } from './routes/_layout/_layout-2' -import { Route as PostsPostIdDeepImport } from './routes/posts_.$postId.deep' -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 PostsRouteImport } from './routes/posts' +import { Route as LayoutRouteImport } from './routes/_layout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts_.$postId.deep' +import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b' +import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' // Create/Update Routes -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const LayoutRoute = LayoutImport.update({ +const LayoutRoute = LayoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const LayoutLayout2Route = LayoutLayout2Import.update({ +const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/posts_/$postId/deep', path: '/posts/$postId/deep', getParentRoute: () => rootRoute, } as any) -const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBImport.update({ +const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => LayoutLayout2Route, } as any) -const LayoutLayout2LayoutARoute = LayoutLayout2LayoutAImport.update({ +const LayoutLayout2LayoutARoute = LayoutLayout2LayoutARouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => LayoutLayout2Route, @@ -83,68 +85,152 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/_layout/_layout-2': { id: '/_layout/_layout-2' path: '' fullPath: '' - preLoaderRoute: typeof LayoutLayout2Import - parentRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutLayout2RouteImport + parentRoute: typeof LayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/_layout/_layout-2/layout-a': { id: '/_layout/_layout-2/layout-a' path: '/layout-a' fullPath: '/layout-a' - preLoaderRoute: typeof LayoutLayout2LayoutAImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutARouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/_layout/_layout-2/layout-b': { id: '/_layout/_layout-2/layout-b' path: '/layout-b' fullPath: '/layout-b' - preLoaderRoute: typeof LayoutLayout2LayoutBImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutBRouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/posts_/$postId/deep': { id: '/posts_/$postId/deep' path: '/posts/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport + preLoaderRoute: typeof PostsPostIdDeepRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_layout' { + const createFileRoute: CreateFileRoute< + '/_layout', + FileRoutesByPath['/_layout']['parentRoute'], + FileRoutesByPath['/_layout']['id'], + FileRoutesByPath['/_layout']['path'], + FileRoutesByPath['/_layout']['fullPath'] + > +} +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/_layout/_layout-2' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2', + FileRoutesByPath['/_layout/_layout-2']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2']['id'], + FileRoutesByPath['/_layout/_layout-2']['path'], + FileRoutesByPath['/_layout/_layout-2']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-a' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-a', + FileRoutesByPath['/_layout/_layout-2/layout-a']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-b' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-b', + FileRoutesByPath['/_layout/_layout-2/layout-b']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['fullPath'] + > +} +declare module './routes/posts_.$postId.deep' { + const createFileRoute: CreateFileRoute< + '/posts_/$postId/deep', + FileRoutesByPath['/posts_/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > +} + // Create and export the route tree interface LayoutLayout2RouteChildren { diff --git a/e2e/react-start/basic-rsc/src/routes/_layout.tsx b/e2e/react-start/basic-rsc/src/routes/_layout.tsx index 02ddbb1cd9..5c4a461d8d 100644 --- a/e2e/react-start/basic-rsc/src/routes/_layout.tsx +++ b/e2e/react-start/basic-rsc/src/routes/_layout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-start/basic-rsc/src/routes/_layout/_layout-2.tsx b/e2e/react-start/basic-rsc/src/routes/_layout/_layout-2.tsx index 3b7dbf2903..483b910862 100644 --- a/e2e/react-start/basic-rsc/src/routes/_layout/_layout-2.tsx +++ b/e2e/react-start/basic-rsc/src/routes/_layout/_layout-2.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout/_layout-2')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-start/basic-rsc/src/routes/_layout/_layout-2/layout-a.tsx b/e2e/react-start/basic-rsc/src/routes/_layout/_layout-2/layout-a.tsx index 61e19b4d9f..a190b24202 100644 --- a/e2e/react-start/basic-rsc/src/routes/_layout/_layout-2/layout-a.tsx +++ b/e2e/react-start/basic-rsc/src/routes/_layout/_layout-2/layout-a.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ +export const Route = createFileRoute({ component: LayoutAComponent, }) diff --git a/e2e/react-start/basic-rsc/src/routes/_layout/_layout-2/layout-b.tsx b/e2e/react-start/basic-rsc/src/routes/_layout/_layout-2/layout-b.tsx index cceed1fb9a..505f8f6fbf 100644 --- a/e2e/react-start/basic-rsc/src/routes/_layout/_layout-2/layout-b.tsx +++ b/e2e/react-start/basic-rsc/src/routes/_layout/_layout-2/layout-b.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ +export const Route = createFileRoute({ component: LayoutBComponent, }) diff --git a/e2e/react-start/basic-rsc/src/routes/index.tsx b/e2e/react-start/basic-rsc/src/routes/index.tsx index b7b6138529..a693dcbf14 100644 --- a/e2e/react-start/basic-rsc/src/routes/index.tsx +++ b/e2e/react-start/basic-rsc/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/react-start/basic-rsc/src/routes/posts.$postId.tsx b/e2e/react-start/basic-rsc/src/routes/posts.$postId.tsx index 7dd63a2cd0..43f780f6fe 100644 --- a/e2e/react-start/basic-rsc/src/routes/posts.$postId.tsx +++ b/e2e/react-start/basic-rsc/src/routes/posts.$postId.tsx @@ -1,4 +1,4 @@ -import { ErrorComponent, Link, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent, Link } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import type { ErrorComponentProps } from '@tanstack/react-router' @@ -28,7 +28,7 @@ const renderPost = createServerFn({ method: 'GET' }) ) }) -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => renderPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, diff --git a/e2e/react-start/basic-rsc/src/routes/posts.index.tsx b/e2e/react-start/basic-rsc/src/routes/posts.index.tsx index 5b5f08f95b..13529228bb 100644 --- a/e2e/react-start/basic-rsc/src/routes/posts.index.tsx +++ b/e2e/react-start/basic-rsc/src/routes/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/e2e/react-start/basic-rsc/src/routes/posts.tsx b/e2e/react-start/basic-rsc/src/routes/posts.tsx index a3ef2a2e20..131cec4b9b 100644 --- a/e2e/react-start/basic-rsc/src/routes/posts.tsx +++ b/e2e/react-start/basic-rsc/src/routes/posts.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' import { createServerFn, renderRsc } from '@tanstack/react-start' import { renderPosts } from '~/utils/renderPosts' @@ -6,7 +5,7 @@ export const serverRenderPosts = createServerFn({ method: 'GET' }).handler( renderPosts, ) -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: async () => serverRenderPosts(), component: PostsComponent, }) diff --git a/e2e/react-start/basic-rsc/src/routes/posts_.$postId.deep.tsx b/e2e/react-start/basic-rsc/src/routes/posts_.$postId.deep.tsx index 13d368cf9c..bf2edef3c9 100644 --- a/e2e/react-start/basic-rsc/src/routes/posts_.$postId.deep.tsx +++ b/e2e/react-start/basic-rsc/src/routes/posts_.$postId.deep.tsx @@ -1,8 +1,8 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { fetchPost } from '../utils/posts' import { PostErrorComponent } from './posts.$postId' -export const Route = createFileRoute('/posts_/$postId/deep')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost(postId), errorComponent: PostErrorComponent, component: PostDeepComponent, diff --git a/e2e/react-start/basic-rsc/src/ssr.tsx b/e2e/react-start/basic-rsc/src/ssr.tsx deleted file mode 100644 index 65a580f25e..0000000000 --- a/e2e/react-start/basic-rsc/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/e2e/react-start/basic-rsc/src/tanstack-start.d.ts b/e2e/react-start/basic-rsc/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/e2e/react-start/basic-rsc/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/react-start/basic-rsc/vite.config.ts b/e2e/react-start/basic-rsc/vite.config.ts new file mode 100644 index 0000000000..1df337cd40 --- /dev/null +++ b/e2e/react-start/basic-rsc/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/react-start/plugin/vite' + +export default defineConfig({ + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/e2e/react-start/basic-tsr-config/.gitignore b/e2e/react-start/basic-tsr-config/.gitignore index 2b76174be5..08eba9e706 100644 --- a/e2e/react-start/basic-tsr-config/.gitignore +++ b/e2e/react-start/basic-tsr-config/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/e2e/react-start/basic-tsr-config/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/react-start/basic-tsr-config/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/e2e/react-start/basic-tsr-config/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/react-start/basic-tsr-config/app.config.ts b/e2e/react-start/basic-tsr-config/app.config.ts deleted file mode 100644 index 8989703df9..0000000000 --- a/e2e/react-start/basic-tsr-config/app.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -// app.config.ts -import { defineConfig } from '@tanstack/react-start/config' - -export default defineConfig({ - tsr: { - appDirectory: './src/app', - }, -}) diff --git a/e2e/react-start/basic-tsr-config/package.json b/e2e/react-start/basic-tsr-config/package.json index cd697d2bfb..aaeb94882e 100644 --- a/e2e/react-start/basic-tsr-config/package.json +++ b/e2e/react-start/basic-tsr-config/package.json @@ -1,13 +1,13 @@ { - "name": "tanstack-start-e2e-basic-tsr-config", + "name": "tanstack-react-start-e2e-basic-tsr-config", "private": true, "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "rimraf ./count.txt && vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "rimraf ./count.txt && vite build && tsc --noEmit", + "start": "node .output/server/index.mjs", "test:e2e": "playwright test --project=chromium" }, "dependencies": { @@ -15,7 +15,7 @@ "@tanstack/react-start": "workspace:^", "react": "^19.0.0", "react-dom": "^19.0.0", - "vinxi": "0.5.3" + "vite": "^6.3.5" }, "devDependencies": { "@tanstack/router-e2e-utils": "workspace:^", diff --git a/e2e/react-start/basic-tsr-config/playwright.config.ts b/e2e/react-start/basic-tsr-config/playwright.config.ts index bb77d0cf70..9806e0c136 100644 --- a/e2e/react-start/basic-tsr-config/playwright.config.ts +++ b/e2e/react-start/basic-tsr-config/playwright.config.ts @@ -19,7 +19,7 @@ export default defineConfig({ }, webServer: { - command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm start --port ${PORT}`, + command: `VITE_SERVER_PORT=${PORT} pnpm build && PORT=${PORT} VITE_SERVER_PORT=${PORT} pnpm start`, url: baseURL, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/e2e/react-start/basic-tsr-config/src/app/client.tsx b/e2e/react-start/basic-tsr-config/src/app/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/e2e/react-start/basic-tsr-config/src/app/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/basic-tsr-config/src/app/routeTree.gen.ts b/e2e/react-start/basic-tsr-config/src/app/routeTree.gen.ts index 5e682936ba..dd5eda94a9 100644 --- a/e2e/react-start/basic-tsr-config/src/app/routeTree.gen.ts +++ b/e2e/react-start/basic-tsr-config/src/app/routeTree.gen.ts @@ -8,14 +8,16 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -29,12 +31,24 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/e2e/react-start/basic-tsr-config/src/app/routes/index.tsx b/e2e/react-start/basic-tsr-config/src/app/routes/index.tsx index aaa4bdfdb3..3c1ef4b5d8 100644 --- a/e2e/react-start/basic-tsr-config/src/app/routes/index.tsx +++ b/e2e/react-start/basic-tsr-config/src/app/routes/index.tsx @@ -1,5 +1,5 @@ import fs from 'node:fs' -import { createFileRoute, useRouter } from '@tanstack/react-router' +import { useRouter } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' const filePath = 'count.txt' @@ -17,7 +17,7 @@ const updateCount = createServerFn({ method: 'POST' }) const count = await getCount() await fs.promises.writeFile(filePath, `${count + data}`) }) -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, loader: async () => await getCount(), }) diff --git a/e2e/react-start/basic-tsr-config/src/app/ssr.tsx b/e2e/react-start/basic-tsr-config/src/app/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/e2e/react-start/basic-tsr-config/src/app/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/e2e/react-start/basic-tsr-config/src/app/tanstack-start.d.ts b/e2e/react-start/basic-tsr-config/src/app/tanstack-start.d.ts new file mode 100644 index 0000000000..df36e6de73 --- /dev/null +++ b/e2e/react-start/basic-tsr-config/src/app/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/react-start/basic-tsr-config/vite.config.ts b/e2e/react-start/basic-tsr-config/vite.config.ts new file mode 100644 index 0000000000..69045b5a44 --- /dev/null +++ b/e2e/react-start/basic-tsr-config/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite' +import { tanstackStart } from '@tanstack/react-start/plugin/vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tanstackStart({ + tsr: { + srcDirectory: './src/app', + }, + }), + ], +}) diff --git a/e2e/react-start/basic/.gitignore b/e2e/react-start/basic/.gitignore index be342025da..a79d5cf129 100644 --- a/e2e/react-start/basic/.gitignore +++ b/e2e/react-start/basic/.gitignore @@ -7,13 +7,11 @@ yarn.lock .env .vercel .output -.vinxi /build/ /api/ /server/build /public/build -.vinxi # Sentry Config File .env.sentry-build-plugin /test-results/ diff --git a/e2e/react-start/basic/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/react-start/basic/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..87c0856e21 --- /dev/null +++ b/e2e/react-start/basic/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,155 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +import { ServerRoute as ApiUsersRouteImport } from './../../src/routes/api.users' +import { ServerRoute as ApiUsersIdRouteImport } from './../../src/routes/api/users.$id' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +const ApiUsersRoute = ApiUsersRouteImport.update({ + id: '/api/users', + path: '/api/users', + getParentRoute: () => rootRoute, +} as any) + +const ApiUsersIdRoute = ApiUsersIdRouteImport.update({ + id: '/$id', + path: '/$id', + getParentRoute: () => ApiUsersRoute, +} as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath { + '/api/users': { + id: '/api/users' + path: '/api/users' + fullPath: '/api/users' + preLoaderRoute: typeof ApiUsersRouteImport + parentRoute: typeof rootRoute + } + '/api/users/$id': { + id: '/api/users/$id' + path: '/$id' + fullPath: '/api/users/$id' + preLoaderRoute: typeof ApiUsersIdRouteImport + parentRoute: typeof ApiUsersRouteImport + } + } +} + +// Add type-safety to the createFileRoute function across the route tree + +declare module './../../src/routes/api.users' { + const createServerFileRoute: CreateServerFileRoute< + FileRoutesByPath['/api/users']['parentRoute'], + FileRoutesByPath['/api/users']['id'], + FileRoutesByPath['/api/users']['path'], + FileRoutesByPath['/api/users']['fullPath'], + ApiUsersRouteChildren + > +} +declare module './../../src/routes/api/users.$id' { + const createServerFileRoute: CreateServerFileRoute< + FileRoutesByPath['/api/users/$id']['parentRoute'], + FileRoutesByPath['/api/users/$id']['id'], + FileRoutesByPath['/api/users/$id']['path'], + FileRoutesByPath['/api/users/$id']['fullPath'], + unknown + > +} + +// Create and export the route tree + +interface ApiUsersRouteChildren { + ApiUsersIdRoute: typeof ApiUsersIdRoute +} + +const ApiUsersRouteChildren: ApiUsersRouteChildren = { + ApiUsersIdRoute: ApiUsersIdRoute, +} + +const ApiUsersRouteWithChildren = ApiUsersRoute._addFileChildren( + ApiUsersRouteChildren, +) + +export interface FileRoutesByFullPath { + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$id': typeof ApiUsersIdRoute +} + +export interface FileRoutesByTo { + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$id': typeof ApiUsersIdRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$id': typeof ApiUsersIdRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/api/users' | '/api/users/$id' + fileRoutesByTo: FileRoutesByTo + to: '/api/users' | '/api/users/$id' + id: '__root__' | '/api/users' | '/api/users/$id' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + ApiUsersRoute: typeof ApiUsersRouteWithChildren +} + +const rootRouteChildren: RootRouteChildren = { + ApiUsersRoute: ApiUsersRouteWithChildren, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/api/users" + ] + }, + "/api/users": { + "filePath": "api.users.ts", + "children": [ + "/api/users/$id" + ] + }, + "/api/users/$id": { + "filePath": "api/users.$id.ts", + "parent": "/api/users" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/react-start/basic/app.config.ts b/e2e/react-start/basic/app.config.ts deleted file mode 100644 index 421aeca7b0..0000000000 --- a/e2e/react-start/basic/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/e2e/react-start/basic/package.json b/e2e/react-start/basic/package.json index 2046e82f17..db3ff39cf2 100644 --- a/e2e/react-start/basic/package.json +++ b/e2e/react-start/basic/package.json @@ -1,36 +1,36 @@ { - "name": "tanstack-start-e2e-basic", + "name": "tanstack-react-start-e2e-basic", "private": true, "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "node .output/server/index.mjs", "test:e2e": "playwright test --project=chromium" }, "dependencies": { "@tanstack/react-router": "workspace:^", "@tanstack/react-router-devtools": "workspace:^", - "@tanstack/start": "workspace:^", + "@tanstack/react-start": "workspace:^", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", + "vite": "6.3.5", "zod": "^3.24.2" }, "devDependencies": { "@playwright/test": "^1.50.1", + "@tanstack/router-e2e-utils": "workspace:^", "@types/node": "^22.10.2", "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", - "@tanstack/router-e2e-utils": "workspace:^", "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.20", "combinate": "^1.1.11", "postcss": "^8.5.1", - "autoprefixer": "^10.4.20", "tailwindcss": "^3.4.17", "typescript": "^5.7.2", "vite-tsconfig-paths": "^5.1.4" diff --git a/e2e/react-start/basic/playwright.config.ts b/e2e/react-start/basic/playwright.config.ts index 95d043d48b..e834d88cf4 100644 --- a/e2e/react-start/basic/playwright.config.ts +++ b/e2e/react-start/basic/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ }, webServer: { - command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm start --port ${PORT}`, + command: `pnpm build && VITE_SERVER_PORT=${PORT} PORT=${PORT} pnpm start`, url: baseURL, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/e2e/react-start/basic/src/api.ts b/e2e/react-start/basic/src/api.ts deleted file mode 100644 index 0caf78bb9d..0000000000 --- a/e2e/react-start/basic/src/api.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { - createStartAPIHandler, - defaultAPIFileRouteHandler, -} from '@tanstack/start/api' - -export default createStartAPIHandler(defaultAPIFileRouteHandler) diff --git a/e2e/react-start/basic/src/client.tsx b/e2e/react-start/basic/src/client.tsx index b14d8aac68..5fcd1c5f19 100644 --- a/e2e/react-start/basic/src/client.tsx +++ b/e2e/react-start/basic/src/client.tsx @@ -1,8 +1,19 @@ -/// +// DO NOT DELETE THIS FILE!!! +// This file is a good smoke test to make sure the custom client entry is working +import { StrictMode, startTransition } from 'react' import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/start' +import { StartClient } from '@tanstack/react-start' import { createRouter } from './router' +console.log("[client-entry]: using custom client entry in 'src/client.tsx'") + const router = createRouter() -hydrateRoot(document, ) +startTransition(() => { + hydrateRoot( + document, + + + , + ) +}) diff --git a/e2e/react-start/basic/src/components/RedirectOnClick.tsx b/e2e/react-start/basic/src/components/RedirectOnClick.tsx index ec7445df5a..37b434c2e7 100644 --- a/e2e/react-start/basic/src/components/RedirectOnClick.tsx +++ b/e2e/react-start/basic/src/components/RedirectOnClick.tsx @@ -1,4 +1,4 @@ -import { useServerFn } from '@tanstack/start' +import { useServerFn } from '@tanstack/react-start' import { throwRedirect } from './throwRedirect' interface RedirectOnClickProps { diff --git a/e2e/react-start/basic/src/components/throwRedirect.ts b/e2e/react-start/basic/src/components/throwRedirect.ts index 9cef423d23..6a7a011912 100644 --- a/e2e/react-start/basic/src/components/throwRedirect.ts +++ b/e2e/react-start/basic/src/components/throwRedirect.ts @@ -1,5 +1,5 @@ import { redirect } from '@tanstack/react-router' -import { createServerFn } from '@tanstack/start' +import { createServerFn } from '@tanstack/react-start' export const throwRedirect = createServerFn() .validator( @@ -11,7 +11,10 @@ export const throwRedirect = createServerFn() ) .handler((ctx) => { if (ctx.data.target === 'internal') { - throw redirect({ to: '/posts', reloadDocument: ctx.data.reloadDocument }) + throw redirect({ + to: '/posts', + reloadDocument: ctx.data.reloadDocument, + }) } const href = ctx.data.externalHost ?? 'http://example.com' throw redirect({ diff --git a/e2e/react-start/basic/src/routeTree.gen.ts b/e2e/react-start/basic/src/routeTree.gen.ts index 1335898845..967443401e 100644 --- a/e2e/react-start/basic/src/routeTree.gen.ts +++ b/e2e/react-start/basic/src/routeTree.gen.ts @@ -8,220 +8,222 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as UsersImport } from './routes/users' -import { Route as StreamImport } from './routes/stream' -import { Route as SearchParamsImport } from './routes/search-params' -import { Route as ScriptsImport } from './routes/scripts' -import { Route as PostsImport } from './routes/posts' -import { Route as LinksImport } from './routes/links' -import { Route as DeferredImport } from './routes/deferred' -import { Route as LayoutImport } from './routes/_layout' -import { Route as NotFoundRouteImport } from './routes/not-found/route' -import { Route as IndexImport } from './routes/index' -import { Route as UsersIndexImport } from './routes/users.index' -import { Route as RedirectIndexImport } from './routes/redirect/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as NotFoundIndexImport } from './routes/not-found/index' -import { Route as UsersUserIdImport } from './routes/users.$userId' -import { Route as RedirectTargetImport } from './routes/redirect/$target' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as NotFoundViaLoaderImport } from './routes/not-found/via-loader' -import { Route as NotFoundViaBeforeLoadImport } from './routes/not-found/via-beforeLoad' -import { Route as LayoutLayout2Import } from './routes/_layout/_layout-2' -import { Route as RedirectTargetIndexImport } from './routes/redirect/$target/index' -import { Route as RedirectTargetViaLoaderImport } from './routes/redirect/$target/via-loader' -import { Route as RedirectTargetViaBeforeLoadImport } from './routes/redirect/$target/via-beforeLoad' -import { Route as PostsPostIdDeepImport } from './routes/posts_.$postId.deep' -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 RedirectTargetServerFnIndexImport } from './routes/redirect/$target/serverFn/index' -import { Route as RedirectTargetServerFnViaUseServerFnImport } from './routes/redirect/$target/serverFn/via-useServerFn' -import { Route as RedirectTargetServerFnViaLoaderImport } from './routes/redirect/$target/serverFn/via-loader' -import { Route as RedirectTargetServerFnViaBeforeLoadImport } from './routes/redirect/$target/serverFn/via-beforeLoad' +import { Route as UsersRouteImport } from './routes/users' +import { Route as StreamRouteImport } from './routes/stream' +import { Route as SearchParamsRouteImport } from './routes/search-params' +import { Route as ScriptsRouteImport } from './routes/scripts' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as LinksRouteImport } from './routes/links' +import { Route as DeferredRouteImport } from './routes/deferred' +import { Route as LayoutRouteImport } from './routes/_layout' +import { Route as NotFoundRouteRouteImport } from './routes/not-found/route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as UsersIndexRouteImport } from './routes/users.index' +import { Route as RedirectIndexRouteImport } from './routes/redirect/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as NotFoundIndexRouteImport } from './routes/not-found/index' +import { Route as UsersUserIdRouteImport } from './routes/users.$userId' +import { Route as RedirectTargetRouteImport } from './routes/redirect/$target' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as NotFoundViaLoaderRouteImport } from './routes/not-found/via-loader' +import { Route as NotFoundViaBeforeLoadRouteImport } from './routes/not-found/via-beforeLoad' +import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2' +import { Route as RedirectTargetIndexRouteImport } from './routes/redirect/$target/index' +import { Route as RedirectTargetViaLoaderRouteImport } from './routes/redirect/$target/via-loader' +import { Route as RedirectTargetViaBeforeLoadRouteImport } from './routes/redirect/$target/via-beforeLoad' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts_.$postId.deep' +import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b' +import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' +import { Route as RedirectTargetServerFnIndexRouteImport } from './routes/redirect/$target/serverFn/index' +import { Route as RedirectTargetServerFnViaUseServerFnRouteImport } from './routes/redirect/$target/serverFn/via-useServerFn' +import { Route as RedirectTargetServerFnViaLoaderRouteImport } from './routes/redirect/$target/serverFn/via-loader' +import { Route as RedirectTargetServerFnViaBeforeLoadRouteImport } from './routes/redirect/$target/serverFn/via-beforeLoad' // Create/Update Routes -const UsersRoute = UsersImport.update({ +const UsersRoute = UsersRouteImport.update({ id: '/users', path: '/users', getParentRoute: () => rootRoute, } as any) -const StreamRoute = StreamImport.update({ +const StreamRoute = StreamRouteImport.update({ id: '/stream', path: '/stream', getParentRoute: () => rootRoute, } as any) -const SearchParamsRoute = SearchParamsImport.update({ +const SearchParamsRoute = SearchParamsRouteImport.update({ id: '/search-params', path: '/search-params', getParentRoute: () => rootRoute, } as any) -const ScriptsRoute = ScriptsImport.update({ +const ScriptsRoute = ScriptsRouteImport.update({ id: '/scripts', path: '/scripts', getParentRoute: () => rootRoute, } as any) -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const LinksRoute = LinksImport.update({ +const LinksRoute = LinksRouteImport.update({ id: '/links', path: '/links', getParentRoute: () => rootRoute, } as any) -const DeferredRoute = DeferredImport.update({ +const DeferredRoute = DeferredRouteImport.update({ id: '/deferred', path: '/deferred', getParentRoute: () => rootRoute, } as any) -const LayoutRoute = LayoutImport.update({ +const LayoutRoute = LayoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const NotFoundRouteRoute = NotFoundRouteImport.update({ +const NotFoundRouteRoute = NotFoundRouteRouteImport.update({ id: '/not-found', path: '/not-found', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const UsersIndexRoute = UsersIndexImport.update({ +const UsersIndexRoute = UsersIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => UsersRoute, } as any) -const RedirectIndexRoute = RedirectIndexImport.update({ +const RedirectIndexRoute = RedirectIndexRouteImport.update({ id: '/redirect/', path: '/redirect/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const NotFoundIndexRoute = NotFoundIndexImport.update({ +const NotFoundIndexRoute = NotFoundIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => NotFoundRouteRoute, } as any) -const UsersUserIdRoute = UsersUserIdImport.update({ +const UsersUserIdRoute = UsersUserIdRouteImport.update({ id: '/$userId', path: '/$userId', getParentRoute: () => UsersRoute, } as any) -const RedirectTargetRoute = RedirectTargetImport.update({ +const RedirectTargetRoute = RedirectTargetRouteImport.update({ id: '/redirect/$target', path: '/redirect/$target', getParentRoute: () => rootRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const NotFoundViaLoaderRoute = NotFoundViaLoaderImport.update({ +const NotFoundViaLoaderRoute = NotFoundViaLoaderRouteImport.update({ id: '/via-loader', path: '/via-loader', getParentRoute: () => NotFoundRouteRoute, } as any) -const NotFoundViaBeforeLoadRoute = NotFoundViaBeforeLoadImport.update({ +const NotFoundViaBeforeLoadRoute = NotFoundViaBeforeLoadRouteImport.update({ id: '/via-beforeLoad', path: '/via-beforeLoad', getParentRoute: () => NotFoundRouteRoute, } as any) -const LayoutLayout2Route = LayoutLayout2Import.update({ +const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) -const RedirectTargetIndexRoute = RedirectTargetIndexImport.update({ +const RedirectTargetIndexRoute = RedirectTargetIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => RedirectTargetRoute, } as any) -const RedirectTargetViaLoaderRoute = RedirectTargetViaLoaderImport.update({ +const RedirectTargetViaLoaderRoute = RedirectTargetViaLoaderRouteImport.update({ id: '/via-loader', path: '/via-loader', getParentRoute: () => RedirectTargetRoute, } as any) const RedirectTargetViaBeforeLoadRoute = - RedirectTargetViaBeforeLoadImport.update({ + RedirectTargetViaBeforeLoadRouteImport.update({ id: '/via-beforeLoad', path: '/via-beforeLoad', getParentRoute: () => RedirectTargetRoute, } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/posts_/$postId/deep', path: '/posts/$postId/deep', getParentRoute: () => rootRoute, } as any) -const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBImport.update({ +const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => LayoutLayout2Route, } as any) -const LayoutLayout2LayoutARoute = LayoutLayout2LayoutAImport.update({ +const LayoutLayout2LayoutARoute = LayoutLayout2LayoutARouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => LayoutLayout2Route, } as any) const RedirectTargetServerFnIndexRoute = - RedirectTargetServerFnIndexImport.update({ + RedirectTargetServerFnIndexRouteImport.update({ id: '/serverFn/', path: '/serverFn/', getParentRoute: () => RedirectTargetRoute, } as any) const RedirectTargetServerFnViaUseServerFnRoute = - RedirectTargetServerFnViaUseServerFnImport.update({ + RedirectTargetServerFnViaUseServerFnRouteImport.update({ id: '/serverFn/via-useServerFn', path: '/serverFn/via-useServerFn', getParentRoute: () => RedirectTargetRoute, } as any) const RedirectTargetServerFnViaLoaderRoute = - RedirectTargetServerFnViaLoaderImport.update({ + RedirectTargetServerFnViaLoaderRouteImport.update({ id: '/serverFn/via-loader', path: '/serverFn/via-loader', getParentRoute: () => RedirectTargetRoute, } as any) const RedirectTargetServerFnViaBeforeLoadRoute = - RedirectTargetServerFnViaBeforeLoadImport.update({ + RedirectTargetServerFnViaBeforeLoadRouteImport.update({ id: '/serverFn/via-beforeLoad', path: '/serverFn/via-beforeLoad', getParentRoute: () => RedirectTargetRoute, @@ -235,215 +237,488 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/not-found': { id: '/not-found' path: '/not-found' fullPath: '/not-found' - preLoaderRoute: typeof NotFoundRouteImport + preLoaderRoute: typeof NotFoundRouteRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutRouteImport parentRoute: typeof rootRoute } '/deferred': { id: '/deferred' path: '/deferred' fullPath: '/deferred' - preLoaderRoute: typeof DeferredImport + preLoaderRoute: typeof DeferredRouteImport parentRoute: typeof rootRoute } '/links': { id: '/links' path: '/links' fullPath: '/links' - preLoaderRoute: typeof LinksImport + preLoaderRoute: typeof LinksRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/scripts': { id: '/scripts' path: '/scripts' fullPath: '/scripts' - preLoaderRoute: typeof ScriptsImport + preLoaderRoute: typeof ScriptsRouteImport parentRoute: typeof rootRoute } '/search-params': { id: '/search-params' path: '/search-params' fullPath: '/search-params' - preLoaderRoute: typeof SearchParamsImport + preLoaderRoute: typeof SearchParamsRouteImport parentRoute: typeof rootRoute } '/stream': { id: '/stream' path: '/stream' fullPath: '/stream' - preLoaderRoute: typeof StreamImport + preLoaderRoute: typeof StreamRouteImport parentRoute: typeof rootRoute } '/users': { id: '/users' path: '/users' fullPath: '/users' - preLoaderRoute: typeof UsersImport + preLoaderRoute: typeof UsersRouteImport parentRoute: typeof rootRoute } '/_layout/_layout-2': { id: '/_layout/_layout-2' path: '' fullPath: '' - preLoaderRoute: typeof LayoutLayout2Import - parentRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutLayout2RouteImport + parentRoute: typeof LayoutRouteImport } '/not-found/via-beforeLoad': { id: '/not-found/via-beforeLoad' path: '/via-beforeLoad' fullPath: '/not-found/via-beforeLoad' - preLoaderRoute: typeof NotFoundViaBeforeLoadImport - parentRoute: typeof NotFoundRouteImport + preLoaderRoute: typeof NotFoundViaBeforeLoadRouteImport + parentRoute: typeof NotFoundRouteRouteImport } '/not-found/via-loader': { id: '/not-found/via-loader' path: '/via-loader' fullPath: '/not-found/via-loader' - preLoaderRoute: typeof NotFoundViaLoaderImport - parentRoute: typeof NotFoundRouteImport + preLoaderRoute: typeof NotFoundViaLoaderRouteImport + parentRoute: typeof NotFoundRouteRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/redirect/$target': { id: '/redirect/$target' path: '/redirect/$target' fullPath: '/redirect/$target' - preLoaderRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetRouteImport parentRoute: typeof rootRoute } '/users/$userId': { id: '/users/$userId' path: '/$userId' fullPath: '/users/$userId' - preLoaderRoute: typeof UsersUserIdImport - parentRoute: typeof UsersImport + preLoaderRoute: typeof UsersUserIdRouteImport + parentRoute: typeof UsersRouteImport } '/not-found/': { id: '/not-found/' path: '/' fullPath: '/not-found/' - preLoaderRoute: typeof NotFoundIndexImport - parentRoute: typeof NotFoundRouteImport + preLoaderRoute: typeof NotFoundIndexRouteImport + parentRoute: typeof NotFoundRouteRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/redirect/': { id: '/redirect/' path: '/redirect' fullPath: '/redirect' - preLoaderRoute: typeof RedirectIndexImport + preLoaderRoute: typeof RedirectIndexRouteImport parentRoute: typeof rootRoute } '/users/': { id: '/users/' path: '/' fullPath: '/users/' - preLoaderRoute: typeof UsersIndexImport - parentRoute: typeof UsersImport + preLoaderRoute: typeof UsersIndexRouteImport + parentRoute: typeof UsersRouteImport } '/_layout/_layout-2/layout-a': { id: '/_layout/_layout-2/layout-a' path: '/layout-a' fullPath: '/layout-a' - preLoaderRoute: typeof LayoutLayout2LayoutAImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutARouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/_layout/_layout-2/layout-b': { id: '/_layout/_layout-2/layout-b' path: '/layout-b' fullPath: '/layout-b' - preLoaderRoute: typeof LayoutLayout2LayoutBImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutBRouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/posts_/$postId/deep': { id: '/posts_/$postId/deep' path: '/posts/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport + preLoaderRoute: typeof PostsPostIdDeepRouteImport parentRoute: typeof rootRoute } '/redirect/$target/via-beforeLoad': { id: '/redirect/$target/via-beforeLoad' path: '/via-beforeLoad' fullPath: '/redirect/$target/via-beforeLoad' - preLoaderRoute: typeof RedirectTargetViaBeforeLoadImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetViaBeforeLoadRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/via-loader': { id: '/redirect/$target/via-loader' path: '/via-loader' fullPath: '/redirect/$target/via-loader' - preLoaderRoute: typeof RedirectTargetViaLoaderImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetViaLoaderRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/': { id: '/redirect/$target/' path: '/' fullPath: '/redirect/$target/' - preLoaderRoute: typeof RedirectTargetIndexImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetIndexRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/serverFn/via-beforeLoad': { id: '/redirect/$target/serverFn/via-beforeLoad' path: '/serverFn/via-beforeLoad' fullPath: '/redirect/$target/serverFn/via-beforeLoad' - preLoaderRoute: typeof RedirectTargetServerFnViaBeforeLoadImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetServerFnViaBeforeLoadRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/serverFn/via-loader': { id: '/redirect/$target/serverFn/via-loader' path: '/serverFn/via-loader' fullPath: '/redirect/$target/serverFn/via-loader' - preLoaderRoute: typeof RedirectTargetServerFnViaLoaderImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetServerFnViaLoaderRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/serverFn/via-useServerFn': { id: '/redirect/$target/serverFn/via-useServerFn' path: '/serverFn/via-useServerFn' fullPath: '/redirect/$target/serverFn/via-useServerFn' - preLoaderRoute: typeof RedirectTargetServerFnViaUseServerFnImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetServerFnViaUseServerFnRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/serverFn/': { id: '/redirect/$target/serverFn/' path: '/serverFn' fullPath: '/redirect/$target/serverFn' - preLoaderRoute: typeof RedirectTargetServerFnIndexImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetServerFnIndexRouteImport + parentRoute: typeof RedirectTargetRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/not-found/route' { + const createFileRoute: CreateFileRoute< + '/not-found', + FileRoutesByPath['/not-found']['parentRoute'], + FileRoutesByPath['/not-found']['id'], + FileRoutesByPath['/not-found']['path'], + FileRoutesByPath['/not-found']['fullPath'] + > +} +declare module './routes/_layout' { + const createFileRoute: CreateFileRoute< + '/_layout', + FileRoutesByPath['/_layout']['parentRoute'], + FileRoutesByPath['/_layout']['id'], + FileRoutesByPath['/_layout']['path'], + FileRoutesByPath['/_layout']['fullPath'] + > +} +declare module './routes/deferred' { + const createFileRoute: CreateFileRoute< + '/deferred', + FileRoutesByPath['/deferred']['parentRoute'], + FileRoutesByPath['/deferred']['id'], + FileRoutesByPath['/deferred']['path'], + FileRoutesByPath['/deferred']['fullPath'] + > +} +declare module './routes/links' { + const createFileRoute: CreateFileRoute< + '/links', + FileRoutesByPath['/links']['parentRoute'], + FileRoutesByPath['/links']['id'], + FileRoutesByPath['/links']['path'], + FileRoutesByPath['/links']['fullPath'] + > +} +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/scripts' { + const createFileRoute: CreateFileRoute< + '/scripts', + FileRoutesByPath['/scripts']['parentRoute'], + FileRoutesByPath['/scripts']['id'], + FileRoutesByPath['/scripts']['path'], + FileRoutesByPath['/scripts']['fullPath'] + > +} +declare module './routes/search-params' { + const createFileRoute: CreateFileRoute< + '/search-params', + FileRoutesByPath['/search-params']['parentRoute'], + FileRoutesByPath['/search-params']['id'], + FileRoutesByPath['/search-params']['path'], + FileRoutesByPath['/search-params']['fullPath'] + > +} +declare module './routes/stream' { + const createFileRoute: CreateFileRoute< + '/stream', + FileRoutesByPath['/stream']['parentRoute'], + FileRoutesByPath['/stream']['id'], + FileRoutesByPath['/stream']['path'], + FileRoutesByPath['/stream']['fullPath'] + > +} +declare module './routes/users' { + const createFileRoute: CreateFileRoute< + '/users', + FileRoutesByPath['/users']['parentRoute'], + FileRoutesByPath['/users']['id'], + FileRoutesByPath['/users']['path'], + FileRoutesByPath['/users']['fullPath'] + > +} +declare module './routes/_layout/_layout-2' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2', + FileRoutesByPath['/_layout/_layout-2']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2']['id'], + FileRoutesByPath['/_layout/_layout-2']['path'], + FileRoutesByPath['/_layout/_layout-2']['fullPath'] + > +} +declare module './routes/not-found/via-beforeLoad' { + const createFileRoute: CreateFileRoute< + '/not-found/via-beforeLoad', + FileRoutesByPath['/not-found/via-beforeLoad']['parentRoute'], + FileRoutesByPath['/not-found/via-beforeLoad']['id'], + FileRoutesByPath['/not-found/via-beforeLoad']['path'], + FileRoutesByPath['/not-found/via-beforeLoad']['fullPath'] + > +} +declare module './routes/not-found/via-loader' { + const createFileRoute: CreateFileRoute< + '/not-found/via-loader', + FileRoutesByPath['/not-found/via-loader']['parentRoute'], + FileRoutesByPath['/not-found/via-loader']['id'], + FileRoutesByPath['/not-found/via-loader']['path'], + FileRoutesByPath['/not-found/via-loader']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/redirect/$target' { + const createFileRoute: CreateFileRoute< + '/redirect/$target', + FileRoutesByPath['/redirect/$target']['parentRoute'], + FileRoutesByPath['/redirect/$target']['id'], + FileRoutesByPath['/redirect/$target']['path'], + FileRoutesByPath['/redirect/$target']['fullPath'] + > +} +declare module './routes/users.$userId' { + const createFileRoute: CreateFileRoute< + '/users/$userId', + FileRoutesByPath['/users/$userId']['parentRoute'], + FileRoutesByPath['/users/$userId']['id'], + FileRoutesByPath['/users/$userId']['path'], + FileRoutesByPath['/users/$userId']['fullPath'] + > +} +declare module './routes/not-found/index' { + const createFileRoute: CreateFileRoute< + '/not-found/', + FileRoutesByPath['/not-found/']['parentRoute'], + FileRoutesByPath['/not-found/']['id'], + FileRoutesByPath['/not-found/']['path'], + FileRoutesByPath['/not-found/']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/redirect/index' { + const createFileRoute: CreateFileRoute< + '/redirect/', + FileRoutesByPath['/redirect/']['parentRoute'], + FileRoutesByPath['/redirect/']['id'], + FileRoutesByPath['/redirect/']['path'], + FileRoutesByPath['/redirect/']['fullPath'] + > +} +declare module './routes/users.index' { + const createFileRoute: CreateFileRoute< + '/users/', + FileRoutesByPath['/users/']['parentRoute'], + FileRoutesByPath['/users/']['id'], + FileRoutesByPath['/users/']['path'], + FileRoutesByPath['/users/']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-a' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-a', + FileRoutesByPath['/_layout/_layout-2/layout-a']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-b' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-b', + FileRoutesByPath['/_layout/_layout-2/layout-b']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['fullPath'] + > +} +declare module './routes/posts_.$postId.deep' { + const createFileRoute: CreateFileRoute< + '/posts_/$postId/deep', + FileRoutesByPath['/posts_/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > +} +declare module './routes/redirect/$target/via-beforeLoad' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/via-beforeLoad', + FileRoutesByPath['/redirect/$target/via-beforeLoad']['parentRoute'], + FileRoutesByPath['/redirect/$target/via-beforeLoad']['id'], + FileRoutesByPath['/redirect/$target/via-beforeLoad']['path'], + FileRoutesByPath['/redirect/$target/via-beforeLoad']['fullPath'] + > +} +declare module './routes/redirect/$target/via-loader' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/via-loader', + FileRoutesByPath['/redirect/$target/via-loader']['parentRoute'], + FileRoutesByPath['/redirect/$target/via-loader']['id'], + FileRoutesByPath['/redirect/$target/via-loader']['path'], + FileRoutesByPath['/redirect/$target/via-loader']['fullPath'] + > +} +declare module './routes/redirect/$target/index' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/', + FileRoutesByPath['/redirect/$target/']['parentRoute'], + FileRoutesByPath['/redirect/$target/']['id'], + FileRoutesByPath['/redirect/$target/']['path'], + FileRoutesByPath['/redirect/$target/']['fullPath'] + > +} +declare module './routes/redirect/$target/serverFn/via-beforeLoad' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/serverFn/via-beforeLoad', + FileRoutesByPath['/redirect/$target/serverFn/via-beforeLoad']['parentRoute'], + FileRoutesByPath['/redirect/$target/serverFn/via-beforeLoad']['id'], + FileRoutesByPath['/redirect/$target/serverFn/via-beforeLoad']['path'], + FileRoutesByPath['/redirect/$target/serverFn/via-beforeLoad']['fullPath'] + > +} +declare module './routes/redirect/$target/serverFn/via-loader' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/serverFn/via-loader', + FileRoutesByPath['/redirect/$target/serverFn/via-loader']['parentRoute'], + FileRoutesByPath['/redirect/$target/serverFn/via-loader']['id'], + FileRoutesByPath['/redirect/$target/serverFn/via-loader']['path'], + FileRoutesByPath['/redirect/$target/serverFn/via-loader']['fullPath'] + > +} +declare module './routes/redirect/$target/serverFn/via-useServerFn' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/serverFn/via-useServerFn', + FileRoutesByPath['/redirect/$target/serverFn/via-useServerFn']['parentRoute'], + FileRoutesByPath['/redirect/$target/serverFn/via-useServerFn']['id'], + FileRoutesByPath['/redirect/$target/serverFn/via-useServerFn']['path'], + FileRoutesByPath['/redirect/$target/serverFn/via-useServerFn']['fullPath'] + > +} +declare module './routes/redirect/$target/serverFn/index' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/serverFn/', + FileRoutesByPath['/redirect/$target/serverFn/']['parentRoute'], + FileRoutesByPath['/redirect/$target/serverFn/']['id'], + FileRoutesByPath['/redirect/$target/serverFn/']['path'], + FileRoutesByPath['/redirect/$target/serverFn/']['fullPath'] + > +} + // Create and export the route tree interface NotFoundRouteRouteChildren { diff --git a/e2e/react-start/basic/src/routes/_layout.tsx b/e2e/react-start/basic/src/routes/_layout.tsx index 02ddbb1cd9..5c4a461d8d 100644 --- a/e2e/react-start/basic/src/routes/_layout.tsx +++ b/e2e/react-start/basic/src/routes/_layout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-start/basic/src/routes/_layout/_layout-2.tsx b/e2e/react-start/basic/src/routes/_layout/_layout-2.tsx index 3b7dbf2903..483b910862 100644 --- a/e2e/react-start/basic/src/routes/_layout/_layout-2.tsx +++ b/e2e/react-start/basic/src/routes/_layout/_layout-2.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout/_layout-2')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-start/basic/src/routes/_layout/_layout-2/layout-a.tsx b/e2e/react-start/basic/src/routes/_layout/_layout-2/layout-a.tsx index 61e19b4d9f..a190b24202 100644 --- a/e2e/react-start/basic/src/routes/_layout/_layout-2/layout-a.tsx +++ b/e2e/react-start/basic/src/routes/_layout/_layout-2/layout-a.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ +export const Route = createFileRoute({ component: LayoutAComponent, }) diff --git a/e2e/react-start/basic/src/routes/_layout/_layout-2/layout-b.tsx b/e2e/react-start/basic/src/routes/_layout/_layout-2/layout-b.tsx index cceed1fb9a..505f8f6fbf 100644 --- a/e2e/react-start/basic/src/routes/_layout/_layout-2/layout-b.tsx +++ b/e2e/react-start/basic/src/routes/_layout/_layout-2/layout-b.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ +export const Route = createFileRoute({ component: LayoutBComponent, }) diff --git a/e2e/react-start/basic/src/routes/api.users.ts b/e2e/react-start/basic/src/routes/api.users.ts index 74b4ad35ba..5d16d71aa6 100644 --- a/e2e/react-start/basic/src/routes/api.users.ts +++ b/e2e/react-start/basic/src/routes/api.users.ts @@ -1,10 +1,9 @@ -import { json } from '@tanstack/start' -import { createAPIFileRoute } from '@tanstack/start/api' +import { json } from '@tanstack/react-start' import axios from 'redaxios' import type { User } from '~/utils/users' -export const APIRoute = createAPIFileRoute('/api/users')({ +export const ServerRoute = createServerFileRoute().methods({ GET: async ({ request }) => { console.info('Fetching users... @', request.url) const res = await axios.get>( diff --git a/e2e/react-start/basic/src/routes/api/users.$id.ts b/e2e/react-start/basic/src/routes/api/users.$id.ts index 2cfe2322ef..3998d60611 100644 --- a/e2e/react-start/basic/src/routes/api/users.$id.ts +++ b/e2e/react-start/basic/src/routes/api/users.$id.ts @@ -1,10 +1,8 @@ -import { json } from '@tanstack/start' -import { createAPIFileRoute } from '@tanstack/start/api' +import { json } from '@tanstack/react-start' import axios from 'redaxios' - import type { User } from '~/utils/users' -export const APIRoute = createAPIFileRoute('/api/users/$id')({ +export const ServerRoute = createServerFileRoute().methods({ GET: async ({ request, params }) => { console.info(`Fetching users by id=${params.id}... @`, request.url) try { diff --git a/e2e/react-start/basic/src/routes/deferred.tsx b/e2e/react-start/basic/src/routes/deferred.tsx index ae64951716..6b128efea0 100644 --- a/e2e/react-start/basic/src/routes/deferred.tsx +++ b/e2e/react-start/basic/src/routes/deferred.tsx @@ -1,5 +1,5 @@ -import { Await, createFileRoute } from '@tanstack/react-router' -import { createServerFn } from '@tanstack/start' +import { Await } from '@tanstack/react-router' +import { createServerFn } from '@tanstack/react-start' import { Suspense, useState } from 'react' const personServerFn = createServerFn({ method: 'GET' }) @@ -15,7 +15,7 @@ const slowServerFn = createServerFn({ method: 'GET' }) return { name: data.name, randomNumber: Math.floor(Math.random() * 100) } }) -export const Route = createFileRoute('/deferred')({ +export const Route = createFileRoute({ loader: async () => { return { deferredStuff: new Promise((r) => diff --git a/e2e/react-start/basic/src/routes/index.tsx b/e2e/react-start/basic/src/routes/index.tsx index 37169a78b4..f2bb5d3f32 100644 --- a/e2e/react-start/basic/src/routes/index.tsx +++ b/e2e/react-start/basic/src/routes/index.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import { CustomMessage } from '~/components/CustomMessage' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/react-start/basic/src/routes/links.tsx b/e2e/react-start/basic/src/routes/links.tsx index adc8fe9c4d..81b53edfd7 100644 --- a/e2e/react-start/basic/src/routes/links.tsx +++ b/e2e/react-start/basic/src/routes/links.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' -export const Route = createFileRoute('/links')({ +export const Route = createFileRoute({ component: () => { const navigate = Route.useNavigate() return ( diff --git a/e2e/react-start/basic/src/routes/not-found/index.tsx b/e2e/react-start/basic/src/routes/not-found/index.tsx index e754f83c74..7abe4a389f 100644 --- a/e2e/react-start/basic/src/routes/not-found/index.tsx +++ b/e2e/react-start/basic/src/routes/not-found/index.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' -export const Route = createFileRoute('/not-found/')({ +export const Route = createFileRoute({ component: () => { const preload = Route.useSearch({ select: (s) => s.preload }) return ( diff --git a/e2e/react-start/basic/src/routes/not-found/route.tsx b/e2e/react-start/basic/src/routes/not-found/route.tsx index e604e098fd..b8343167f5 100644 --- a/e2e/react-start/basic/src/routes/not-found/route.tsx +++ b/e2e/react-start/basic/src/routes/not-found/route.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import z from 'zod' -export const Route = createFileRoute('/not-found')({ +export const Route = createFileRoute({ validateSearch: z.object({ preload: z.literal(false).optional(), }), diff --git a/e2e/react-start/basic/src/routes/not-found/via-beforeLoad.tsx b/e2e/react-start/basic/src/routes/not-found/via-beforeLoad.tsx index 85164dbab5..cc04e59dec 100644 --- a/e2e/react-start/basic/src/routes/not-found/via-beforeLoad.tsx +++ b/e2e/react-start/basic/src/routes/not-found/via-beforeLoad.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, notFound } from '@tanstack/react-router' +import { notFound } from '@tanstack/react-router' -export const Route = createFileRoute('/not-found/via-beforeLoad')({ +export const Route = createFileRoute({ beforeLoad: () => { throw notFound() }, diff --git a/e2e/react-start/basic/src/routes/not-found/via-loader.tsx b/e2e/react-start/basic/src/routes/not-found/via-loader.tsx index 6174b27f77..8ca69f7bb6 100644 --- a/e2e/react-start/basic/src/routes/not-found/via-loader.tsx +++ b/e2e/react-start/basic/src/routes/not-found/via-loader.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, notFound } from '@tanstack/react-router' +import { notFound } from '@tanstack/react-router' -export const Route = createFileRoute('/not-found/via-loader')({ +export const Route = createFileRoute({ loader: () => { throw notFound() }, diff --git a/e2e/react-start/basic/src/routes/posts.$postId.tsx b/e2e/react-start/basic/src/routes/posts.$postId.tsx index 005228a0fe..68c663c7e8 100644 --- a/e2e/react-start/basic/src/routes/posts.$postId.tsx +++ b/e2e/react-start/basic/src/routes/posts.$postId.tsx @@ -1,10 +1,10 @@ -import { ErrorComponent, Link, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent, Link } from '@tanstack/react-router' import type { ErrorComponentProps } from '@tanstack/react-router' import { fetchPost } from '~/utils/posts' import { NotFound } from '~/components/NotFound' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, @@ -30,7 +30,7 @@ function PostComponent() { postId: post.id, }} activeProps={{ className: 'text-black font-bold' }} - className="block py-1 text-blue-800 hover:text-blue-600" + className="inline-block py-1 text-blue-800 hover:text-blue-600" > Deep View diff --git a/e2e/react-start/basic/src/routes/posts.index.tsx b/e2e/react-start/basic/src/routes/posts.index.tsx index 1bad79b0f7..07e41d1b0b 100644 --- a/e2e/react-start/basic/src/routes/posts.index.tsx +++ b/e2e/react-start/basic/src/routes/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/e2e/react-start/basic/src/routes/posts.tsx b/e2e/react-start/basic/src/routes/posts.tsx index 0f69c18341..6fa5bfbe8b 100644 --- a/e2e/react-start/basic/src/routes/posts.tsx +++ b/e2e/react-start/basic/src/routes/posts.tsx @@ -1,8 +1,8 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '~/utils/posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ head: () => ({ meta: [ { diff --git a/e2e/react-start/basic/src/routes/posts_.$postId.deep.tsx b/e2e/react-start/basic/src/routes/posts_.$postId.deep.tsx index e8f733560b..ea326087b8 100644 --- a/e2e/react-start/basic/src/routes/posts_.$postId.deep.tsx +++ b/e2e/react-start/basic/src/routes/posts_.$postId.deep.tsx @@ -1,9 +1,9 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { PostErrorComponent } from './posts.$postId' import { fetchPost } from '~/utils/posts' -export const Route = createFileRoute('/posts_/$postId/deep')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostDeepComponent, diff --git a/e2e/react-start/basic/src/routes/redirect/$target.tsx b/e2e/react-start/basic/src/routes/redirect/$target.tsx index 686f1c7056..099a7ab0be 100644 --- a/e2e/react-start/basic/src/routes/redirect/$target.tsx +++ b/e2e/react-start/basic/src/routes/redirect/$target.tsx @@ -1,7 +1,7 @@ -import { createFileRoute, retainSearchParams } from '@tanstack/react-router' +import { retainSearchParams } from '@tanstack/react-router' import z from 'zod' -export const Route = createFileRoute('/redirect/$target')({ +export const Route = createFileRoute({ params: { parse: (p) => z diff --git a/e2e/react-start/basic/src/routes/redirect/$target/index.tsx b/e2e/react-start/basic/src/routes/redirect/$target/index.tsx index f399d965cf..d4878e0990 100644 --- a/e2e/react-start/basic/src/routes/redirect/$target/index.tsx +++ b/e2e/react-start/basic/src/routes/redirect/$target/index.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect/$target/')({ +export const Route = createFileRoute({ component: () => { const preload = Route.useSearch({ select: (s) => s.preload }) return ( diff --git a/e2e/react-start/basic/src/routes/redirect/$target/serverFn/index.tsx b/e2e/react-start/basic/src/routes/redirect/$target/serverFn/index.tsx index ddb0d8e996..12118917d6 100644 --- a/e2e/react-start/basic/src/routes/redirect/$target/serverFn/index.tsx +++ b/e2e/react-start/basic/src/routes/redirect/$target/serverFn/index.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect/$target/serverFn/')({ +export const Route = createFileRoute({ component: () => (

diff --git a/e2e/react-start/basic/src/routes/redirect/$target/serverFn/via-beforeLoad.tsx b/e2e/react-start/basic/src/routes/redirect/$target/serverFn/via-beforeLoad.tsx index eed26559f3..3aad8bffa4 100644 --- a/e2e/react-start/basic/src/routes/redirect/$target/serverFn/via-beforeLoad.tsx +++ b/e2e/react-start/basic/src/routes/redirect/$target/serverFn/via-beforeLoad.tsx @@ -1,9 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import { throwRedirect } from '~/components/throwRedirect' -export const Route = createFileRoute( - '/redirect/$target/serverFn/via-beforeLoad', -)({ +export const Route = createFileRoute({ beforeLoad: ({ params: { target }, search: { reloadDocument, externalHost }, diff --git a/e2e/react-start/basic/src/routes/redirect/$target/serverFn/via-loader.tsx b/e2e/react-start/basic/src/routes/redirect/$target/serverFn/via-loader.tsx index 1db205e311..3087fa2e15 100644 --- a/e2e/react-start/basic/src/routes/redirect/$target/serverFn/via-loader.tsx +++ b/e2e/react-start/basic/src/routes/redirect/$target/serverFn/via-loader.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import { throwRedirect } from '~/components/throwRedirect' -export const Route = createFileRoute('/redirect/$target/serverFn/via-loader')({ +export const Route = createFileRoute({ loaderDeps: ({ search: { reloadDocument, externalHost } }) => ({ reloadDocument, externalHost, diff --git a/e2e/react-start/basic/src/routes/redirect/$target/serverFn/via-useServerFn.tsx b/e2e/react-start/basic/src/routes/redirect/$target/serverFn/via-useServerFn.tsx index 866bb19b10..98816a067a 100644 --- a/e2e/react-start/basic/src/routes/redirect/$target/serverFn/via-useServerFn.tsx +++ b/e2e/react-start/basic/src/routes/redirect/$target/serverFn/via-useServerFn.tsx @@ -1,9 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import { RedirectOnClick } from '~/components/RedirectOnClick' -export const Route = createFileRoute( - '/redirect/$target/serverFn/via-useServerFn', -)({ +export const Route = createFileRoute({ component: () => { const { target } = Route.useParams() const { reloadDocument, externalHost } = Route.useSearch() diff --git a/e2e/react-start/basic/src/routes/redirect/$target/via-beforeLoad.tsx b/e2e/react-start/basic/src/routes/redirect/$target/via-beforeLoad.tsx index 14a2492331..bfda558451 100644 --- a/e2e/react-start/basic/src/routes/redirect/$target/via-beforeLoad.tsx +++ b/e2e/react-start/basic/src/routes/redirect/$target/via-beforeLoad.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect/$target/via-beforeLoad')({ +export const Route = createFileRoute({ beforeLoad: ({ params: { target }, search: { reloadDocument, externalHost }, diff --git a/e2e/react-start/basic/src/routes/redirect/$target/via-loader.tsx b/e2e/react-start/basic/src/routes/redirect/$target/via-loader.tsx index 9e6a3fc9db..022d5c1f8c 100644 --- a/e2e/react-start/basic/src/routes/redirect/$target/via-loader.tsx +++ b/e2e/react-start/basic/src/routes/redirect/$target/via-loader.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect/$target/via-loader')({ +export const Route = createFileRoute({ loaderDeps: ({ search: { reloadDocument, externalHost } }) => ({ reloadDocument, externalHost, diff --git a/e2e/react-start/basic/src/routes/redirect/index.tsx b/e2e/react-start/basic/src/routes/redirect/index.tsx index c0b26a1df4..a400e552ab 100644 --- a/e2e/react-start/basic/src/routes/redirect/index.tsx +++ b/e2e/react-start/basic/src/routes/redirect/index.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect/')({ +export const Route = createFileRoute({ component: () => (
({ scripts: [ { diff --git a/e2e/react-start/basic/src/routes/search-params.tsx b/e2e/react-start/basic/src/routes/search-params.tsx index 8ebe45bc34..5ddddc58f0 100644 --- a/e2e/react-start/basic/src/routes/search-params.tsx +++ b/e2e/react-start/basic/src/routes/search-params.tsx @@ -1,7 +1,7 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' import { z } from 'zod' -export const Route = createFileRoute('/search-params')({ +export const Route = createFileRoute({ component: () => { const search = Route.useSearch() return ( diff --git a/e2e/react-start/basic/src/routes/stream.tsx b/e2e/react-start/basic/src/routes/stream.tsx index 691792ac21..a113492e1c 100644 --- a/e2e/react-start/basic/src/routes/stream.tsx +++ b/e2e/react-start/basic/src/routes/stream.tsx @@ -1,7 +1,7 @@ -import { Await, createFileRoute } from '@tanstack/react-router' +import { Await } from '@tanstack/react-router' import { useEffect, useState } from 'react' -export const Route = createFileRoute('/stream')({ +export const Route = createFileRoute({ component: Home, loader() { return { diff --git a/e2e/react-start/basic/src/routes/users.$userId.tsx b/e2e/react-start/basic/src/routes/users.$userId.tsx index 1e2921411a..87f81e0f53 100644 --- a/e2e/react-start/basic/src/routes/users.$userId.tsx +++ b/e2e/react-start/basic/src/routes/users.$userId.tsx @@ -1,15 +1,14 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import axios from 'redaxios' import type { ErrorComponentProps } from '@tanstack/react-router' import type { User } from '~/utils/users' -import { DEPLOY_URL } from '~/utils/users' import { NotFound } from '~/components/NotFound' -export const Route = createFileRoute('/users/$userId')({ +export const Route = createFileRoute({ loader: async ({ params: { userId } }) => { return await axios - .get(DEPLOY_URL + '/api/users/' + userId) + .get('/api/users/' + userId) .then((r) => r.data) .catch(() => { throw new Error('Failed to fetch user') @@ -22,7 +21,7 @@ export const Route = createFileRoute('/users/$userId')({ }, }) -export function UserErrorComponent({ error }: ErrorComponentProps) { +function UserErrorComponent({ error }: ErrorComponentProps) { return } diff --git a/e2e/react-start/basic/src/routes/users.index.tsx b/e2e/react-start/basic/src/routes/users.index.tsx index b6b0ee67fb..662e8b6c68 100644 --- a/e2e/react-start/basic/src/routes/users.index.tsx +++ b/e2e/react-start/basic/src/routes/users.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/users/')({ +export const Route = createFileRoute({ component: UsersIndexComponent, }) diff --git a/e2e/react-start/basic/src/routes/users.tsx b/e2e/react-start/basic/src/routes/users.tsx index 45e070657e..7a07e4e9fd 100644 --- a/e2e/react-start/basic/src/routes/users.tsx +++ b/e2e/react-start/basic/src/routes/users.tsx @@ -1,13 +1,13 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import axios from 'redaxios' import type { User } from '~/utils/users' import { DEPLOY_URL } from '~/utils/users' -export const Route = createFileRoute('/users')({ +export const Route = createFileRoute({ loader: async () => { return await axios - .get>(DEPLOY_URL + '/api/users') + .get>('/api/users') .then((r) => r.data) .catch(() => { throw new Error('Failed to fetch users') diff --git a/e2e/react-start/basic-react-query/src/ssr.tsx b/e2e/react-start/basic/src/server.ts similarity index 53% rename from e2e/react-start/basic-react-query/src/ssr.tsx rename to e2e/react-start/basic/src/server.ts index 65a580f25e..77cb4a1316 100644 --- a/e2e/react-start/basic-react-query/src/ssr.tsx +++ b/e2e/react-start/basic/src/server.ts @@ -1,12 +1,13 @@ +// DO NOT DELETE THIS FILE!!! +// This file is a good smoke test to make sure the custom server entry is working import { createStartHandler, defaultStreamHandler, } from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - import { createRouter } from './router' +console.log("[server-entry]: using custom server entry in 'src/server.ts'") + export default createStartHandler({ createRouter, - getRouterManifest, })(defaultStreamHandler) diff --git a/e2e/react-start/basic/src/ssr.tsx b/e2e/react-start/basic/src/ssr.tsx deleted file mode 100644 index 62572579ac..0000000000 --- a/e2e/react-start/basic/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/start/server' -import { getRouterManifest } from '@tanstack/start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/e2e/react-start/basic/src/tanstack-start.d.ts b/e2e/react-start/basic/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/e2e/react-start/basic/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/react-start/basic/src/utils/posts.tsx b/e2e/react-start/basic/src/utils/posts.tsx index bf139e0ac8..9fdff27673 100644 --- a/e2e/react-start/basic/src/utils/posts.tsx +++ b/e2e/react-start/basic/src/utils/posts.tsx @@ -1,5 +1,5 @@ import { notFound } from '@tanstack/react-router' -import { createServerFn } from '@tanstack/start' +import { createServerFn } from '@tanstack/react-start' import axios from 'redaxios' export type PostType = { diff --git a/e2e/react-start/basic/src/utils/users.tsx b/e2e/react-start/basic/src/utils/users.tsx index 79b45867d5..46be4b1580 100644 --- a/e2e/react-start/basic/src/utils/users.tsx +++ b/e2e/react-start/basic/src/utils/users.tsx @@ -4,7 +4,6 @@ export type User = { email: string } -const PORT = - import.meta.env.VITE_SERVER_PORT || process.env.VITE_SERVER_PORT || 3000 +const PORT = process.env.VITE_SERVER_PORT || 3000 export const DEPLOY_URL = `http://localhost:${PORT}` diff --git a/e2e/react-start/basic/tests/redirect.spec.ts b/e2e/react-start/basic/tests/redirect.spec.ts index 1809b531df..3403243ff0 100644 --- a/e2e/react-start/basic/tests/redirect.spec.ts +++ b/e2e/react-start/basic/tests/redirect.spec.ts @@ -1,10 +1,10 @@ +import queryString from 'node:querystring' import { expect } from '@playwright/test' import combinateImport from 'combinate' import { derivePort, localDummyServer } from '@tanstack/router-e2e-utils' import packageJson from '../package.json' with { type: 'json' } import { test } from './fixture' -import { Server } from 'node:http' -import queryString from 'node:querystring' +import type { Server } from 'node:http' // somehow playwright does not correctly import default exports const combinate = (combinateImport as any).default as typeof combinateImport @@ -44,7 +44,9 @@ test.describe('redirects', () => { const requestPromise = new Promise((resolve) => { page.on('request', (request) => { - if (request.url().startsWith(`http://localhost:${PORT}/_server/`)) { + if ( + request.url().startsWith(`http://localhost:${PORT}/_serverFn/`) + ) { requestHappened = true resolve() } @@ -104,7 +106,7 @@ test.describe('redirects', () => { test(`external target: scenario: ${scenario}, thrower: ${thrower}`, async ({ page, }) => { - let q = queryString.stringify({ + const q = queryString.stringify({ externalHost: `http://localhost:${EXTERNAL_HOST_PORT}/`, }) @@ -138,7 +140,7 @@ test.describe('redirects', () => { page, }) => { let fullPageLoad = false - let q = queryString.stringify({ + const q = queryString.stringify({ externalHost: `http://localhost:${EXTERNAL_HOST_PORT}/`, reloadDocument, }) diff --git a/e2e/react-start/basic/vite.config.ts b/e2e/react-start/basic/vite.config.ts new file mode 100644 index 0000000000..a1b3d840f5 --- /dev/null +++ b/e2e/react-start/basic/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/react-start/plugin/vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/e2e/react-start/clerk-basic/.gitignore b/e2e/react-start/clerk-basic/.gitignore index b15fed94e2..2818549158 100644 --- a/e2e/react-start/clerk-basic/.gitignore +++ b/e2e/react-start/clerk-basic/.gitignore @@ -7,14 +7,10 @@ yarn.lock .cache .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/e2e/react-start/clerk-basic/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/react-start/clerk-basic/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/e2e/react-start/clerk-basic/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/react-start/clerk-basic/app.config.ts b/e2e/react-start/clerk-basic/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/e2e/react-start/clerk-basic/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/e2e/react-start/clerk-basic/package.json b/e2e/react-start/clerk-basic/package.disabled.json similarity index 80% rename from e2e/react-start/clerk-basic/package.json rename to e2e/react-start/clerk-basic/package.disabled.json index c2c2bb13fe..27e0387949 100644 --- a/e2e/react-start/clerk-basic/package.json +++ b/e2e/react-start/clerk-basic/package.disabled.json @@ -1,13 +1,13 @@ { - "name": "tanstack-start-e2e-clerk-basic", + "name": "tanstack-react-start-e2e-clerk-basic", "private": true, "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build", + "start": "node .output/server/index.mjs", "test:e2e": "exit 0; playwright test --project=chromium" }, "dependencies": { @@ -19,7 +19,7 @@ "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "vite": "^6.3.5" }, "devDependencies": { "@playwright/test": "^1.50.1", @@ -28,8 +28,8 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "postcss": "^8.5.1", "autoprefixer": "^10.4.20", + "postcss": "^8.5.1", "tailwindcss": "^3.4.17", "typescript": "^5.7.2", "vite-tsconfig-paths": "^5.1.4" diff --git a/e2e/react-start/clerk-basic/playwright.config.ts b/e2e/react-start/clerk-basic/playwright.config.ts index bb77d0cf70..9806e0c136 100644 --- a/e2e/react-start/clerk-basic/playwright.config.ts +++ b/e2e/react-start/clerk-basic/playwright.config.ts @@ -19,7 +19,7 @@ export default defineConfig({ }, webServer: { - command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm start --port ${PORT}`, + command: `VITE_SERVER_PORT=${PORT} pnpm build && PORT=${PORT} VITE_SERVER_PORT=${PORT} pnpm start`, url: baseURL, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/e2e/react-start/clerk-basic/src/client.tsx b/e2e/react-start/clerk-basic/src/client.tsx deleted file mode 100644 index 31385f57f1..0000000000 --- a/e2e/react-start/clerk-basic/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document!, ) diff --git a/e2e/react-start/clerk-basic/src/routeTree.gen.ts b/e2e/react-start/clerk-basic/src/routeTree.gen.ts index b4b4f459a8..00f53c8623 100644 --- a/e2e/react-start/clerk-basic/src/routeTree.gen.ts +++ b/e2e/react-start/clerk-basic/src/routeTree.gen.ts @@ -8,48 +8,50 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as AuthedImport } from './routes/_authed' -import { Route as IndexImport } from './routes/index' -import { Route as AuthedPostsImport } from './routes/_authed/posts' -import { Route as AuthedPostsIndexImport } from './routes/_authed/posts.index' -import { Route as AuthedProfileSplatImport } from './routes/_authed/profile.$' -import { Route as AuthedPostsPostIdImport } from './routes/_authed/posts.$postId' +import { Route as AuthedRouteImport } from './routes/_authed' +import { Route as IndexRouteImport } from './routes/index' +import { Route as AuthedPostsRouteImport } from './routes/_authed/posts' +import { Route as AuthedPostsIndexRouteImport } from './routes/_authed/posts.index' +import { Route as AuthedProfileSplatRouteImport } from './routes/_authed/profile.$' +import { Route as AuthedPostsPostIdRouteImport } from './routes/_authed/posts.$postId' // Create/Update Routes -const AuthedRoute = AuthedImport.update({ +const AuthedRoute = AuthedRouteImport.update({ id: '/_authed', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const AuthedPostsRoute = AuthedPostsImport.update({ +const AuthedPostsRoute = AuthedPostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => AuthedRoute, } as any) -const AuthedPostsIndexRoute = AuthedPostsIndexImport.update({ +const AuthedPostsIndexRoute = AuthedPostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => AuthedPostsRoute, } as any) -const AuthedProfileSplatRoute = AuthedProfileSplatImport.update({ +const AuthedProfileSplatRoute = AuthedProfileSplatRouteImport.update({ id: '/profile/$', path: '/profile/$', getParentRoute: () => AuthedRoute, } as any) -const AuthedPostsPostIdRoute = AuthedPostsPostIdImport.update({ +const AuthedPostsPostIdRoute = AuthedPostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => AuthedPostsRoute, @@ -63,47 +65,104 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_authed': { id: '/_authed' path: '' fullPath: '' - preLoaderRoute: typeof AuthedImport + preLoaderRoute: typeof AuthedRouteImport parentRoute: typeof rootRoute } '/_authed/posts': { id: '/_authed/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof AuthedPostsImport - parentRoute: typeof AuthedImport + preLoaderRoute: typeof AuthedPostsRouteImport + parentRoute: typeof AuthedRouteImport } '/_authed/posts/$postId': { id: '/_authed/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof AuthedPostsPostIdImport - parentRoute: typeof AuthedPostsImport + preLoaderRoute: typeof AuthedPostsPostIdRouteImport + parentRoute: typeof AuthedPostsRouteImport } '/_authed/profile/$': { id: '/_authed/profile/$' path: '/profile/$' fullPath: '/profile/$' - preLoaderRoute: typeof AuthedProfileSplatImport - parentRoute: typeof AuthedImport + preLoaderRoute: typeof AuthedProfileSplatRouteImport + parentRoute: typeof AuthedRouteImport } '/_authed/posts/': { id: '/_authed/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof AuthedPostsIndexImport - parentRoute: typeof AuthedPostsImport + preLoaderRoute: typeof AuthedPostsIndexRouteImport + parentRoute: typeof AuthedPostsRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_authed' { + const createFileRoute: CreateFileRoute< + '/_authed', + FileRoutesByPath['/_authed']['parentRoute'], + FileRoutesByPath['/_authed']['id'], + FileRoutesByPath['/_authed']['path'], + FileRoutesByPath['/_authed']['fullPath'] + > +} +declare module './routes/_authed/posts' { + const createFileRoute: CreateFileRoute< + '/_authed/posts', + FileRoutesByPath['/_authed/posts']['parentRoute'], + FileRoutesByPath['/_authed/posts']['id'], + FileRoutesByPath['/_authed/posts']['path'], + FileRoutesByPath['/_authed/posts']['fullPath'] + > +} +declare module './routes/_authed/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/_authed/posts/$postId', + FileRoutesByPath['/_authed/posts/$postId']['parentRoute'], + FileRoutesByPath['/_authed/posts/$postId']['id'], + FileRoutesByPath['/_authed/posts/$postId']['path'], + FileRoutesByPath['/_authed/posts/$postId']['fullPath'] + > +} +declare module './routes/_authed/profile.$' { + const createFileRoute: CreateFileRoute< + '/_authed/profile/$', + FileRoutesByPath['/_authed/profile/$']['parentRoute'], + FileRoutesByPath['/_authed/profile/$']['id'], + FileRoutesByPath['/_authed/profile/$']['path'], + FileRoutesByPath['/_authed/profile/$']['fullPath'] + > +} +declare module './routes/_authed/posts.index' { + const createFileRoute: CreateFileRoute< + '/_authed/posts/', + FileRoutesByPath['/_authed/posts/']['parentRoute'], + FileRoutesByPath['/_authed/posts/']['id'], + FileRoutesByPath['/_authed/posts/']['path'], + FileRoutesByPath['/_authed/posts/']['fullPath'] + > +} + // Create and export the route tree interface AuthedPostsRouteChildren { diff --git a/e2e/react-start/clerk-basic/src/routes/__root.tsx b/e2e/react-start/clerk-basic/src/routes/__root.tsx index 2806298d49..569979e37a 100644 --- a/e2e/react-start/clerk-basic/src/routes/__root.tsx +++ b/e2e/react-start/clerk-basic/src/routes/__root.tsx @@ -1,4 +1,3 @@ -/// import { HeadContent, Link, diff --git a/e2e/react-start/clerk-basic/src/routes/_authed.tsx b/e2e/react-start/clerk-basic/src/routes/_authed.tsx index 226ae0829f..6242975272 100644 --- a/e2e/react-start/clerk-basic/src/routes/_authed.tsx +++ b/e2e/react-start/clerk-basic/src/routes/_authed.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import { SignIn } from '@clerk/tanstack-react-start' -export const Route = createFileRoute('/_authed')({ +export const Route = createFileRoute({ beforeLoad: ({ context }) => { if (!context.user.userId) { throw new Error('Not authenticated') diff --git a/e2e/react-start/clerk-basic/src/routes/_authed/posts.$postId.tsx b/e2e/react-start/clerk-basic/src/routes/_authed/posts.$postId.tsx index 27296b9658..49cad9b374 100644 --- a/e2e/react-start/clerk-basic/src/routes/_authed/posts.$postId.tsx +++ b/e2e/react-start/clerk-basic/src/routes/_authed/posts.$postId.tsx @@ -1,10 +1,10 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import type { ErrorComponentProps } from '@tanstack/react-router' import { NotFound } from '~/components/NotFound.js' import { fetchPost } from '~/utils/posts.js' -export const Route = createFileRoute('/_authed/posts/$postId')({ +export const Route = createFileRoute({ loader: ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, diff --git a/e2e/react-start/clerk-basic/src/routes/_authed/posts.index.tsx b/e2e/react-start/clerk-basic/src/routes/_authed/posts.index.tsx index ea9e667e54..13529228bb 100644 --- a/e2e/react-start/clerk-basic/src/routes/_authed/posts.index.tsx +++ b/e2e/react-start/clerk-basic/src/routes/_authed/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_authed/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/e2e/react-start/clerk-basic/src/routes/_authed/posts.tsx b/e2e/react-start/clerk-basic/src/routes/_authed/posts.tsx index c01f12c49a..6c37957e8c 100644 --- a/e2e/react-start/clerk-basic/src/routes/_authed/posts.tsx +++ b/e2e/react-start/clerk-basic/src/routes/_authed/posts.tsx @@ -1,8 +1,8 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '~/utils/posts.js' -export const Route = createFileRoute('/_authed/posts')({ +export const Route = createFileRoute({ loader: () => fetchPosts(), component: PostsComponent, }) diff --git a/e2e/react-start/clerk-basic/src/routes/_authed/profile.$.tsx b/e2e/react-start/clerk-basic/src/routes/_authed/profile.$.tsx index 1e5a8b1429..6c37957e8c 100644 --- a/e2e/react-start/clerk-basic/src/routes/_authed/profile.$.tsx +++ b/e2e/react-start/clerk-basic/src/routes/_authed/profile.$.tsx @@ -1,8 +1,8 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '~/utils/posts.js' -export const Route = createFileRoute('/_authed/profile/$')({ +export const Route = createFileRoute({ loader: () => fetchPosts(), component: PostsComponent, }) diff --git a/e2e/react-start/clerk-basic/src/routes/index.tsx b/e2e/react-start/clerk-basic/src/routes/index.tsx index 6ae388a178..66baf1e9f1 100644 --- a/e2e/react-start/clerk-basic/src/routes/index.tsx +++ b/e2e/react-start/clerk-basic/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/react-start/clerk-basic/src/server.tsx b/e2e/react-start/clerk-basic/src/server.tsx new file mode 100644 index 0000000000..2987216e24 --- /dev/null +++ b/e2e/react-start/clerk-basic/src/server.tsx @@ -0,0 +1,18 @@ +import { + createStartHandler, + defaultStreamHandler, + defineEventHandler, +} from '@tanstack/react-start/server' +import { createClerkHandler } from '@clerk/tanstack-react-start/server' +import { createRouter } from './router' + +export default defineEventHandler((event) => { + const startHandler = createStartHandler({ + createRouter, + }) + + const withClerkHandler = + createClerkHandler(startHandler)(defaultStreamHandler) + + return withClerkHandler(event) +}) diff --git a/e2e/react-start/clerk-basic/src/tanstack-start.d.ts b/e2e/react-start/clerk-basic/src/tanstack-start.d.ts new file mode 100644 index 0000000000..7f91a4813b --- /dev/null +++ b/e2e/react-start/clerk-basic/src/tanstack-start.d.ts @@ -0,0 +1 @@ +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/react-start/clerk-basic/vite.config.ts b/e2e/react-start/clerk-basic/vite.config.ts new file mode 100644 index 0000000000..1df337cd40 --- /dev/null +++ b/e2e/react-start/clerk-basic/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/react-start/plugin/vite' + +export default defineConfig({ + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/e2e/react-start/scroll-restoration/.gitignore b/e2e/react-start/scroll-restoration/.gitignore index be342025da..ca63f49885 100644 --- a/e2e/react-start/scroll-restoration/.gitignore +++ b/e2e/react-start/scroll-restoration/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/e2e/react-start/scroll-restoration/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/react-start/scroll-restoration/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/e2e/react-start/scroll-restoration/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/react-start/scroll-restoration/app.config.ts b/e2e/react-start/scroll-restoration/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/e2e/react-start/scroll-restoration/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/e2e/react-start/scroll-restoration/package.json b/e2e/react-start/scroll-restoration/package.json index 73a72f7300..d4673b5392 100644 --- a/e2e/react-start/scroll-restoration/package.json +++ b/e2e/react-start/scroll-restoration/package.json @@ -1,13 +1,13 @@ { - "name": "tanstack-start-e2e-basic-scroll-restoration", + "name": "tanstack-react-start-e2e-basic-scroll-restoration", "private": true, "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "node .output/server/index.mjs", "test:e2e": "playwright test --project=chromium" }, "dependencies": { @@ -19,7 +19,7 @@ "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", + "vite": "^6.3.5", "zod": "^3.24.2" }, "devDependencies": { diff --git a/e2e/react-start/scroll-restoration/playwright.config.ts b/e2e/react-start/scroll-restoration/playwright.config.ts index 95d043d48b..cf58d18adf 100644 --- a/e2e/react-start/scroll-restoration/playwright.config.ts +++ b/e2e/react-start/scroll-restoration/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ }, webServer: { - command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm start --port ${PORT}`, + command: `VITE_SERVER_PORT=${PORT} pnpm build && PORT=${PORT} VITE_SERVER_PORT=${PORT} pnpm start`, url: baseURL, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/e2e/react-start/scroll-restoration/src/api.ts b/e2e/react-start/scroll-restoration/src/api.ts deleted file mode 100644 index 8b9fef1667..0000000000 --- a/e2e/react-start/scroll-restoration/src/api.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { - createStartAPIHandler, - defaultAPIFileRouteHandler, -} from '@tanstack/react-start/api' - -export default createStartAPIHandler(defaultAPIFileRouteHandler) diff --git a/e2e/react-start/scroll-restoration/src/client.tsx b/e2e/react-start/scroll-restoration/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/e2e/react-start/scroll-restoration/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/scroll-restoration/src/routeTree.gen.ts b/e2e/react-start/scroll-restoration/src/routeTree.gen.ts index f0a79cc008..03dc138db0 100644 --- a/e2e/react-start/scroll-restoration/src/routeTree.gen.ts +++ b/e2e/react-start/scroll-restoration/src/routeTree.gen.ts @@ -8,35 +8,37 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' -import { Route as testsWithSearchImport } from './routes/(tests)/with-search' -import { Route as testsWithLoaderImport } from './routes/(tests)/with-loader' -import { Route as testsNormalPageImport } from './routes/(tests)/normal-page' +import { Route as IndexRouteImport } from './routes/index' +import { Route as testsWithSearchRouteImport } from './routes/(tests)/with-search' +import { Route as testsWithLoaderRouteImport } from './routes/(tests)/with-loader' +import { Route as testsNormalPageRouteImport } from './routes/(tests)/normal-page' // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const testsWithSearchRoute = testsWithSearchImport.update({ +const testsWithSearchRoute = testsWithSearchRouteImport.update({ id: '/(tests)/with-search', path: '/with-search', getParentRoute: () => rootRoute, } as any) -const testsWithLoaderRoute = testsWithLoaderImport.update({ +const testsWithLoaderRoute = testsWithLoaderRouteImport.update({ id: '/(tests)/with-loader', path: '/with-loader', getParentRoute: () => rootRoute, } as any) -const testsNormalPageRoute = testsNormalPageImport.update({ +const testsNormalPageRoute = testsNormalPageRouteImport.update({ id: '/(tests)/normal-page', path: '/normal-page', getParentRoute: () => rootRoute, @@ -50,33 +52,72 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/(tests)/normal-page': { id: '/(tests)/normal-page' path: '/normal-page' fullPath: '/normal-page' - preLoaderRoute: typeof testsNormalPageImport + preLoaderRoute: typeof testsNormalPageRouteImport parentRoute: typeof rootRoute } '/(tests)/with-loader': { id: '/(tests)/with-loader' path: '/with-loader' fullPath: '/with-loader' - preLoaderRoute: typeof testsWithLoaderImport + preLoaderRoute: typeof testsWithLoaderRouteImport parentRoute: typeof rootRoute } '/(tests)/with-search': { id: '/(tests)/with-search' path: '/with-search' fullPath: '/with-search' - preLoaderRoute: typeof testsWithSearchImport + preLoaderRoute: typeof testsWithSearchRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/(tests)/normal-page' { + const createFileRoute: CreateFileRoute< + '/(tests)/normal-page', + FileRoutesByPath['/(tests)/normal-page']['parentRoute'], + FileRoutesByPath['/(tests)/normal-page']['id'], + FileRoutesByPath['/(tests)/normal-page']['path'], + FileRoutesByPath['/(tests)/normal-page']['fullPath'] + > +} +declare module './routes/(tests)/with-loader' { + const createFileRoute: CreateFileRoute< + '/(tests)/with-loader', + FileRoutesByPath['/(tests)/with-loader']['parentRoute'], + FileRoutesByPath['/(tests)/with-loader']['id'], + FileRoutesByPath['/(tests)/with-loader']['path'], + FileRoutesByPath['/(tests)/with-loader']['fullPath'] + > +} +declare module './routes/(tests)/with-search' { + const createFileRoute: CreateFileRoute< + '/(tests)/with-search', + FileRoutesByPath['/(tests)/with-search']['parentRoute'], + FileRoutesByPath['/(tests)/with-search']['id'], + FileRoutesByPath['/(tests)/with-search']['path'], + FileRoutesByPath['/(tests)/with-search']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/e2e/react-start/scroll-restoration/src/routes/(tests)/normal-page.tsx b/e2e/react-start/scroll-restoration/src/routes/(tests)/normal-page.tsx index 95fb7e119e..401397d63c 100644 --- a/e2e/react-start/scroll-restoration/src/routes/(tests)/normal-page.tsx +++ b/e2e/react-start/scroll-restoration/src/routes/(tests)/normal-page.tsx @@ -1,8 +1,7 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' import { ScrollBlock } from '../-components/scroll-block' -export const Route = createFileRoute('/(tests)/normal-page')({ +export const Route = createFileRoute({ component: Component, }) diff --git a/e2e/react-start/scroll-restoration/src/routes/(tests)/with-loader.tsx b/e2e/react-start/scroll-restoration/src/routes/(tests)/with-loader.tsx index dfd4c7bf13..a8da1a2594 100644 --- a/e2e/react-start/scroll-restoration/src/routes/(tests)/with-loader.tsx +++ b/e2e/react-start/scroll-restoration/src/routes/(tests)/with-loader.tsx @@ -1,8 +1,7 @@ -import { createFileRoute } from '@tanstack/react-router' import { ScrollBlock } from '../-components/scroll-block' import { sleep } from '~/utils/posts' -export const Route = createFileRoute('/(tests)/with-loader')({ +export const Route = createFileRoute({ loader: async () => { await sleep(1000) return { foo: 'bar' } diff --git a/e2e/react-start/scroll-restoration/src/routes/(tests)/with-search.tsx b/e2e/react-start/scroll-restoration/src/routes/(tests)/with-search.tsx index 7916c18f73..21e7635e29 100644 --- a/e2e/react-start/scroll-restoration/src/routes/(tests)/with-search.tsx +++ b/e2e/react-start/scroll-restoration/src/routes/(tests)/with-search.tsx @@ -1,9 +1,8 @@ -import { createFileRoute } from '@tanstack/react-router' import { z } from 'zod' import { zodValidator } from '@tanstack/zod-adapter' import { ScrollBlock } from '../-components/scroll-block' -export const Route = createFileRoute('/(tests)/with-search')({ +export const Route = createFileRoute({ validateSearch: zodValidator(z.object({ where: z.string() })), component: Component, }) diff --git a/e2e/react-start/scroll-restoration/src/routes/__root.tsx b/e2e/react-start/scroll-restoration/src/routes/__root.tsx index bf315e98ae..ac55e334cd 100644 --- a/e2e/react-start/scroll-restoration/src/routes/__root.tsx +++ b/e2e/react-start/scroll-restoration/src/routes/__root.tsx @@ -1,12 +1,13 @@ import * as React from 'react' import { + HeadContent, Link, Outlet, + Scripts, createRootRoute, linkOptions, - HeadContent, - Scripts, } from '@tanstack/react-router' +import { TanStackRouterDevtools } from '@tanstack/react-router-devtools' import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary' import { NotFound } from '~/components/NotFound' import appCss from '~/styles/app.css?url' @@ -66,6 +67,7 @@ function RootComponent() { return ( + ) } diff --git a/e2e/react-start/scroll-restoration/src/routes/index.tsx b/e2e/react-start/scroll-restoration/src/routes/index.tsx index 79453d4967..d97ba9ef54 100644 --- a/e2e/react-start/scroll-restoration/src/routes/index.tsx +++ b/e2e/react-start/scroll-restoration/src/routes/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' -import { Link, createFileRoute, linkOptions } from '@tanstack/react-router' +import { Link, linkOptions } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: HomeComponent, }) diff --git a/e2e/react-start/scroll-restoration/src/ssr.tsx b/e2e/react-start/scroll-restoration/src/ssr.tsx deleted file mode 100644 index 65a580f25e..0000000000 --- a/e2e/react-start/scroll-restoration/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/e2e/react-start/scroll-restoration/src/tanstack-start.d.ts b/e2e/react-start/scroll-restoration/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/e2e/react-start/scroll-restoration/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/react-start/scroll-restoration/tsconfig.json b/e2e/react-start/scroll-restoration/tsconfig.json index b3a2d67dfa..09dd95b355 100644 --- a/e2e/react-start/scroll-restoration/tsconfig.json +++ b/e2e/react-start/scroll-restoration/tsconfig.json @@ -17,6 +17,7 @@ "paths": { "~/*": ["./src/*"] }, + "types": ["vite/client"], "noEmit": true } } diff --git a/e2e/react-start/scroll-restoration/vite.config.ts b/e2e/react-start/scroll-restoration/vite.config.ts new file mode 100644 index 0000000000..5b91efb751 --- /dev/null +++ b/e2e/react-start/scroll-restoration/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/react-start/plugin/vite' + +export default defineConfig({ + plugins: [tsConfigPaths({ projects: ['./tsconfig.json'] }), tanstackStart()], +}) diff --git a/e2e/react-start/server-functions/.gitignore b/e2e/react-start/server-functions/.gitignore index be342025da..ca63f49885 100644 --- a/e2e/react-start/server-functions/.gitignore +++ b/e2e/react-start/server-functions/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/e2e/react-start/server-functions/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/react-start/server-functions/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/e2e/react-start/server-functions/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/react-start/server-functions/app.config.ts b/e2e/react-start/server-functions/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/e2e/react-start/server-functions/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/e2e/react-start/server-functions/package.json b/e2e/react-start/server-functions/package.json index 2107818357..075734b7ce 100644 --- a/e2e/react-start/server-functions/package.json +++ b/e2e/react-start/server-functions/package.json @@ -1,13 +1,13 @@ { - "name": "tanstack-start-e2e-server-functions", + "name": "tanstack-react-start-e2e-server-functions", "private": true, "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "node .output/server/index.mjs", "test:e2e": "playwright test --project=chromium" }, "dependencies": { @@ -19,7 +19,7 @@ "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", + "vite": "^6.3.5", "zod": "^3.24.2" }, "devDependencies": { diff --git a/e2e/react-start/server-functions/playwright.config.ts b/e2e/react-start/server-functions/playwright.config.ts index 409765549f..88ff69f92e 100644 --- a/e2e/react-start/server-functions/playwright.config.ts +++ b/e2e/react-start/server-functions/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ }, webServer: { - command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm start --port ${PORT}`, + command: `VITE_SERVER_PORT=${PORT} pnpm build && PORT=${PORT} VITE_SERVER_PORT=${PORT} pnpm start`, url: baseURL, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/e2e/react-start/server-functions/src/client.tsx b/e2e/react-start/server-functions/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/e2e/react-start/server-functions/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/server-functions/src/routeTree.gen.ts b/e2e/react-start/server-functions/src/routeTree.gen.ts index 6025f04091..b767d3415b 100644 --- a/e2e/react-start/server-functions/src/routeTree.gen.ts +++ b/e2e/react-start/server-functions/src/routeTree.gen.ts @@ -8,112 +8,114 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as SubmitPostFormdataImport } from './routes/submit-post-formdata' -import { Route as StatusImport } from './routes/status' -import { Route as SerializeFormDataImport } from './routes/serialize-form-data' -import { Route as ReturnNullImport } from './routes/return-null' -import { Route as RawResponseImport } from './routes/raw-response' -import { Route as MultipartImport } from './routes/multipart' -import { Route as IsomorphicFnsImport } from './routes/isomorphic-fns' -import { Route as HeadersImport } from './routes/headers' -import { Route as EnvOnlyImport } from './routes/env-only' -import { Route as DeadCodePreserveImport } from './routes/dead-code-preserve' -import { Route as ConsistentImport } from './routes/consistent' -import { Route as AbortSignalImport } from './routes/abort-signal' -import { Route as IndexImport } from './routes/index' -import { Route as CookiesIndexImport } from './routes/cookies/index' -import { Route as CookiesSetImport } from './routes/cookies/set' +import { Route as SubmitPostFormdataRouteImport } from './routes/submit-post-formdata' +import { Route as StatusRouteImport } from './routes/status' +import { Route as SerializeFormDataRouteImport } from './routes/serialize-form-data' +import { Route as ReturnNullRouteImport } from './routes/return-null' +import { Route as RawResponseRouteImport } from './routes/raw-response' +import { Route as MultipartRouteImport } from './routes/multipart' +import { Route as IsomorphicFnsRouteImport } from './routes/isomorphic-fns' +import { Route as HeadersRouteImport } from './routes/headers' +import { Route as EnvOnlyRouteImport } from './routes/env-only' +import { Route as DeadCodePreserveRouteImport } from './routes/dead-code-preserve' +import { Route as ConsistentRouteImport } from './routes/consistent' +import { Route as AbortSignalRouteImport } from './routes/abort-signal' +import { Route as IndexRouteImport } from './routes/index' +import { Route as CookiesIndexRouteImport } from './routes/cookies/index' +import { Route as CookiesSetRouteImport } from './routes/cookies/set' // Create/Update Routes -const SubmitPostFormdataRoute = SubmitPostFormdataImport.update({ +const SubmitPostFormdataRoute = SubmitPostFormdataRouteImport.update({ id: '/submit-post-formdata', path: '/submit-post-formdata', getParentRoute: () => rootRoute, } as any) -const StatusRoute = StatusImport.update({ +const StatusRoute = StatusRouteImport.update({ id: '/status', path: '/status', getParentRoute: () => rootRoute, } as any) -const SerializeFormDataRoute = SerializeFormDataImport.update({ +const SerializeFormDataRoute = SerializeFormDataRouteImport.update({ id: '/serialize-form-data', path: '/serialize-form-data', getParentRoute: () => rootRoute, } as any) -const ReturnNullRoute = ReturnNullImport.update({ +const ReturnNullRoute = ReturnNullRouteImport.update({ id: '/return-null', path: '/return-null', getParentRoute: () => rootRoute, } as any) -const RawResponseRoute = RawResponseImport.update({ +const RawResponseRoute = RawResponseRouteImport.update({ id: '/raw-response', path: '/raw-response', getParentRoute: () => rootRoute, } as any) -const MultipartRoute = MultipartImport.update({ +const MultipartRoute = MultipartRouteImport.update({ id: '/multipart', path: '/multipart', getParentRoute: () => rootRoute, } as any) -const IsomorphicFnsRoute = IsomorphicFnsImport.update({ +const IsomorphicFnsRoute = IsomorphicFnsRouteImport.update({ id: '/isomorphic-fns', path: '/isomorphic-fns', getParentRoute: () => rootRoute, } as any) -const HeadersRoute = HeadersImport.update({ +const HeadersRoute = HeadersRouteImport.update({ id: '/headers', path: '/headers', getParentRoute: () => rootRoute, } as any) -const EnvOnlyRoute = EnvOnlyImport.update({ +const EnvOnlyRoute = EnvOnlyRouteImport.update({ id: '/env-only', path: '/env-only', getParentRoute: () => rootRoute, } as any) -const DeadCodePreserveRoute = DeadCodePreserveImport.update({ +const DeadCodePreserveRoute = DeadCodePreserveRouteImport.update({ id: '/dead-code-preserve', path: '/dead-code-preserve', getParentRoute: () => rootRoute, } as any) -const ConsistentRoute = ConsistentImport.update({ +const ConsistentRoute = ConsistentRouteImport.update({ id: '/consistent', path: '/consistent', getParentRoute: () => rootRoute, } as any) -const AbortSignalRoute = AbortSignalImport.update({ +const AbortSignalRoute = AbortSignalRouteImport.update({ id: '/abort-signal', path: '/abort-signal', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const CookiesIndexRoute = CookiesIndexImport.update({ +const CookiesIndexRoute = CookiesIndexRouteImport.update({ id: '/cookies/', path: '/cookies/', getParentRoute: () => rootRoute, } as any) -const CookiesSetRoute = CookiesSetImport.update({ +const CookiesSetRoute = CookiesSetRouteImport.update({ id: '/cookies/set', path: '/cookies/set', getParentRoute: () => rootRoute, @@ -127,110 +129,248 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/abort-signal': { id: '/abort-signal' path: '/abort-signal' fullPath: '/abort-signal' - preLoaderRoute: typeof AbortSignalImport + preLoaderRoute: typeof AbortSignalRouteImport parentRoute: typeof rootRoute } '/consistent': { id: '/consistent' path: '/consistent' fullPath: '/consistent' - preLoaderRoute: typeof ConsistentImport + preLoaderRoute: typeof ConsistentRouteImport parentRoute: typeof rootRoute } '/dead-code-preserve': { id: '/dead-code-preserve' path: '/dead-code-preserve' fullPath: '/dead-code-preserve' - preLoaderRoute: typeof DeadCodePreserveImport + preLoaderRoute: typeof DeadCodePreserveRouteImport parentRoute: typeof rootRoute } '/env-only': { id: '/env-only' path: '/env-only' fullPath: '/env-only' - preLoaderRoute: typeof EnvOnlyImport + preLoaderRoute: typeof EnvOnlyRouteImport parentRoute: typeof rootRoute } '/headers': { id: '/headers' path: '/headers' fullPath: '/headers' - preLoaderRoute: typeof HeadersImport + preLoaderRoute: typeof HeadersRouteImport parentRoute: typeof rootRoute } '/isomorphic-fns': { id: '/isomorphic-fns' path: '/isomorphic-fns' fullPath: '/isomorphic-fns' - preLoaderRoute: typeof IsomorphicFnsImport + preLoaderRoute: typeof IsomorphicFnsRouteImport parentRoute: typeof rootRoute } '/multipart': { id: '/multipart' path: '/multipart' fullPath: '/multipart' - preLoaderRoute: typeof MultipartImport + preLoaderRoute: typeof MultipartRouteImport parentRoute: typeof rootRoute } '/raw-response': { id: '/raw-response' path: '/raw-response' fullPath: '/raw-response' - preLoaderRoute: typeof RawResponseImport + preLoaderRoute: typeof RawResponseRouteImport parentRoute: typeof rootRoute } '/return-null': { id: '/return-null' path: '/return-null' fullPath: '/return-null' - preLoaderRoute: typeof ReturnNullImport + preLoaderRoute: typeof ReturnNullRouteImport parentRoute: typeof rootRoute } '/serialize-form-data': { id: '/serialize-form-data' path: '/serialize-form-data' fullPath: '/serialize-form-data' - preLoaderRoute: typeof SerializeFormDataImport + preLoaderRoute: typeof SerializeFormDataRouteImport parentRoute: typeof rootRoute } '/status': { id: '/status' path: '/status' fullPath: '/status' - preLoaderRoute: typeof StatusImport + preLoaderRoute: typeof StatusRouteImport parentRoute: typeof rootRoute } '/submit-post-formdata': { id: '/submit-post-formdata' path: '/submit-post-formdata' fullPath: '/submit-post-formdata' - preLoaderRoute: typeof SubmitPostFormdataImport + preLoaderRoute: typeof SubmitPostFormdataRouteImport parentRoute: typeof rootRoute } '/cookies/set': { id: '/cookies/set' path: '/cookies/set' fullPath: '/cookies/set' - preLoaderRoute: typeof CookiesSetImport + preLoaderRoute: typeof CookiesSetRouteImport parentRoute: typeof rootRoute } '/cookies/': { id: '/cookies/' path: '/cookies' fullPath: '/cookies' - preLoaderRoute: typeof CookiesIndexImport + preLoaderRoute: typeof CookiesIndexRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/abort-signal' { + const createFileRoute: CreateFileRoute< + '/abort-signal', + FileRoutesByPath['/abort-signal']['parentRoute'], + FileRoutesByPath['/abort-signal']['id'], + FileRoutesByPath['/abort-signal']['path'], + FileRoutesByPath['/abort-signal']['fullPath'] + > +} +declare module './routes/consistent' { + const createFileRoute: CreateFileRoute< + '/consistent', + FileRoutesByPath['/consistent']['parentRoute'], + FileRoutesByPath['/consistent']['id'], + FileRoutesByPath['/consistent']['path'], + FileRoutesByPath['/consistent']['fullPath'] + > +} +declare module './routes/dead-code-preserve' { + const createFileRoute: CreateFileRoute< + '/dead-code-preserve', + FileRoutesByPath['/dead-code-preserve']['parentRoute'], + FileRoutesByPath['/dead-code-preserve']['id'], + FileRoutesByPath['/dead-code-preserve']['path'], + FileRoutesByPath['/dead-code-preserve']['fullPath'] + > +} +declare module './routes/env-only' { + const createFileRoute: CreateFileRoute< + '/env-only', + FileRoutesByPath['/env-only']['parentRoute'], + FileRoutesByPath['/env-only']['id'], + FileRoutesByPath['/env-only']['path'], + FileRoutesByPath['/env-only']['fullPath'] + > +} +declare module './routes/headers' { + const createFileRoute: CreateFileRoute< + '/headers', + FileRoutesByPath['/headers']['parentRoute'], + FileRoutesByPath['/headers']['id'], + FileRoutesByPath['/headers']['path'], + FileRoutesByPath['/headers']['fullPath'] + > +} +declare module './routes/isomorphic-fns' { + const createFileRoute: CreateFileRoute< + '/isomorphic-fns', + FileRoutesByPath['/isomorphic-fns']['parentRoute'], + FileRoutesByPath['/isomorphic-fns']['id'], + FileRoutesByPath['/isomorphic-fns']['path'], + FileRoutesByPath['/isomorphic-fns']['fullPath'] + > +} +declare module './routes/multipart' { + const createFileRoute: CreateFileRoute< + '/multipart', + FileRoutesByPath['/multipart']['parentRoute'], + FileRoutesByPath['/multipart']['id'], + FileRoutesByPath['/multipart']['path'], + FileRoutesByPath['/multipart']['fullPath'] + > +} +declare module './routes/raw-response' { + const createFileRoute: CreateFileRoute< + '/raw-response', + FileRoutesByPath['/raw-response']['parentRoute'], + FileRoutesByPath['/raw-response']['id'], + FileRoutesByPath['/raw-response']['path'], + FileRoutesByPath['/raw-response']['fullPath'] + > +} +declare module './routes/return-null' { + const createFileRoute: CreateFileRoute< + '/return-null', + FileRoutesByPath['/return-null']['parentRoute'], + FileRoutesByPath['/return-null']['id'], + FileRoutesByPath['/return-null']['path'], + FileRoutesByPath['/return-null']['fullPath'] + > +} +declare module './routes/serialize-form-data' { + const createFileRoute: CreateFileRoute< + '/serialize-form-data', + FileRoutesByPath['/serialize-form-data']['parentRoute'], + FileRoutesByPath['/serialize-form-data']['id'], + FileRoutesByPath['/serialize-form-data']['path'], + FileRoutesByPath['/serialize-form-data']['fullPath'] + > +} +declare module './routes/status' { + const createFileRoute: CreateFileRoute< + '/status', + FileRoutesByPath['/status']['parentRoute'], + FileRoutesByPath['/status']['id'], + FileRoutesByPath['/status']['path'], + FileRoutesByPath['/status']['fullPath'] + > +} +declare module './routes/submit-post-formdata' { + const createFileRoute: CreateFileRoute< + '/submit-post-formdata', + FileRoutesByPath['/submit-post-formdata']['parentRoute'], + FileRoutesByPath['/submit-post-formdata']['id'], + FileRoutesByPath['/submit-post-formdata']['path'], + FileRoutesByPath['/submit-post-formdata']['fullPath'] + > +} +declare module './routes/cookies/set' { + const createFileRoute: CreateFileRoute< + '/cookies/set', + FileRoutesByPath['/cookies/set']['parentRoute'], + FileRoutesByPath['/cookies/set']['id'], + FileRoutesByPath['/cookies/set']['path'], + FileRoutesByPath['/cookies/set']['fullPath'] + > +} +declare module './routes/cookies/index' { + const createFileRoute: CreateFileRoute< + '/cookies/', + FileRoutesByPath['/cookies/']['parentRoute'], + FileRoutesByPath['/cookies/']['id'], + FileRoutesByPath['/cookies/']['path'], + FileRoutesByPath['/cookies/']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/e2e/react-start/server-functions/src/routes/abort-signal.tsx b/e2e/react-start/server-functions/src/routes/abort-signal.tsx index 7de90f3143..dd899a4c10 100644 --- a/e2e/react-start/server-functions/src/routes/abort-signal.tsx +++ b/e2e/react-start/server-functions/src/routes/abort-signal.tsx @@ -1,8 +1,7 @@ -import { createFileRoute } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import React from 'react' -export const Route = createFileRoute('/abort-signal')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/e2e/react-start/server-functions/src/routes/consistent.tsx b/e2e/react-start/server-functions/src/routes/consistent.tsx index 5908512fa2..0d07b1833c 100644 --- a/e2e/react-start/server-functions/src/routes/consistent.tsx +++ b/e2e/react-start/server-functions/src/routes/consistent.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' import { createServerFn } from '@tanstack/react-start' @@ -10,7 +9,7 @@ import { createServerFn } from '@tanstack/react-start' * @link https://github.com/TanStack/router/issues/2481 */ -export const Route = createFileRoute('/consistent')({ +export const Route = createFileRoute({ component: ConsistentServerFnCalls, loader: async () => { const data = await cons_serverGetFn1({ data: { username: 'TEST' } }) diff --git a/e2e/react-start/server-functions/src/routes/cookies/index.tsx b/e2e/react-start/server-functions/src/routes/cookies/index.tsx index ae42043959..01a6450bc6 100644 --- a/e2e/react-start/server-functions/src/routes/cookies/index.tsx +++ b/e2e/react-start/server-functions/src/routes/cookies/index.tsx @@ -1,10 +1,10 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { z } from 'zod' const cookieSchema = z .object({ value: z.string() }) .catch(() => ({ value: `CLIENT-${Date.now()}` })) -export const Route = createFileRoute('/cookies/')({ +export const Route = createFileRoute({ validateSearch: cookieSchema, component: RouteComponent, }) diff --git a/e2e/react-start/server-functions/src/routes/cookies/set.tsx b/e2e/react-start/server-functions/src/routes/cookies/set.tsx index fd9e979ab9..965082750e 100644 --- a/e2e/react-start/server-functions/src/routes/cookies/set.tsx +++ b/e2e/react-start/server-functions/src/routes/cookies/set.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import { setCookie } from '@tanstack/react-start/server' import { z } from 'zod' @@ -7,7 +6,7 @@ import React, { useEffect } from 'react' const cookieSchema = z.object({ value: z.string() }) -export const Route = createFileRoute('/cookies/set')({ +export const Route = createFileRoute({ validateSearch: cookieSchema, loaderDeps: ({ search }) => search, loader: async ({ deps }) => { diff --git a/e2e/react-start/server-functions/src/routes/dead-code-preserve.tsx b/e2e/react-start/server-functions/src/routes/dead-code-preserve.tsx index 46273c59e3..7c1d879272 100644 --- a/e2e/react-start/server-functions/src/routes/dead-code-preserve.tsx +++ b/e2e/react-start/server-functions/src/routes/dead-code-preserve.tsx @@ -2,9 +2,8 @@ import * as fs from 'node:fs' import { createServerFn } from '@tanstack/react-start' import { getRequestHeader } from '@tanstack/react-start/server' import { useState } from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/dead-code-preserve')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/e2e/react-start/server-functions/src/routes/env-only.tsx b/e2e/react-start/server-functions/src/routes/env-only.tsx index fe5ae8c1e8..52af89acc2 100644 --- a/e2e/react-start/server-functions/src/routes/env-only.tsx +++ b/e2e/react-start/server-functions/src/routes/env-only.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' import { clientOnly, createServerFn, serverOnly } from '@tanstack/react-start' import { useState } from 'react' @@ -18,7 +17,7 @@ const testOnServer = createServerFn().handler(() => { return { serverOnServer, clientOnServer } }) -export const Route = createFileRoute('/env-only')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/e2e/react-start/server-functions/src/routes/headers.tsx b/e2e/react-start/server-functions/src/routes/headers.tsx index 0b0f1ff7bc..59b09736b9 100644 --- a/e2e/react-start/server-functions/src/routes/headers.tsx +++ b/e2e/react-start/server-functions/src/routes/headers.tsx @@ -1,10 +1,9 @@ -import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' import { createServerFn } from '@tanstack/react-start' import { getHeaders, setHeader } from '@tanstack/react-start/server' import type { HTTPHeaderName } from '@tanstack/react-start/server' -export const Route = createFileRoute('/headers')({ +export const Route = createFileRoute({ loader: async () => { return { testHeaders: await getTestHeaders(), @@ -36,7 +35,7 @@ function ResponseHeaders({ initialTestHeaders: TestHeadersResult }) { const [testHeadersResult, setTestHeadersResult] = - React.useState(initialTestHeaders) + React.useState(null) return (
@@ -58,10 +57,18 @@ function ResponseHeaders({
-

Headers:

-
-          {JSON.stringify(testHeadersResult.headers, null, 2)}
+        

Initial Headers:

+
+          {JSON.stringify(initialTestHeaders.headers, null, 2)}
         
+ {testHeadersResult && ( + <> +

Updated Headers:

+
+              {JSON.stringify(testHeadersResult.headers, null, 2)}
+            
+ + )}
) diff --git a/e2e/react-start/server-functions/src/routes/index.tsx b/e2e/react-start/server-functions/src/routes/index.tsx index 4c3673ed34..90fdb817cd 100644 --- a/e2e/react-start/server-functions/src/routes/index.tsx +++ b/e2e/react-start/server-functions/src/routes/index.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/react-start/server-functions/src/routes/isomorphic-fns.tsx b/e2e/react-start/server-functions/src/routes/isomorphic-fns.tsx index 2c7bbc4a8f..dac800a60f 100644 --- a/e2e/react-start/server-functions/src/routes/isomorphic-fns.tsx +++ b/e2e/react-start/server-functions/src/routes/isomorphic-fns.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' import { createIsomorphicFn, createServerFn } from '@tanstack/react-start' import { useState } from 'react' @@ -16,7 +15,7 @@ const getServerEcho = createServerFn() .validator((input: string) => input) .handler(({ data }) => getEcho(data)) -export const Route = createFileRoute('/isomorphic-fns')({ +export const Route = createFileRoute({ component: RouteComponent, loader() { return { diff --git a/e2e/react-start/server-functions/src/routes/multipart.tsx b/e2e/react-start/server-functions/src/routes/multipart.tsx index a80ca0f1cd..817a181d38 100644 --- a/e2e/react-start/server-functions/src/routes/multipart.tsx +++ b/e2e/react-start/server-functions/src/routes/multipart.tsx @@ -1,8 +1,7 @@ -import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' import { createServerFn } from '@tanstack/react-start' -export const Route = createFileRoute('/multipart')({ +export const Route = createFileRoute({ component: MultipartServerFnCall, }) diff --git a/e2e/react-start/server-functions/src/routes/raw-response.tsx b/e2e/react-start/server-functions/src/routes/raw-response.tsx index cb2c4bfbb8..5c15e08514 100644 --- a/e2e/react-start/server-functions/src/routes/raw-response.tsx +++ b/e2e/react-start/server-functions/src/routes/raw-response.tsx @@ -1,8 +1,8 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' + import { createServerFn } from '@tanstack/react-start' -export const Route = createFileRoute('/raw-response')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/e2e/react-start/server-functions/src/routes/return-null.tsx b/e2e/react-start/server-functions/src/routes/return-null.tsx index 6d83d2762f..8e6fd55e7f 100644 --- a/e2e/react-start/server-functions/src/routes/return-null.tsx +++ b/e2e/react-start/server-functions/src/routes/return-null.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import * as React from 'react' @@ -8,7 +7,7 @@ import * as React from 'react' * @link https://github.com/TanStack/router/issues/2776 */ -export const Route = createFileRoute('/return-null')({ +export const Route = createFileRoute({ component: AllowServerFnReturnNull, }) diff --git a/e2e/react-start/server-functions/src/routes/serialize-form-data.tsx b/e2e/react-start/server-functions/src/routes/serialize-form-data.tsx index 901a22fdc0..486b3cf2ee 100644 --- a/e2e/react-start/server-functions/src/routes/serialize-form-data.tsx +++ b/e2e/react-start/server-functions/src/routes/serialize-form-data.tsx @@ -1,8 +1,8 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' + import { createServerFn } from '@tanstack/react-start' -export const Route = createFileRoute('/serialize-form-data')({ +export const Route = createFileRoute({ component: SerializeFormDataFnCall, }) diff --git a/e2e/react-start/server-functions/src/routes/status.tsx b/e2e/react-start/server-functions/src/routes/status.tsx index b8dcdee2e6..ec279cf906 100644 --- a/e2e/react-start/server-functions/src/routes/status.tsx +++ b/e2e/react-start/server-functions/src/routes/status.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' import { createServerFn, useServerFn } from '@tanstack/react-start' import { setResponseStatus } from '@tanstack/react-start/server' @@ -9,7 +8,7 @@ const helloFn = createServerFn().handler(() => { } }) -export const Route = createFileRoute('/status')({ +export const Route = createFileRoute({ component: StatusComponent, }) diff --git a/e2e/react-start/server-functions/src/routes/submit-post-formdata.tsx b/e2e/react-start/server-functions/src/routes/submit-post-formdata.tsx index 05df922817..2208875ef5 100644 --- a/e2e/react-start/server-functions/src/routes/submit-post-formdata.tsx +++ b/e2e/react-start/server-functions/src/routes/submit-post-formdata.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' -export const Route = createFileRoute('/submit-post-formdata')({ +export const Route = createFileRoute({ component: SubmitPostFormDataFn, }) diff --git a/e2e/react-start/server-functions/src/ssr.tsx b/e2e/react-start/server-functions/src/ssr.tsx deleted file mode 100644 index 65a580f25e..0000000000 --- a/e2e/react-start/server-functions/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/e2e/react-start/server-functions/src/tanstack-start.d.ts b/e2e/react-start/server-functions/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/e2e/react-start/server-functions/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/react-start/server-functions/tests/server-functions.spec.ts b/e2e/react-start/server-functions/tests/server-functions.spec.ts index 56d6608077..80c89004c5 100644 --- a/e2e/react-start/server-functions/tests/server-functions.spec.ts +++ b/e2e/react-start/server-functions/tests/server-functions.spec.ts @@ -179,44 +179,24 @@ test('server function can correctly send and receive headers', async ({ await page.goto('/headers') await page.waitForLoadState('networkidle') - // console.log(await page.getByTestId('test-headers-result').textContent()) - await expect(page.getByTestId('test-headers-result')).toContainText(`{ - "accept": "application/json", - "accept-encoding": "gzip, deflate, br, zstd", - "accept-language": "en-US", - "connection": "keep-alive", - "content-type": "application/json", - "host": "localhost:${PORT}", - "sec-ch-ua": "\\"Chromium\\";v=\\"136\\", \\"HeadlessChrome\\";v=\\"136\\", \\"Not.A/Brand\\";v=\\"99\\"", - "sec-ch-ua-mobile": "?0", - "sec-ch-ua-platform": "\\"Windows\\"", - "sec-fetch-dest": "document", - "sec-fetch-mode": "navigate", - "sec-fetch-site": "none", - "sec-fetch-user": "?1", - "upgrade-insecure-requests": "1", - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.7103.25 Safari/537.36" -}`) + let headers = JSON.parse( + await page.getByTestId('initial-headers-result').innerText(), + ) + expect(headers['host']).toBe(`localhost:${PORT}`) + expect(headers['user-agent']).toContain('Mozilla/5.0') + expect(headers['sec-fetch-mode']).toBe('navigate') await page.getByTestId('test-headers-btn').click() - await page.waitForLoadState('networkidle') + await page.waitForSelector('[data-testid="updated-headers-result"]') + + headers = JSON.parse( + await page.getByTestId('updated-headers-result').innerText(), + ) - await expect(page.getByTestId('test-headers-result')).toContainText(`{ - "host": "localhost:${PORT}", - "connection": "keep-alive", - "sec-ch-ua-platform": "\\"Windows\\"", - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.7103.25 Safari/537.36", - "accept": "application/json", - "sec-ch-ua": "\\"Chromium\\";v=\\"136\\", \\"HeadlessChrome\\";v=\\"136\\", \\"Not.A/Brand\\";v=\\"99\\"", - "content-type": "application/json", - "sec-ch-ua-mobile": "?0", - "accept-language": "en-US", - "sec-fetch-site": "same-origin", - "sec-fetch-mode": "cors", - "sec-fetch-dest": "empty", - "referer": "http://localhost:${PORT}/headers", - "accept-encoding": "gzip, deflate, br, zstd" -}`) + expect(headers['host']).toBe(`localhost:${PORT}`) + expect(headers['user-agent']).toContain('Mozilla/5.0') + expect(headers['sec-fetch-mode']).toBe('cors') + expect(headers['referer']).toBe(`http://localhost:${PORT}/headers`) }) test('Direct POST submitting FormData to a Server function returns the correct message', async ({ diff --git a/e2e/react-start/server-functions/tsconfig.json b/e2e/react-start/server-functions/tsconfig.json index b3a2d67dfa..d35a4b17f4 100644 --- a/e2e/react-start/server-functions/tsconfig.json +++ b/e2e/react-start/server-functions/tsconfig.json @@ -17,6 +17,7 @@ "paths": { "~/*": ["./src/*"] }, - "noEmit": true + "noEmit": true, + "types": ["vite/client"] } } diff --git a/e2e/react-start/server-functions/vite.config.ts b/e2e/react-start/server-functions/vite.config.ts new file mode 100644 index 0000000000..1df337cd40 --- /dev/null +++ b/e2e/react-start/server-functions/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/react-start/plugin/vite' + +export default defineConfig({ + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/e2e/react-start/virtual-routes/.gitignore b/e2e/react-start/virtual-routes/.gitignore new file mode 100644 index 0000000000..a79d5cf129 --- /dev/null +++ b/e2e/react-start/virtual-routes/.gitignore @@ -0,0 +1,20 @@ +node_modules +package-lock.json +yarn.lock + +.DS_Store +.cache +.env +.vercel +.output + +/build/ +/api/ +/server/build +/public/build +# Sentry Config File +.env.sentry-build-plugin +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/e2e/react-start/virtual-routes/.prettierignore b/e2e/react-start/virtual-routes/.prettierignore new file mode 100644 index 0000000000..2be5eaa6ec --- /dev/null +++ b/e2e/react-start/virtual-routes/.prettierignore @@ -0,0 +1,4 @@ +**/build +**/public +pnpm-lock.yaml +routeTree.gen.ts \ No newline at end of file diff --git a/e2e/react-start/virtual-routes/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/react-start/virtual-routes/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..1ff2bf304c --- /dev/null +++ b/e2e/react-start/virtual-routes/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/react-start/virtual-routes/package.json b/e2e/react-start/virtual-routes/package.json new file mode 100644 index 0000000000..b5f66f2287 --- /dev/null +++ b/e2e/react-start/virtual-routes/package.json @@ -0,0 +1,39 @@ +{ + "name": "tanstack-react-start-e2e-virtual-routes", + "private": true, + "sideEffects": false, + "type": "module", + "scripts": { + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "node .output/server/index.mjs", + "test:e2e": "playwright test --project=chromium" + }, + "dependencies": { + "@tanstack/react-router": "workspace:^", + "@tanstack/react-router-devtools": "workspace:^", + "@tanstack/react-start": "workspace:^", + "@tanstack/virtual-file-routes": "workspace:^", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "redaxios": "^0.5.1", + "tailwind-merge": "^2.6.0", + "vite": "^6.3.5", + "zod": "^3.24.2" + }, + "devDependencies": { + "@playwright/test": "^1.50.1", + "@tanstack/router-e2e-utils": "workspace:^", + "@types/node": "^22.10.2", + "@types/react": "^19.0.8", + "@types/react-dom": "^19.0.3", + "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.20", + "combinate": "^1.1.11", + "postcss": "^8.5.1", + "tailwindcss": "^3.4.17", + "typescript": "^5.7.2", + "vite-tsconfig-paths": "^5.1.4" + } +} diff --git a/e2e/react-start/virtual-routes/playwright.config.ts b/e2e/react-start/virtual-routes/playwright.config.ts new file mode 100644 index 0000000000..e834d88cf4 --- /dev/null +++ b/e2e/react-start/virtual-routes/playwright.config.ts @@ -0,0 +1,35 @@ +import { defineConfig, devices } from '@playwright/test' +import { derivePort } from '@tanstack/router-e2e-utils' +import packageJson from './package.json' with { type: 'json' } + +const PORT = derivePort(packageJson.name) +const baseURL = `http://localhost:${PORT}` + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './tests', + workers: 1, + + reporter: [['line']], + + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL, + }, + + webServer: { + command: `pnpm build && VITE_SERVER_PORT=${PORT} PORT=${PORT} pnpm start`, + url: baseURL, + reuseExistingServer: !process.env.CI, + stdout: 'pipe', + }, + + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], +}) diff --git a/e2e/react-start/virtual-routes/postcss.config.mjs b/e2e/react-start/virtual-routes/postcss.config.mjs new file mode 100644 index 0000000000..2e7af2b7f1 --- /dev/null +++ b/e2e/react-start/virtual-routes/postcss.config.mjs @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/e2e/react-start/virtual-routes/public/android-chrome-192x192.png b/e2e/react-start/virtual-routes/public/android-chrome-192x192.png new file mode 100644 index 0000000000..09c8324f8c Binary files /dev/null and b/e2e/react-start/virtual-routes/public/android-chrome-192x192.png differ diff --git a/e2e/react-start/virtual-routes/public/android-chrome-512x512.png b/e2e/react-start/virtual-routes/public/android-chrome-512x512.png new file mode 100644 index 0000000000..11d626ea3d Binary files /dev/null and b/e2e/react-start/virtual-routes/public/android-chrome-512x512.png differ diff --git a/e2e/react-start/virtual-routes/public/apple-touch-icon.png b/e2e/react-start/virtual-routes/public/apple-touch-icon.png new file mode 100644 index 0000000000..5a9423cc02 Binary files /dev/null and b/e2e/react-start/virtual-routes/public/apple-touch-icon.png differ diff --git a/e2e/react-start/virtual-routes/public/favicon-16x16.png b/e2e/react-start/virtual-routes/public/favicon-16x16.png new file mode 100644 index 0000000000..e3389b0044 Binary files /dev/null and b/e2e/react-start/virtual-routes/public/favicon-16x16.png differ diff --git a/e2e/react-start/virtual-routes/public/favicon-32x32.png b/e2e/react-start/virtual-routes/public/favicon-32x32.png new file mode 100644 index 0000000000..900c77d444 Binary files /dev/null and b/e2e/react-start/virtual-routes/public/favicon-32x32.png differ diff --git a/e2e/react-start/virtual-routes/public/favicon.ico b/e2e/react-start/virtual-routes/public/favicon.ico new file mode 100644 index 0000000000..1a1751676f Binary files /dev/null and b/e2e/react-start/virtual-routes/public/favicon.ico differ diff --git a/e2e/react-start/virtual-routes/public/favicon.png b/e2e/react-start/virtual-routes/public/favicon.png new file mode 100644 index 0000000000..1e77bc0609 Binary files /dev/null and b/e2e/react-start/virtual-routes/public/favicon.png differ diff --git a/e2e/react-start/virtual-routes/public/script.js b/e2e/react-start/virtual-routes/public/script.js new file mode 100644 index 0000000000..897477e7d0 --- /dev/null +++ b/e2e/react-start/virtual-routes/public/script.js @@ -0,0 +1,2 @@ +console.log('SCRIPT_1 loaded') +window.SCRIPT_1 = true diff --git a/e2e/react-start/virtual-routes/public/script2.js b/e2e/react-start/virtual-routes/public/script2.js new file mode 100644 index 0000000000..819af30daf --- /dev/null +++ b/e2e/react-start/virtual-routes/public/script2.js @@ -0,0 +1,2 @@ +console.log('SCRIPT_2 loaded') +window.SCRIPT_2 = true diff --git a/e2e/react-start/virtual-routes/public/site.webmanifest b/e2e/react-start/virtual-routes/public/site.webmanifest new file mode 100644 index 0000000000..fa99de77db --- /dev/null +++ b/e2e/react-start/virtual-routes/public/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/e2e/react-start/virtual-routes/routes.ts b/e2e/react-start/virtual-routes/routes.ts new file mode 100644 index 0000000000..ab17b8f58b --- /dev/null +++ b/e2e/react-start/virtual-routes/routes.ts @@ -0,0 +1,24 @@ +import { + index, + layout, + physical, + rootRoute, + route, +} from '@tanstack/virtual-file-routes' + +export const routes = rootRoute('root.tsx', [ + index('home.tsx'), + route('/posts', 'posts/posts.tsx', [ + index('posts/posts-home.tsx'), + route('$postId', 'posts/posts-detail.tsx'), + ]), + layout('first', 'layout/first-layout.tsx', [ + layout('layout/second-layout.tsx', [ + route('route-without-file', [ + route('/layout-a', 'a.tsx'), + route('/layout-b', 'b.tsx'), + ]), + ]), + ]), + physical('/classic', 'file-based-subtree'), +]) diff --git a/e2e/react-start/virtual-routes/src/posts.tsx b/e2e/react-start/virtual-routes/src/posts.tsx new file mode 100644 index 0000000000..3ccf1ff421 --- /dev/null +++ b/e2e/react-start/virtual-routes/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/e2e/react-start/virtual-routes/src/routeTree.gen.ts b/e2e/react-start/virtual-routes/src/routeTree.gen.ts new file mode 100644 index 0000000000..c6ef800c5a --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routeTree.gen.ts @@ -0,0 +1,584 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { createFileRoute } from '@tanstack/react-router' +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + +// Import Routes + +import { Route as rootRoute } from './routes/root' +import { Route as postsPostsRouteImport } from './routes/posts/posts' +import { Route as layoutFirstLayoutRouteImport } from './routes/layout/first-layout' +import { Route as homeRouteImport } from './routes/home' +import { Route as postsPostsDetailRouteImport } from './routes/posts/posts-detail' +import { Route as layoutSecondLayoutRouteImport } from './routes/layout/second-layout' +import { Route as postsPostsHomeRouteImport } from './routes/posts/posts-home' +import { Route as ClassicHelloRouteRouteImport } from './routes/file-based-subtree/hello/route' +import { Route as ClassicHelloIndexRouteImport } from './routes/file-based-subtree/hello/index' +import { Route as ClassicHelloWorldRouteImport } from './routes/file-based-subtree/hello/world' +import { Route as ClassicHelloUniverseRouteImport } from './routes/file-based-subtree/hello/universe' +import { Route as bRouteImport } from './routes/b' +import { Route as aRouteImport } from './routes/a' + +// Create Virtual Routes + +const FirstSecondLayoutRouteWithoutFileRouteImport = createFileRoute( + '/_first/_second-layout/route-without-file', +)() + +// Create/Update Routes + +const postsPostsRoute = postsPostsRouteImport.update({ + id: '/posts', + path: '/posts', + getParentRoute: () => rootRoute, +} as any) + +const layoutFirstLayoutRoute = layoutFirstLayoutRouteImport.update({ + id: '/_first', + getParentRoute: () => rootRoute, +} as any) + +const homeRoute = homeRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRoute, +} as any) + +const postsPostsDetailRoute = postsPostsDetailRouteImport.update({ + id: '/$postId', + path: '/$postId', + getParentRoute: () => postsPostsRoute, +} as any) + +const layoutSecondLayoutRoute = layoutSecondLayoutRouteImport.update({ + id: '/_second-layout', + getParentRoute: () => layoutFirstLayoutRoute, +} as any) + +const postsPostsHomeRoute = postsPostsHomeRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => postsPostsRoute, +} as any) + +const ClassicHelloRouteRoute = ClassicHelloRouteRouteImport.update({ + id: '/classic/hello', + path: '/classic/hello', + getParentRoute: () => rootRoute, +} as any) + +const ClassicHelloIndexRoute = ClassicHelloIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => ClassicHelloRouteRoute, +} as any) + +const ClassicHelloWorldRoute = ClassicHelloWorldRouteImport.update({ + id: '/world', + path: '/world', + getParentRoute: () => ClassicHelloRouteRoute, +} as any) + +const ClassicHelloUniverseRoute = ClassicHelloUniverseRouteImport.update({ + id: '/universe', + path: '/universe', + getParentRoute: () => ClassicHelloRouteRoute, +} as any) + +const FirstSecondLayoutRouteWithoutFileRoute = + FirstSecondLayoutRouteWithoutFileRouteImport.update({ + id: '/route-without-file', + path: '/route-without-file', + getParentRoute: () => layoutSecondLayoutRoute, + } as any) + +const bRoute = bRouteImport.update({ + id: '/layout-b', + path: '/layout-b', + getParentRoute: () => FirstSecondLayoutRouteWithoutFileRoute, +} as any) + +const aRoute = aRouteImport.update({ + id: '/layout-a', + path: '/layout-a', + getParentRoute: () => FirstSecondLayoutRouteWithoutFileRoute, +} as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof homeRouteImport + parentRoute: typeof rootRoute + } + '/_first': { + id: '/_first' + path: '' + fullPath: '' + preLoaderRoute: typeof layoutFirstLayoutRouteImport + parentRoute: typeof rootRoute + } + '/posts': { + id: '/posts' + path: '/posts' + fullPath: '/posts' + preLoaderRoute: typeof postsPostsRouteImport + parentRoute: typeof rootRoute + } + '/classic/hello': { + id: '/classic/hello' + path: '/classic/hello' + fullPath: '/classic/hello' + preLoaderRoute: typeof ClassicHelloRouteRouteImport + parentRoute: typeof rootRoute + } + '/posts/': { + id: '/posts/' + path: '/' + fullPath: '/posts/' + preLoaderRoute: typeof postsPostsHomeRouteImport + parentRoute: typeof postsPostsRouteImport + } + '/_first/_second-layout': { + id: '/_first/_second-layout' + path: '' + fullPath: '' + preLoaderRoute: typeof layoutSecondLayoutRouteImport + parentRoute: typeof layoutFirstLayoutRouteImport + } + '/posts/$postId': { + id: '/posts/$postId' + path: '/$postId' + fullPath: '/posts/$postId' + preLoaderRoute: typeof postsPostsDetailRouteImport + parentRoute: typeof postsPostsRouteImport + } + '/_first/_second-layout/route-without-file': { + id: '/_first/_second-layout/route-without-file' + path: '/route-without-file' + fullPath: '/route-without-file' + preLoaderRoute: typeof FirstSecondLayoutRouteWithoutFileRouteImport + parentRoute: typeof layoutSecondLayoutRouteImport + } + '/classic/hello/universe': { + id: '/classic/hello/universe' + path: '/universe' + fullPath: '/classic/hello/universe' + preLoaderRoute: typeof ClassicHelloUniverseRouteImport + parentRoute: typeof ClassicHelloRouteRouteImport + } + '/classic/hello/world': { + id: '/classic/hello/world' + path: '/world' + fullPath: '/classic/hello/world' + preLoaderRoute: typeof ClassicHelloWorldRouteImport + parentRoute: typeof ClassicHelloRouteRouteImport + } + '/classic/hello/': { + id: '/classic/hello/' + path: '/' + fullPath: '/classic/hello/' + preLoaderRoute: typeof ClassicHelloIndexRouteImport + parentRoute: typeof ClassicHelloRouteRouteImport + } + '/_first/_second-layout/route-without-file/layout-a': { + id: '/_first/_second-layout/route-without-file/layout-a' + path: '/layout-a' + fullPath: '/route-without-file/layout-a' + preLoaderRoute: typeof aRouteImport + parentRoute: typeof FirstSecondLayoutRouteWithoutFileRouteImport + } + '/_first/_second-layout/route-without-file/layout-b': { + id: '/_first/_second-layout/route-without-file/layout-b' + path: '/layout-b' + fullPath: '/route-without-file/layout-b' + preLoaderRoute: typeof bRouteImport + parentRoute: typeof FirstSecondLayoutRouteWithoutFileRouteImport + } + } +} + +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/home' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/layout/first-layout' { + const createFileRoute: CreateFileRoute< + '/_first', + FileRoutesByPath['/_first']['parentRoute'], + FileRoutesByPath['/_first']['id'], + FileRoutesByPath['/_first']['path'], + FileRoutesByPath['/_first']['fullPath'] + > +} +declare module './routes/posts/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/route' { + const createFileRoute: CreateFileRoute< + '/classic/hello', + FileRoutesByPath['/classic/hello']['parentRoute'], + FileRoutesByPath['/classic/hello']['id'], + FileRoutesByPath['/classic/hello']['path'], + FileRoutesByPath['/classic/hello']['fullPath'] + > +} +declare module './routes/posts/posts-home' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/layout/second-layout' { + const createFileRoute: CreateFileRoute< + '/_first/_second-layout', + FileRoutesByPath['/_first/_second-layout']['parentRoute'], + FileRoutesByPath['/_first/_second-layout']['id'], + FileRoutesByPath['/_first/_second-layout']['path'], + FileRoutesByPath['/_first/_second-layout']['fullPath'] + > +} +declare module './routes/posts/posts-detail' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} + +declare module './routes/file-based-subtree/hello/universe' { + const createFileRoute: CreateFileRoute< + '/classic/hello/universe', + FileRoutesByPath['/classic/hello/universe']['parentRoute'], + FileRoutesByPath['/classic/hello/universe']['id'], + FileRoutesByPath['/classic/hello/universe']['path'], + FileRoutesByPath['/classic/hello/universe']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/world' { + const createFileRoute: CreateFileRoute< + '/classic/hello/world', + FileRoutesByPath['/classic/hello/world']['parentRoute'], + FileRoutesByPath['/classic/hello/world']['id'], + FileRoutesByPath['/classic/hello/world']['path'], + FileRoutesByPath['/classic/hello/world']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/index' { + const createFileRoute: CreateFileRoute< + '/classic/hello/', + FileRoutesByPath['/classic/hello/']['parentRoute'], + FileRoutesByPath['/classic/hello/']['id'], + FileRoutesByPath['/classic/hello/']['path'], + FileRoutesByPath['/classic/hello/']['fullPath'] + > +} +declare module './routes/a' { + const createFileRoute: CreateFileRoute< + '/_first/_second-layout/route-without-file/layout-a', + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-a']['parentRoute'], + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-a']['id'], + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-a']['path'], + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-a']['fullPath'] + > +} +declare module './routes/b' { + const createFileRoute: CreateFileRoute< + '/_first/_second-layout/route-without-file/layout-b', + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-b']['parentRoute'], + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-b']['id'], + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-b']['path'], + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-b']['fullPath'] + > +} + +// Create and export the route tree + +interface FirstSecondLayoutRouteWithoutFileRouteChildren { + aRoute: typeof aRoute + bRoute: typeof bRoute +} + +const FirstSecondLayoutRouteWithoutFileRouteChildren: FirstSecondLayoutRouteWithoutFileRouteChildren = + { + aRoute: aRoute, + bRoute: bRoute, + } + +const FirstSecondLayoutRouteWithoutFileRouteWithChildren = + FirstSecondLayoutRouteWithoutFileRoute._addFileChildren( + FirstSecondLayoutRouteWithoutFileRouteChildren, + ) + +interface layoutSecondLayoutRouteChildren { + FirstSecondLayoutRouteWithoutFileRoute: typeof FirstSecondLayoutRouteWithoutFileRouteWithChildren +} + +const layoutSecondLayoutRouteChildren: layoutSecondLayoutRouteChildren = { + FirstSecondLayoutRouteWithoutFileRoute: + FirstSecondLayoutRouteWithoutFileRouteWithChildren, +} + +const layoutSecondLayoutRouteWithChildren = + layoutSecondLayoutRoute._addFileChildren(layoutSecondLayoutRouteChildren) + +interface layoutFirstLayoutRouteChildren { + layoutSecondLayoutRoute: typeof layoutSecondLayoutRouteWithChildren +} + +const layoutFirstLayoutRouteChildren: layoutFirstLayoutRouteChildren = { + layoutSecondLayoutRoute: layoutSecondLayoutRouteWithChildren, +} + +const layoutFirstLayoutRouteWithChildren = + layoutFirstLayoutRoute._addFileChildren(layoutFirstLayoutRouteChildren) + +interface postsPostsRouteChildren { + postsPostsHomeRoute: typeof postsPostsHomeRoute + postsPostsDetailRoute: typeof postsPostsDetailRoute +} + +const postsPostsRouteChildren: postsPostsRouteChildren = { + postsPostsHomeRoute: postsPostsHomeRoute, + postsPostsDetailRoute: postsPostsDetailRoute, +} + +const postsPostsRouteWithChildren = postsPostsRoute._addFileChildren( + postsPostsRouteChildren, +) + +interface ClassicHelloRouteRouteChildren { + ClassicHelloUniverseRoute: typeof ClassicHelloUniverseRoute + ClassicHelloWorldRoute: typeof ClassicHelloWorldRoute + ClassicHelloIndexRoute: typeof ClassicHelloIndexRoute +} + +const ClassicHelloRouteRouteChildren: ClassicHelloRouteRouteChildren = { + ClassicHelloUniverseRoute: ClassicHelloUniverseRoute, + ClassicHelloWorldRoute: ClassicHelloWorldRoute, + ClassicHelloIndexRoute: ClassicHelloIndexRoute, +} + +const ClassicHelloRouteRouteWithChildren = + ClassicHelloRouteRoute._addFileChildren(ClassicHelloRouteRouteChildren) + +export interface FileRoutesByFullPath { + '/': typeof homeRoute + '': typeof layoutSecondLayoutRouteWithChildren + '/posts': typeof postsPostsRouteWithChildren + '/classic/hello': typeof ClassicHelloRouteRouteWithChildren + '/posts/': typeof postsPostsHomeRoute + '/posts/$postId': typeof postsPostsDetailRoute + '/route-without-file': typeof FirstSecondLayoutRouteWithoutFileRouteWithChildren + '/classic/hello/universe': typeof ClassicHelloUniverseRoute + '/classic/hello/world': typeof ClassicHelloWorldRoute + '/classic/hello/': typeof ClassicHelloIndexRoute + '/route-without-file/layout-a': typeof aRoute + '/route-without-file/layout-b': typeof bRoute +} + +export interface FileRoutesByTo { + '/': typeof homeRoute + '': typeof layoutSecondLayoutRouteWithChildren + '/posts': typeof postsPostsHomeRoute + '/posts/$postId': typeof postsPostsDetailRoute + '/route-without-file': typeof FirstSecondLayoutRouteWithoutFileRouteWithChildren + '/classic/hello/universe': typeof ClassicHelloUniverseRoute + '/classic/hello/world': typeof ClassicHelloWorldRoute + '/classic/hello': typeof ClassicHelloIndexRoute + '/route-without-file/layout-a': typeof aRoute + '/route-without-file/layout-b': typeof bRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/': typeof homeRoute + '/_first': typeof layoutFirstLayoutRouteWithChildren + '/posts': typeof postsPostsRouteWithChildren + '/classic/hello': typeof ClassicHelloRouteRouteWithChildren + '/posts/': typeof postsPostsHomeRoute + '/_first/_second-layout': typeof layoutSecondLayoutRouteWithChildren + '/posts/$postId': typeof postsPostsDetailRoute + '/_first/_second-layout/route-without-file': typeof FirstSecondLayoutRouteWithoutFileRouteWithChildren + '/classic/hello/universe': typeof ClassicHelloUniverseRoute + '/classic/hello/world': typeof ClassicHelloWorldRoute + '/classic/hello/': typeof ClassicHelloIndexRoute + '/_first/_second-layout/route-without-file/layout-a': typeof aRoute + '/_first/_second-layout/route-without-file/layout-b': typeof bRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/' + | '' + | '/posts' + | '/classic/hello' + | '/posts/' + | '/posts/$postId' + | '/route-without-file' + | '/classic/hello/universe' + | '/classic/hello/world' + | '/classic/hello/' + | '/route-without-file/layout-a' + | '/route-without-file/layout-b' + fileRoutesByTo: FileRoutesByTo + to: + | '/' + | '' + | '/posts' + | '/posts/$postId' + | '/route-without-file' + | '/classic/hello/universe' + | '/classic/hello/world' + | '/classic/hello' + | '/route-without-file/layout-a' + | '/route-without-file/layout-b' + id: + | '__root__' + | '/' + | '/_first' + | '/posts' + | '/classic/hello' + | '/posts/' + | '/_first/_second-layout' + | '/posts/$postId' + | '/_first/_second-layout/route-without-file' + | '/classic/hello/universe' + | '/classic/hello/world' + | '/classic/hello/' + | '/_first/_second-layout/route-without-file/layout-a' + | '/_first/_second-layout/route-without-file/layout-b' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + homeRoute: typeof homeRoute + layoutFirstLayoutRoute: typeof layoutFirstLayoutRouteWithChildren + postsPostsRoute: typeof postsPostsRouteWithChildren + ClassicHelloRouteRoute: typeof ClassicHelloRouteRouteWithChildren +} + +const rootRouteChildren: RootRouteChildren = { + homeRoute: homeRoute, + layoutFirstLayoutRoute: layoutFirstLayoutRouteWithChildren, + postsPostsRoute: postsPostsRouteWithChildren, + ClassicHelloRouteRoute: ClassicHelloRouteRouteWithChildren, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* 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-layout" + ] + }, + "/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-layout": { + "filePath": "layout/second-layout.tsx", + "parent": "/_first", + "children": [ + "/_first/_second-layout/route-without-file" + ] + }, + "/posts/$postId": { + "filePath": "posts/posts-detail.tsx", + "parent": "/posts" + }, + "/_first/_second-layout/route-without-file": { + "filePath": "", + "parent": "/_first/_second-layout", + "children": [ + "/_first/_second-layout/route-without-file/layout-a", + "/_first/_second-layout/route-without-file/layout-b" + ] + }, + "/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" + }, + "/_first/_second-layout/route-without-file/layout-a": { + "filePath": "a.tsx", + "parent": "/_first/_second-layout/route-without-file" + }, + "/_first/_second-layout/route-without-file/layout-b": { + "filePath": "b.tsx", + "parent": "/_first/_second-layout/route-without-file" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/react-start/virtual-routes/src/router.tsx b/e2e/react-start/virtual-routes/src/router.tsx new file mode 100644 index 0000000000..b8744cb41f --- /dev/null +++ b/e2e/react-start/virtual-routes/src/router.tsx @@ -0,0 +1,18 @@ +import { createRouter as createTanStackRouter } from '@tanstack/react-router' +import { routeTree } from './routeTree.gen' + +export function createRouter() { + const router = createTanStackRouter({ + routeTree, + defaultPreload: 'intent', + scrollRestoration: true, + }) + + return router +} + +declare module '@tanstack/react-router' { + interface Register { + router: ReturnType + } +} diff --git a/e2e/react-start/virtual-routes/src/routes/a.tsx b/e2e/react-start/virtual-routes/src/routes/a.tsx new file mode 100644 index 0000000000..a190b24202 --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routes/a.tsx @@ -0,0 +1,7 @@ +export const Route = createFileRoute({ + component: LayoutAComponent, +}) + +function LayoutAComponent() { + return
I'm layout A!
+} diff --git a/e2e/react-start/virtual-routes/src/routes/b.tsx b/e2e/react-start/virtual-routes/src/routes/b.tsx new file mode 100644 index 0000000000..505f8f6fbf --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routes/b.tsx @@ -0,0 +1,7 @@ +export const Route = createFileRoute({ + component: LayoutBComponent, +}) + +function LayoutBComponent() { + return
I'm layout B!
+} diff --git a/e2e/react-start/virtual-routes/src/routes/file-based-subtree/hello/index.tsx b/e2e/react-start/virtual-routes/src/routes/file-based-subtree/hello/index.tsx new file mode 100644 index 0000000000..f86335e291 --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routes/file-based-subtree/hello/index.tsx @@ -0,0 +1,3 @@ +export const Route = createFileRoute({ + component: () =>
This is the index
, +}) diff --git a/e2e/react-start/virtual-routes/src/routes/file-based-subtree/hello/route.tsx b/e2e/react-start/virtual-routes/src/routes/file-based-subtree/hello/route.tsx new file mode 100644 index 0000000000..620dd2b76b --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routes/file-based-subtree/hello/route.tsx @@ -0,0 +1,27 @@ +import { Link, Outlet } from '@tanstack/react-router' + +export const Route = createFileRoute({ + component: () => ( +
+ Hello! +
{' '} + + say hello to the universe + {' '} + + say hello to the world + + +
+ ), +}) diff --git a/e2e/react-start/virtual-routes/src/routes/file-based-subtree/hello/universe.tsx b/e2e/react-start/virtual-routes/src/routes/file-based-subtree/hello/universe.tsx new file mode 100644 index 0000000000..20b07c41cc --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routes/file-based-subtree/hello/universe.tsx @@ -0,0 +1,3 @@ +export const Route = createFileRoute({ + component: () =>
Hello /classic/hello/universe!
, +}) diff --git a/e2e/react-start/virtual-routes/src/routes/file-based-subtree/hello/world.tsx b/e2e/react-start/virtual-routes/src/routes/file-based-subtree/hello/world.tsx new file mode 100644 index 0000000000..4af11357a2 --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routes/file-based-subtree/hello/world.tsx @@ -0,0 +1,3 @@ +export const Route = createFileRoute({ + component: () =>
Hello /classic/hello/world!
, +}) diff --git a/e2e/react-start/virtual-routes/src/routes/home.tsx b/e2e/react-start/virtual-routes/src/routes/home.tsx new file mode 100644 index 0000000000..b23956ae17 --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routes/home.tsx @@ -0,0 +1,13 @@ +import * as React from 'react' + +export const Route = createFileRoute({ + component: Home, +}) + +function Home() { + return ( +
+

Welcome Home!

+
+ ) +} diff --git a/e2e/react-start/virtual-routes/src/routes/layout/first-layout.tsx b/e2e/react-start/virtual-routes/src/routes/layout/first-layout.tsx new file mode 100644 index 0000000000..5c4a461d8d --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routes/layout/first-layout.tsx @@ -0,0 +1,16 @@ +import { Outlet } from '@tanstack/react-router' + +export const Route = createFileRoute({ + component: LayoutComponent, +}) + +function LayoutComponent() { + return ( +
+
I'm a layout
+
+ +
+
+ ) +} diff --git a/e2e/react-start/virtual-routes/src/routes/layout/second-layout.tsx b/e2e/react-start/virtual-routes/src/routes/layout/second-layout.tsx new file mode 100644 index 0000000000..478d9afbec --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routes/layout/second-layout.tsx @@ -0,0 +1,34 @@ +import { Link, Outlet } from '@tanstack/react-router' + +export const Route = createFileRoute({ + component: LayoutComponent, +}) + +function LayoutComponent() { + return ( +
+
I'm a nested layout
+
+ + Layout A + + + Layout B + +
+
+ +
+
+ ) +} diff --git a/e2e/react-start/virtual-routes/src/routes/posts/posts-detail.tsx b/e2e/react-start/virtual-routes/src/routes/posts/posts-detail.tsx new file mode 100644 index 0000000000..654f3cfd18 --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routes/posts/posts-detail.tsx @@ -0,0 +1,28 @@ +import * as React from 'react' +import { ErrorComponent } from '@tanstack/react-router' +import { fetchPost } from '../../posts' +import type { ErrorComponentProps } from '@tanstack/react-router' + +export const Route = createFileRoute({ + 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/e2e/react-start/virtual-routes/src/routes/posts/posts-home.tsx b/e2e/react-start/virtual-routes/src/routes/posts/posts-home.tsx new file mode 100644 index 0000000000..fdbe5865e5 --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routes/posts/posts-home.tsx @@ -0,0 +1,9 @@ +import * as React from 'react' + +export const Route = createFileRoute({ + component: PostsIndexComponent, +}) + +function PostsIndexComponent() { + return
Select a post.
+} diff --git a/e2e/react-start/virtual-routes/src/routes/posts/posts.tsx b/e2e/react-start/virtual-routes/src/routes/posts/posts.tsx new file mode 100644 index 0000000000..f92c37f537 --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routes/posts/posts.tsx @@ -0,0 +1,39 @@ +import * as React from 'react' +import { Link, Outlet } from '@tanstack/react-router' +import { fetchPosts } from '../../posts' + +export const Route = createFileRoute({ + loader: fetchPosts, + component: PostsComponent, +}) + +function PostsComponent() { + const posts = Route.useLoaderData() + + return ( +
+
    + {[...posts, { id: 'i-do-not-exist', title: 'Non-existent Post' }].map( + (post) => { + return ( +
  • + +
    {post.title.substring(0, 20)}
    + +
  • + ) + }, + )} +
+
+ +
+ ) +} diff --git a/e2e/react-start/virtual-routes/src/routes/root.tsx b/e2e/react-start/virtual-routes/src/routes/root.tsx new file mode 100644 index 0000000000..9f0018dcaa --- /dev/null +++ b/e2e/react-start/virtual-routes/src/routes/root.tsx @@ -0,0 +1,96 @@ +import * as React from 'react' +import { + HeadContent, + Link, + Outlet, + Scripts, + createRootRoute, +} from '@tanstack/react-router' +import { TanStackRouterDevtools } from '@tanstack/react-router-devtools' +import appCss from '~/styles/app.css?url' + +export const Route = createRootRoute({ + component: RootComponent, + notFoundComponent: () => { + return ( +
+

This is the notFoundComponent configured on root route

+ Start Over +
+ ) + }, + head: () => { + return { + links: [{ rel: 'stylesheet', href: appCss }], + } + }, +}) + +function RootComponent() { + return ( + + + + ) +} + +function RootDocument({ children }: { children: React.ReactNode }) { + return ( + + + + + +
+ + Home + {' '} + + Posts + {' '} + + Layout + {' '} + + Subtree + {' '} + + This Route Does Not Exist + +
+
+ {children} + {/* Start rendering router matches */} + + + + + ) +} diff --git a/e2e/react-start/virtual-routes/src/styles/app.css b/e2e/react-start/virtual-routes/src/styles/app.css new file mode 100644 index 0000000000..c53c870665 --- /dev/null +++ b/e2e/react-start/virtual-routes/src/styles/app.css @@ -0,0 +1,22 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + html { + color-scheme: light dark; + } + + * { + @apply border-gray-200 dark:border-gray-800; + } + + html, + body { + @apply text-gray-900 bg-gray-50 dark:bg-gray-950 dark:text-gray-200; + } + + .using-mouse * { + outline: none !important; + } +} diff --git a/e2e/react-start/virtual-routes/src/tanstack-start.d.ts b/e2e/react-start/virtual-routes/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/e2e/react-start/virtual-routes/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/react-start/virtual-routes/src/utils/posts.tsx b/e2e/react-start/virtual-routes/src/utils/posts.tsx new file mode 100644 index 0000000000..9fdff27673 --- /dev/null +++ b/e2e/react-start/virtual-routes/src/utils/posts.tsx @@ -0,0 +1,36 @@ +import { notFound } from '@tanstack/react-router' +import { createServerFn } from '@tanstack/react-start' +import axios from 'redaxios' + +export type PostType = { + id: string + title: string + body: string +} + +export const fetchPost = createServerFn({ method: 'GET' }) + .validator((postId: string) => postId) + .handler(async ({ data: postId }) => { + console.info(`Fetching post with id ${postId}...`) + const post = await axios + .get(`https://jsonplaceholder.typicode.com/posts/${postId}`) + .then((r) => r.data) + .catch((err) => { + console.error(err) + if (err.status === 404) { + throw notFound() + } + throw err + }) + + return post + }) + +export const fetchPosts = createServerFn({ method: 'GET' }).handler( + async () => { + console.info('Fetching posts...') + return axios + .get>('https://jsonplaceholder.typicode.com/posts') + .then((r) => r.data.slice(0, 10)) + }, +) diff --git a/e2e/react-start/virtual-routes/src/utils/seo.ts b/e2e/react-start/virtual-routes/src/utils/seo.ts new file mode 100644 index 0000000000..d18ad84b74 --- /dev/null +++ b/e2e/react-start/virtual-routes/src/utils/seo.ts @@ -0,0 +1,33 @@ +export const seo = ({ + title, + description, + keywords, + image, +}: { + title: string + description?: string + image?: string + keywords?: string +}) => { + const tags = [ + { title }, + { name: 'description', content: description }, + { name: 'keywords', content: keywords }, + { name: 'twitter:title', content: title }, + { name: 'twitter:description', content: description }, + { name: 'twitter:creator', content: '@tannerlinsley' }, + { name: 'twitter:site', content: '@tannerlinsley' }, + { name: 'og:type', content: 'website' }, + { name: 'og:title', content: title }, + { name: 'og:description', content: description }, + ...(image + ? [ + { name: 'twitter:image', content: image }, + { name: 'twitter:card', content: 'summary_large_image' }, + { name: 'og:image', content: image }, + ] + : []), + ] + + return tags +} diff --git a/e2e/react-start/virtual-routes/src/utils/users.tsx b/e2e/react-start/virtual-routes/src/utils/users.tsx new file mode 100644 index 0000000000..46be4b1580 --- /dev/null +++ b/e2e/react-start/virtual-routes/src/utils/users.tsx @@ -0,0 +1,9 @@ +export type User = { + id: number + name: string + email: string +} + +const PORT = process.env.VITE_SERVER_PORT || 3000 + +export const DEPLOY_URL = `http://localhost:${PORT}` diff --git a/e2e/react-start/virtual-routes/tailwind.config.mjs b/e2e/react-start/virtual-routes/tailwind.config.mjs new file mode 100644 index 0000000000..e49f4eb776 --- /dev/null +++ b/e2e/react-start/virtual-routes/tailwind.config.mjs @@ -0,0 +1,4 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./src/**/*.{js,jsx,ts,tsx}'], +} diff --git a/e2e/react-start/virtual-routes/tests/app.spec.ts b/e2e/react-start/virtual-routes/tests/app.spec.ts new file mode 100644 index 0000000000..3182febfa0 --- /dev/null +++ b/e2e/react-start/virtual-routes/tests/app.spec.ts @@ -0,0 +1,33 @@ +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.getByRole('link', { name: 'Layout', exact: true }).click() + + await expect(page.locator('body')).toContainText("I'm a layout") + await expect(page.locator('body')).toContainText("I'm a nested layout") + + await page.getByRole('link', { name: 'Layout A' }).click() + await expect(page.locator('body')).toContainText("I'm layout A!") + + await page.getByRole('link', { name: 'Layout B' }).click() + await expect(page.locator('body')).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/e2e/react-start/virtual-routes/tsconfig.json b/e2e/react-start/virtual-routes/tsconfig.json new file mode 100644 index 0000000000..b3a2d67dfa --- /dev/null +++ b/e2e/react-start/virtual-routes/tsconfig.json @@ -0,0 +1,22 @@ +{ + "include": ["**/*.ts", "**/*.tsx", "public/script*.js"], + "compilerOptions": { + "strict": true, + "esModuleInterop": true, + "jsx": "react-jsx", + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "isolatedModules": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "target": "ES2022", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "paths": { + "~/*": ["./src/*"] + }, + "noEmit": true + } +} diff --git a/e2e/react-start/virtual-routes/vite.config.ts b/e2e/react-start/virtual-routes/vite.config.ts new file mode 100644 index 0000000000..21ff4c2940 --- /dev/null +++ b/e2e/react-start/virtual-routes/vite.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/react-start/plugin/vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart({ + tsr: { + virtualRouteConfig: './routes.ts', + }, + }), + ], +}) diff --git a/e2e/react-start/website/.gitignore b/e2e/react-start/website/.gitignore index be342025da..a5f619189c 100644 --- a/e2e/react-start/website/.gitignore +++ b/e2e/react-start/website/.gitignore @@ -7,16 +7,14 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ /blob-report/ /playwright/.cache/ + +.tanstack-start/build \ No newline at end of file diff --git a/e2e/react-start/website/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/react-start/website/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..ac36454b7c --- /dev/null +++ b/e2e/react-start/website/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,112 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +import { ServerRoute as ProjectVersionDocsFrameworkFrameworkChar123Char125DotmdRouteImport } from './../../src/routes/$project.$version.docs.framework.$framework.{$}[.]md' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +const ProjectVersionDocsFrameworkFrameworkChar123Char125DotmdRoute = + ProjectVersionDocsFrameworkFrameworkChar123Char125DotmdRouteImport.update({ + id: '/$project/$version/docs/framework/$framework/{$}.md', + path: '/$project/$version/docs/framework/$framework/{$}.md', + getParentRoute: () => rootRoute, + } as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath { + '/$project/$version/docs/framework/$framework/{$}.md': { + id: '/$project/$version/docs/framework/$framework/{$}.md' + path: '/$project/$version/docs/framework/$framework/{$}.md' + fullPath: '/$project/$version/docs/framework/$framework/{$}.md' + preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkChar123Char125DotmdRouteImport + parentRoute: typeof rootRoute + } + } +} + +// Add type-safety to the createFileRoute function across the route tree + +declare module './../../src/routes/$project.$version.docs.framework.$framework.{$}[.]md' { + const createServerFileRoute: CreateServerFileRoute< + FileRoutesByPath['/$project/$version/docs/framework/$framework/{$}.md']['parentRoute'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/{$}.md']['id'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/{$}.md']['path'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/{$}.md']['fullPath'], + unknown + > +} + +// Create and export the route tree + +export interface FileRoutesByFullPath { + '/$project/$version/docs/framework/$framework/{$}.md': typeof ProjectVersionDocsFrameworkFrameworkChar123Char125DotmdRoute +} + +export interface FileRoutesByTo { + '/$project/$version/docs/framework/$framework/{$}.md': typeof ProjectVersionDocsFrameworkFrameworkChar123Char125DotmdRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/$project/$version/docs/framework/$framework/{$}.md': typeof ProjectVersionDocsFrameworkFrameworkChar123Char125DotmdRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/$project/$version/docs/framework/$framework/{$}.md' + fileRoutesByTo: FileRoutesByTo + to: '/$project/$version/docs/framework/$framework/{$}.md' + id: '__root__' | '/$project/$version/docs/framework/$framework/{$}.md' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + ProjectVersionDocsFrameworkFrameworkChar123Char125DotmdRoute: typeof ProjectVersionDocsFrameworkFrameworkChar123Char125DotmdRoute +} + +const rootRouteChildren: RootRouteChildren = { + ProjectVersionDocsFrameworkFrameworkChar123Char125DotmdRoute: + ProjectVersionDocsFrameworkFrameworkChar123Char125DotmdRoute, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/$project/$version/docs/framework/$framework/{$}.md" + ] + }, + "/$project/$version/docs/framework/$framework/{$}.md": { + "filePath": "$project.$version.docs.framework.$framework.{$}[.]md.tsx" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/react-start/website/app.config.ts b/e2e/react-start/website/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/e2e/react-start/website/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/e2e/react-start/website/package.json b/e2e/react-start/website/package.json index e69c2b3ffa..f86fe1693d 100644 --- a/e2e/react-start/website/package.json +++ b/e2e/react-start/website/package.json @@ -1,13 +1,13 @@ { - "name": "tanstack-start-e2e-website", + "name": "tanstack-react-start-e2e-website", "private": true, "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "node .output/server/index.mjs", "test:e2e": "playwright test --project=chromium" }, "dependencies": { @@ -18,7 +18,6 @@ "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { @@ -28,10 +27,11 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "postcss": "^8.5.1", "autoprefixer": "^10.4.20", + "postcss": "^8.5.1", "tailwindcss": "^3.4.17", "typescript": "^5.7.2", + "vite": "^6.3.5", "vite-tsconfig-paths": "^5.1.4" } } diff --git a/e2e/react-start/website/playwright.config.ts b/e2e/react-start/website/playwright.config.ts index bb77d0cf70..9806e0c136 100644 --- a/e2e/react-start/website/playwright.config.ts +++ b/e2e/react-start/website/playwright.config.ts @@ -19,7 +19,7 @@ export default defineConfig({ }, webServer: { - command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm start --port ${PORT}`, + command: `VITE_SERVER_PORT=${PORT} pnpm build && PORT=${PORT} VITE_SERVER_PORT=${PORT} pnpm start`, url: baseURL, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/e2e/react-start/website/src/client.tsx b/e2e/react-start/website/src/client.tsx deleted file mode 100644 index 31385f57f1..0000000000 --- a/e2e/react-start/website/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document!, ) diff --git a/e2e/react-start/website/src/routeTree.gen.ts b/e2e/react-start/website/src/routeTree.gen.ts index 72b5ecded6..3f36d7f172 100644 --- a/e2e/react-start/website/src/routeTree.gen.ts +++ b/e2e/react-start/website/src/routeTree.gen.ts @@ -8,82 +8,83 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as LibraryImport } from './routes/_library' -import { Route as LibraryIndexImport } from './routes/_library.index' -import { Route as ProjectIndexImport } from './routes/$project.index' -import { Route as LibraryProjectImport } from './routes/_library.$project' -import { Route as LibraryProjectVersionIndexImport } from './routes/_library.$project.$version.index' -import { Route as ProjectVersionDocsIndexImport } from './routes/$project.$version.docs.index' -import { Route as ProjectVersionDocsFrameworkFrameworkImport } from './routes/$project.$version.docs.framework.$framework' -import { Route as ProjectVersionDocsFrameworkFrameworkIndexImport } from './routes/$project.$version.docs.framework.$framework.index' -import { Route as ProjectVersionDocsFrameworkFrameworkSplatImport } from './routes/$project.$version.docs.framework.$framework.$' -import { Route as ProjectVersionDocsFrameworkFrameworkExamplesSplatImport } from './routes/$project.$version.docs.framework.$framework.examples.$' +import { Route as LibraryRouteImport } from './routes/_library' +import { Route as LibraryIndexRouteImport } from './routes/_library.index' +import { Route as ProjectIndexRouteImport } from './routes/$project.index' +import { Route as LibraryProjectRouteImport } from './routes/_library.$project' +import { Route as LibraryProjectVersionIndexRouteImport } from './routes/_library.$project.$version.index' +import { Route as ProjectVersionDocsIndexRouteImport } from './routes/$project.$version.docs.index' +import { Route as ProjectVersionDocsFrameworkFrameworkRouteImport } from './routes/$project.$version.docs.framework.$framework' +import { Route as ProjectVersionDocsFrameworkFrameworkIndexRouteImport } from './routes/$project.$version.docs.framework.$framework.index' +import { Route as ProjectVersionDocsFrameworkFrameworkSplatRouteImport } from './routes/$project.$version.docs.framework.$framework.$' +import { Route as ProjectVersionDocsFrameworkFrameworkExamplesSplatRouteImport } from './routes/$project.$version.docs.framework.$framework.examples.$' // Create/Update Routes -const LibraryRoute = LibraryImport.update({ +const LibraryRoute = LibraryRouteImport.update({ id: '/_library', getParentRoute: () => rootRoute, } as any) -const LibraryIndexRoute = LibraryIndexImport.update({ +const LibraryIndexRoute = LibraryIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => LibraryRoute, } as any) -const ProjectIndexRoute = ProjectIndexImport.update({ +const ProjectIndexRoute = ProjectIndexRouteImport.update({ id: '/$project/', path: '/$project/', getParentRoute: () => rootRoute, } as any) -const LibraryProjectRoute = LibraryProjectImport.update({ +const LibraryProjectRoute = LibraryProjectRouteImport.update({ id: '/$project', path: '/$project', getParentRoute: () => LibraryRoute, } as any) -const LibraryProjectVersionIndexRoute = LibraryProjectVersionIndexImport.update( - { +const LibraryProjectVersionIndexRoute = + LibraryProjectVersionIndexRouteImport.update({ id: '/$version/', path: '/$version/', getParentRoute: () => LibraryProjectRoute, - } as any, -) + } as any) -const ProjectVersionDocsIndexRoute = ProjectVersionDocsIndexImport.update({ +const ProjectVersionDocsIndexRoute = ProjectVersionDocsIndexRouteImport.update({ id: '/$project/$version/docs/', path: '/$project/$version/docs/', getParentRoute: () => rootRoute, } as any) const ProjectVersionDocsFrameworkFrameworkRoute = - ProjectVersionDocsFrameworkFrameworkImport.update({ + ProjectVersionDocsFrameworkFrameworkRouteImport.update({ id: '/$project/$version/docs/framework/$framework', path: '/$project/$version/docs/framework/$framework', getParentRoute: () => rootRoute, } as any) const ProjectVersionDocsFrameworkFrameworkIndexRoute = - ProjectVersionDocsFrameworkFrameworkIndexImport.update({ + ProjectVersionDocsFrameworkFrameworkIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => ProjectVersionDocsFrameworkFrameworkRoute, } as any) const ProjectVersionDocsFrameworkFrameworkSplatRoute = - ProjectVersionDocsFrameworkFrameworkSplatImport.update({ + ProjectVersionDocsFrameworkFrameworkSplatRouteImport.update({ id: '/$', path: '/$', getParentRoute: () => ProjectVersionDocsFrameworkFrameworkRoute, } as any) const ProjectVersionDocsFrameworkFrameworkExamplesSplatRoute = - ProjectVersionDocsFrameworkFrameworkExamplesSplatImport.update({ + ProjectVersionDocsFrameworkFrameworkExamplesSplatRouteImport.update({ id: '/examples/$', path: '/examples/$', getParentRoute: () => ProjectVersionDocsFrameworkFrameworkRoute, @@ -97,75 +98,168 @@ declare module '@tanstack/react-router' { id: '/_library' path: '' fullPath: '' - preLoaderRoute: typeof LibraryImport + preLoaderRoute: typeof LibraryRouteImport parentRoute: typeof rootRoute } '/_library/$project': { id: '/_library/$project' path: '/$project' fullPath: '/$project' - preLoaderRoute: typeof LibraryProjectImport - parentRoute: typeof LibraryImport + preLoaderRoute: typeof LibraryProjectRouteImport + parentRoute: typeof LibraryRouteImport } '/$project/': { id: '/$project/' path: '/$project' fullPath: '/$project' - preLoaderRoute: typeof ProjectIndexImport + preLoaderRoute: typeof ProjectIndexRouteImport parentRoute: typeof rootRoute } '/_library/': { id: '/_library/' path: '/' fullPath: '/' - preLoaderRoute: typeof LibraryIndexImport - parentRoute: typeof LibraryImport + preLoaderRoute: typeof LibraryIndexRouteImport + parentRoute: typeof LibraryRouteImport } '/$project/$version/docs/': { id: '/$project/$version/docs/' path: '/$project/$version/docs' fullPath: '/$project/$version/docs' - preLoaderRoute: typeof ProjectVersionDocsIndexImport + preLoaderRoute: typeof ProjectVersionDocsIndexRouteImport parentRoute: typeof rootRoute } '/_library/$project/$version/': { id: '/_library/$project/$version/' path: '/$version' fullPath: '/$project/$version' - preLoaderRoute: typeof LibraryProjectVersionIndexImport - parentRoute: typeof LibraryProjectImport + preLoaderRoute: typeof LibraryProjectVersionIndexRouteImport + parentRoute: typeof LibraryProjectRouteImport } '/$project/$version/docs/framework/$framework': { id: '/$project/$version/docs/framework/$framework' path: '/$project/$version/docs/framework/$framework' fullPath: '/$project/$version/docs/framework/$framework' - preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkImport + preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkRouteImport parentRoute: typeof rootRoute } '/$project/$version/docs/framework/$framework/$': { id: '/$project/$version/docs/framework/$framework/$' path: '/$' fullPath: '/$project/$version/docs/framework/$framework/$' - preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkSplatImport - parentRoute: typeof ProjectVersionDocsFrameworkFrameworkImport + preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkSplatRouteImport + parentRoute: typeof ProjectVersionDocsFrameworkFrameworkRouteImport } '/$project/$version/docs/framework/$framework/': { id: '/$project/$version/docs/framework/$framework/' path: '/' fullPath: '/$project/$version/docs/framework/$framework/' - preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkIndexImport - parentRoute: typeof ProjectVersionDocsFrameworkFrameworkImport + preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkIndexRouteImport + parentRoute: typeof ProjectVersionDocsFrameworkFrameworkRouteImport } '/$project/$version/docs/framework/$framework/examples/$': { id: '/$project/$version/docs/framework/$framework/examples/$' path: '/examples/$' fullPath: '/$project/$version/docs/framework/$framework/examples/$' - preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkExamplesSplatImport - parentRoute: typeof ProjectVersionDocsFrameworkFrameworkImport + preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkExamplesSplatRouteImport + parentRoute: typeof ProjectVersionDocsFrameworkFrameworkRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/_library' { + const createFileRoute: CreateFileRoute< + '/_library', + FileRoutesByPath['/_library']['parentRoute'], + FileRoutesByPath['/_library']['id'], + FileRoutesByPath['/_library']['path'], + FileRoutesByPath['/_library']['fullPath'] + > +} +declare module './routes/_library.$project' { + const createFileRoute: CreateFileRoute< + '/_library/$project', + FileRoutesByPath['/_library/$project']['parentRoute'], + FileRoutesByPath['/_library/$project']['id'], + FileRoutesByPath['/_library/$project']['path'], + FileRoutesByPath['/_library/$project']['fullPath'] + > +} +declare module './routes/$project.index' { + const createFileRoute: CreateFileRoute< + '/$project/', + FileRoutesByPath['/$project/']['parentRoute'], + FileRoutesByPath['/$project/']['id'], + FileRoutesByPath['/$project/']['path'], + FileRoutesByPath['/$project/']['fullPath'] + > +} +declare module './routes/_library.index' { + const createFileRoute: CreateFileRoute< + '/_library/', + FileRoutesByPath['/_library/']['parentRoute'], + FileRoutesByPath['/_library/']['id'], + FileRoutesByPath['/_library/']['path'], + FileRoutesByPath['/_library/']['fullPath'] + > +} +declare module './routes/$project.$version.docs.index' { + const createFileRoute: CreateFileRoute< + '/$project/$version/docs/', + FileRoutesByPath['/$project/$version/docs/']['parentRoute'], + FileRoutesByPath['/$project/$version/docs/']['id'], + FileRoutesByPath['/$project/$version/docs/']['path'], + FileRoutesByPath['/$project/$version/docs/']['fullPath'] + > +} +declare module './routes/_library.$project.$version.index' { + const createFileRoute: CreateFileRoute< + '/_library/$project/$version/', + FileRoutesByPath['/_library/$project/$version/']['parentRoute'], + FileRoutesByPath['/_library/$project/$version/']['id'], + FileRoutesByPath['/_library/$project/$version/']['path'], + FileRoutesByPath['/_library/$project/$version/']['fullPath'] + > +} +declare module './routes/$project.$version.docs.framework.$framework' { + const createFileRoute: CreateFileRoute< + '/$project/$version/docs/framework/$framework', + FileRoutesByPath['/$project/$version/docs/framework/$framework']['parentRoute'], + FileRoutesByPath['/$project/$version/docs/framework/$framework']['id'], + FileRoutesByPath['/$project/$version/docs/framework/$framework']['path'], + FileRoutesByPath['/$project/$version/docs/framework/$framework']['fullPath'] + > +} +declare module './routes/$project.$version.docs.framework.$framework.$' { + const createFileRoute: CreateFileRoute< + '/$project/$version/docs/framework/$framework/$', + FileRoutesByPath['/$project/$version/docs/framework/$framework/$']['parentRoute'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/$']['id'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/$']['path'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/$']['fullPath'] + > +} +declare module './routes/$project.$version.docs.framework.$framework.index' { + const createFileRoute: CreateFileRoute< + '/$project/$version/docs/framework/$framework/', + FileRoutesByPath['/$project/$version/docs/framework/$framework/']['parentRoute'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/']['id'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/']['path'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/']['fullPath'] + > +} +declare module './routes/$project.$version.docs.framework.$framework.examples.$' { + const createFileRoute: CreateFileRoute< + '/$project/$version/docs/framework/$framework/examples/$', + FileRoutesByPath['/$project/$version/docs/framework/$framework/examples/$']['parentRoute'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/examples/$']['id'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/examples/$']['path'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/examples/$']['fullPath'] + > +} + // Create and export the route tree interface LibraryProjectRouteChildren { diff --git a/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.$.tsx b/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.$.tsx index 055f77622b..0c70abc68d 100644 --- a/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.$.tsx +++ b/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.$.tsx @@ -1,12 +1,10 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent, useLocation } from '@tanstack/react-router' import type { ErrorComponentProps } from '@tanstack/react-router' import { NotFound } from '~/components/NotFound' import { getDocument } from '~/server/document' import { capitalize, seo } from '~/utils/seo' -export const Route = createFileRoute( - '/$project/$version/docs/framework/$framework/$', -)({ +export const Route = createFileRoute({ loader: ({ params: { _splat } }) => getDocument({ data: _splat!, @@ -28,6 +26,7 @@ function PostErrorComponent({ error }: ErrorComponentProps) { } function Page() { + const pathname = useLocation({ select: (s) => s.pathname }) const post = Route.useLoaderData() return ( @@ -39,6 +38,11 @@ function Page() { {post.title}

{post.content}
+

+ + View Raw Content + +

) } diff --git a/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.examples.$.tsx b/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.examples.$.tsx index 5d5cbe324d..9e56e61762 100644 --- a/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.examples.$.tsx +++ b/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.examples.$.tsx @@ -1,10 +1,7 @@ -import { createFileRoute } from '@tanstack/react-router' import { NotFound } from '~/components/NotFound' import { capitalize, seo } from '~/utils/seo' -export const Route = createFileRoute( - '/$project/$version/docs/framework/$framework/examples/$', -)({ +export const Route = createFileRoute({ head: ({ params }) => ({ meta: seo({ title: `${capitalize(params._splat || '')} Example | TanStack ${capitalize(params.project)} ${capitalize(params.framework)}`, diff --git a/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.index.tsx b/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.index.tsx index 64a30c1ee1..b791228e26 100644 --- a/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.index.tsx +++ b/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.index.tsx @@ -1,9 +1,7 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' -export const Route = createFileRoute( - '/$project/$version/docs/framework/$framework/', -)({ - loader: () => { +export const Route = createFileRoute({ + beforeLoad: () => { throw redirect({ from: '/$project/$version/docs/framework/$framework/', to: '/$project/$version/docs/framework/$framework/$', diff --git a/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.tsx b/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.tsx index 5d1be9df39..f2b4a24d77 100644 --- a/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.tsx +++ b/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.tsx @@ -1,15 +1,8 @@ -import { - Link, - Outlet, - createFileRoute, - useLocation, -} from '@tanstack/react-router' +import { Link, Outlet, useLocation } from '@tanstack/react-router' import { getDocumentHeads } from '~/server/document' import { getProject } from '~/server/projects' -export const Route = createFileRoute( - '/$project/$version/docs/framework/$framework', -)({ +export const Route = createFileRoute({ loader: async ({ params: { project } }) => { const library = await getProject({ data: project }) const documents = await getDocumentHeads() diff --git a/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.{$}[.]md.tsx b/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.{$}[.]md.tsx new file mode 100644 index 0000000000..4644e2d0cf --- /dev/null +++ b/e2e/react-start/website/src/routes/$project.$version.docs.framework.$framework.{$}[.]md.tsx @@ -0,0 +1,22 @@ +import { getDocument } from '~/server/document' + +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ params }) => { + const splat = params['_splat'] || '' + const docPath = splat.split('.md')[0] + + if (!docPath) { + return new Response('Document not found', { status: 404 }) + } + + const doc = await getDocument({ data: docPath }) + const markdown = `# ${doc.title}\n\n${doc.content}` + + return new Response(markdown, { + headers: { + 'Content-Type': 'text/markdown', + 'Content-Disposition': `inline; filename="${doc.title}.md"`, + }, + }) + }, +}) diff --git a/e2e/react-start/website/src/routes/$project.$version.docs.index.tsx b/e2e/react-start/website/src/routes/$project.$version.docs.index.tsx index e379d81908..f15e022443 100644 --- a/e2e/react-start/website/src/routes/$project.$version.docs.index.tsx +++ b/e2e/react-start/website/src/routes/$project.$version.docs.index.tsx @@ -1,7 +1,7 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' -export const Route = createFileRoute('/$project/$version/docs/')({ - loader: () => { +export const Route = createFileRoute({ + beforeLoad: () => { throw redirect({ from: '/$project/$version/docs', to: '/$project/$version/docs/framework/$framework/$', diff --git a/e2e/react-start/website/src/routes/$project.index.tsx b/e2e/react-start/website/src/routes/$project.index.tsx index 9c6b935e83..6f5d49cef0 100644 --- a/e2e/react-start/website/src/routes/$project.index.tsx +++ b/e2e/react-start/website/src/routes/$project.index.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' -export const Route = createFileRoute('/$project/')({ +export const Route = createFileRoute({ loader: ({ params }) => { throw redirect({ to: '/$project/$version', diff --git a/e2e/react-start/website/src/routes/__root.tsx b/e2e/react-start/website/src/routes/__root.tsx index 1b98cc37f9..a9a0d5e47f 100644 --- a/e2e/react-start/website/src/routes/__root.tsx +++ b/e2e/react-start/website/src/routes/__root.tsx @@ -1,8 +1,8 @@ import { - Outlet, - createRootRoute, HeadContent, + Outlet, Scripts, + createRootRoute, } from '@tanstack/react-router' import { TanStackRouterDevtools } from '@tanstack/react-router-devtools' import * as React from 'react' diff --git a/e2e/react-start/website/src/routes/_library.$project.$version.index.tsx b/e2e/react-start/website/src/routes/_library.$project.$version.index.tsx index d91b72d2b7..25023822d5 100644 --- a/e2e/react-start/website/src/routes/_library.$project.$version.index.tsx +++ b/e2e/react-start/website/src/routes/_library.$project.$version.index.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' -export const Route = createFileRoute('/_library/$project/$version/')({ +export const Route = createFileRoute({ component: Page, }) @@ -14,7 +14,11 @@ function Page() {

version: {params.version}

- + Get started with our documentation.

diff --git a/e2e/react-start/website/src/routes/_library.$project.tsx b/e2e/react-start/website/src/routes/_library.$project.tsx index 3384fcf3a0..8fb100b563 100644 --- a/e2e/react-start/website/src/routes/_library.$project.tsx +++ b/e2e/react-start/website/src/routes/_library.$project.tsx @@ -1,8 +1,8 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' import { getProject } from '~/server/projects' import { seo } from '~/utils/seo' -export const Route = createFileRoute('/_library/$project')({ +export const Route = createFileRoute({ loader: ({ params: { project } }) => getProject({ data: project }), head: ({ loaderData }) => ({ meta: seo({ title: `TanStack ${loaderData?.name || 'Project'}` }), diff --git a/e2e/react-start/website/src/routes/_library.index.tsx b/e2e/react-start/website/src/routes/_library.index.tsx index f08b6c633a..20e6a7468f 100644 --- a/e2e/react-start/website/src/routes/_library.index.tsx +++ b/e2e/react-start/website/src/routes/_library.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_library/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/react-start/website/src/routes/_library.tsx b/e2e/react-start/website/src/routes/_library.tsx index e120515350..c3970050ca 100644 --- a/e2e/react-start/website/src/routes/_library.tsx +++ b/e2e/react-start/website/src/routes/_library.tsx @@ -1,12 +1,7 @@ -import { - Link, - Outlet, - createFileRoute, - useLocation, -} from '@tanstack/react-router' +import { Link, Outlet, useLocation } from '@tanstack/react-router' import { getProjects } from '~/server/projects' -export const Route = createFileRoute('/_library')({ +export const Route = createFileRoute({ loader: async () => { const projects = await getProjects() return { diff --git a/e2e/react-start/website/src/ssr.tsx b/e2e/react-start/website/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/e2e/react-start/website/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/e2e/react-start/website/src/tanstack-start.d.ts b/e2e/react-start/website/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/e2e/react-start/website/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/react-start/website/tests/app.spec.ts b/e2e/react-start/website/tests/app.spec.ts index f115180956..179fa81bf8 100644 --- a/e2e/react-start/website/tests/app.spec.ts +++ b/e2e/react-start/website/tests/app.spec.ts @@ -17,3 +17,17 @@ test('resolves to the overview docs page', async ({ page }) => { '/router/latest/docs/framework/react/overview', ) }) + +test('clicking on Documentation link navigates to the overview docs page', async ({ + page, +}) => { + await page.goto('/router') + await page.waitForLoadState('networkidle') + + const documentationLink = page.getByLabel('Documentation') + await documentationLink.click() + await page.waitForLoadState('networkidle') + + const pathname = new URL(page.url()).pathname + expect(pathname).toBe('/router/latest/docs/framework/react/overview') +}) diff --git a/e2e/react-start/website/vite.config.ts b/e2e/react-start/website/vite.config.ts new file mode 100644 index 0000000000..a1b3d840f5 --- /dev/null +++ b/e2e/react-start/website/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/react-start/plugin/vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/e2e/solid-router/basic-esbuild-file-based/src/esbuild.config.js b/e2e/solid-router/basic-esbuild-file-based/src/esbuild.config.js index a361b1d4f1..2d6ea80c1b 100644 --- a/e2e/solid-router/basic-esbuild-file-based/src/esbuild.config.js +++ b/e2e/solid-router/basic-esbuild-file-based/src/esbuild.config.js @@ -1,10 +1,10 @@ -import { TanStackRouterEsbuild } from '@tanstack/router-plugin/esbuild' +import { tanstackRouter } from '@tanstack/router-plugin/esbuild' import { solidPlugin } from 'esbuild-plugin-solid' export default { // ... plugins: [ - TanStackRouterEsbuild({ + tanstackRouter({ target: 'solid', autoCodeSplitting: true, }), diff --git a/e2e/solid-router/basic-file-based-code-splitting/package.json b/e2e/solid-router/basic-file-based-code-splitting/package.json index ba4a9e2940..9f65ec5d04 100644 --- a/e2e/solid-router/basic-file-based-code-splitting/package.json +++ b/e2e/solid-router/basic-file-based-code-splitting/package.json @@ -23,7 +23,7 @@ "devDependencies": { "@playwright/test": "^1.50.1", "@tanstack/router-e2e-utils": "workspace:^", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-solid": "^2.11.2" } } diff --git a/e2e/solid-router/basic-file-based-code-splitting/src/routeTree.gen.ts b/e2e/solid-router/basic-file-based-code-splitting/src/routeTree.gen.ts index b7e80e980b..7032a890eb 100644 --- a/e2e/solid-router/basic-file-based-code-splitting/src/routeTree.gen.ts +++ b/e2e/solid-router/basic-file-based-code-splitting/src/routeTree.gen.ts @@ -8,75 +8,77 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/solid-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as WithoutLoaderImport } from './routes/without-loader' -import { Route as ViewportTestImport } from './routes/viewport-test' -import { Route as PostsImport } from './routes/posts' -import { Route as LayoutImport } from './routes/_layout' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as LayoutLayout2Import } from './routes/_layout/_layout-2' -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 WithoutLoaderRouteImport } from './routes/without-loader' +import { Route as ViewportTestRouteImport } from './routes/viewport-test' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as LayoutRouteImport } from './routes/_layout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2' +import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b' +import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' // Create/Update Routes -const WithoutLoaderRoute = WithoutLoaderImport.update({ +const WithoutLoaderRoute = WithoutLoaderRouteImport.update({ id: '/without-loader', path: '/without-loader', getParentRoute: () => rootRoute, } as any) -const ViewportTestRoute = ViewportTestImport.update({ +const ViewportTestRoute = ViewportTestRouteImport.update({ id: '/viewport-test', path: '/viewport-test', getParentRoute: () => rootRoute, } as any) -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const LayoutRoute = LayoutImport.update({ +const LayoutRoute = LayoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const LayoutLayout2Route = LayoutLayout2Import.update({ +const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) -const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBImport.update({ +const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => LayoutLayout2Route, } as any) -const LayoutLayout2LayoutARoute = LayoutLayout2LayoutAImport.update({ +const LayoutLayout2LayoutARoute = LayoutLayout2LayoutARouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => LayoutLayout2Route, @@ -90,75 +92,168 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/viewport-test': { id: '/viewport-test' path: '/viewport-test' fullPath: '/viewport-test' - preLoaderRoute: typeof ViewportTestImport + preLoaderRoute: typeof ViewportTestRouteImport parentRoute: typeof rootRoute } '/without-loader': { id: '/without-loader' path: '/without-loader' fullPath: '/without-loader' - preLoaderRoute: typeof WithoutLoaderImport + preLoaderRoute: typeof WithoutLoaderRouteImport parentRoute: typeof rootRoute } '/_layout/_layout-2': { id: '/_layout/_layout-2' path: '' fullPath: '' - preLoaderRoute: typeof LayoutLayout2Import - parentRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutLayout2RouteImport + parentRoute: typeof LayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/_layout/_layout-2/layout-a': { id: '/_layout/_layout-2/layout-a' path: '/layout-a' fullPath: '/layout-a' - preLoaderRoute: typeof LayoutLayout2LayoutAImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutARouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/_layout/_layout-2/layout-b': { id: '/_layout/_layout-2/layout-b' path: '/layout-b' fullPath: '/layout-b' - preLoaderRoute: typeof LayoutLayout2LayoutBImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutBRouteImport + parentRoute: typeof LayoutLayout2RouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_layout' { + const createFileRoute: CreateFileRoute< + '/_layout', + FileRoutesByPath['/_layout']['parentRoute'], + FileRoutesByPath['/_layout']['id'], + FileRoutesByPath['/_layout']['path'], + FileRoutesByPath['/_layout']['fullPath'] + > +} +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/viewport-test' { + const createFileRoute: CreateFileRoute< + '/viewport-test', + FileRoutesByPath['/viewport-test']['parentRoute'], + FileRoutesByPath['/viewport-test']['id'], + FileRoutesByPath['/viewport-test']['path'], + FileRoutesByPath['/viewport-test']['fullPath'] + > +} +declare module './routes/without-loader' { + const createFileRoute: CreateFileRoute< + '/without-loader', + FileRoutesByPath['/without-loader']['parentRoute'], + FileRoutesByPath['/without-loader']['id'], + FileRoutesByPath['/without-loader']['path'], + FileRoutesByPath['/without-loader']['fullPath'] + > +} +declare module './routes/_layout/_layout-2' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2', + FileRoutesByPath['/_layout/_layout-2']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2']['id'], + FileRoutesByPath['/_layout/_layout-2']['path'], + FileRoutesByPath['/_layout/_layout-2']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-a' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-a', + FileRoutesByPath['/_layout/_layout-2/layout-a']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-b' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-b', + FileRoutesByPath['/_layout/_layout-2/layout-b']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['fullPath'] + > +} + // Create and export the route tree interface LayoutLayout2RouteChildren { @@ -291,3 +386,66 @@ const rootRouteChildren: RootRouteChildren = { export const routeTree = rootRoute ._addFileChildren(rootRouteChildren) ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/", + "/_layout", + "/posts", + "/viewport-test", + "/without-loader" + ] + }, + "/": { + "filePath": "index.tsx" + }, + "/_layout": { + "filePath": "_layout.tsx", + "children": [ + "/_layout/_layout-2" + ] + }, + "/posts": { + "filePath": "posts.tsx", + "children": [ + "/posts/$postId", + "/posts/" + ] + }, + "/viewport-test": { + "filePath": "viewport-test.tsx" + }, + "/without-loader": { + "filePath": "without-loader.tsx" + }, + "/_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.$postId.tsx", + "parent": "/posts" + }, + "/posts/": { + "filePath": "posts.index.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" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout.tsx b/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout.tsx index d43b4ef5f5..c549175638 100644 --- a/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout.tsx +++ b/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/_layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2.tsx b/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2.tsx index 7a5a3623a0..efeca5ce86 100644 --- a/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2.tsx +++ b/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/_layout/_layout-2')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-a.tsx b/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-a.tsx index b69951b246..a190b24202 100644 --- a/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-a.tsx +++ b/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-a.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ +export const Route = createFileRoute({ component: LayoutAComponent, }) diff --git a/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-b.tsx b/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-b.tsx index 30dbcce90f..505f8f6fbf 100644 --- a/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-b.tsx +++ b/e2e/solid-router/basic-file-based-code-splitting/src/routes/_layout/_layout-2/layout-b.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ +export const Route = createFileRoute({ component: LayoutBComponent, }) diff --git a/e2e/solid-router/basic-file-based-code-splitting/src/routes/index.tsx b/e2e/solid-router/basic-file-based-code-splitting/src/routes/index.tsx index bdfb4c7676..510db79b73 100644 --- a/e2e/solid-router/basic-file-based-code-splitting/src/routes/index.tsx +++ b/e2e/solid-router/basic-file-based-code-splitting/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/solid-router/basic-file-based-code-splitting/src/routes/posts.$postId.tsx b/e2e/solid-router/basic-file-based-code-splitting/src/routes/posts.$postId.tsx index 105f08d64e..e23c29a21a 100644 --- a/e2e/solid-router/basic-file-based-code-splitting/src/routes/posts.$postId.tsx +++ b/e2e/solid-router/basic-file-based-code-splitting/src/routes/posts.$postId.tsx @@ -1,4 +1,4 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/solid-router' +import { ErrorComponent } from '@tanstack/solid-router' import { fetchPost } from '../posts' import type { ErrorComponentProps } from '@tanstack/solid-router' @@ -6,7 +6,7 @@ export function PostErrorComponent({ error }: ErrorComponentProps) { return } -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost(postId), errorComponent: PostErrorComponent as any, notFoundComponent: () => { diff --git a/e2e/solid-router/basic-file-based-code-splitting/src/routes/posts.index.tsx b/e2e/solid-router/basic-file-based-code-splitting/src/routes/posts.index.tsx index 33d0386c19..13529228bb 100644 --- a/e2e/solid-router/basic-file-based-code-splitting/src/routes/posts.index.tsx +++ b/e2e/solid-router/basic-file-based-code-splitting/src/routes/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/e2e/solid-router/basic-file-based-code-splitting/src/routes/posts.tsx b/e2e/solid-router/basic-file-based-code-splitting/src/routes/posts.tsx index 11a999f50a..2e28f9beb3 100644 --- a/e2e/solid-router/basic-file-based-code-splitting/src/routes/posts.tsx +++ b/e2e/solid-router/basic-file-based-code-splitting/src/routes/posts.tsx @@ -1,7 +1,7 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import { fetchPosts } from '../posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: fetchPosts, component: PostsComponent, }) diff --git a/e2e/solid-router/basic-file-based-code-splitting/src/routes/viewport-test.tsx b/e2e/solid-router/basic-file-based-code-splitting/src/routes/viewport-test.tsx index 22dd8fd282..b182feb7b1 100644 --- a/e2e/solid-router/basic-file-based-code-splitting/src/routes/viewport-test.tsx +++ b/e2e/solid-router/basic-file-based-code-splitting/src/routes/viewport-test.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/viewport-test')({ +export const Route = createFileRoute({ component: () =>
Hello /viewport-test!
, }) diff --git a/e2e/solid-router/basic-file-based-code-splitting/src/routes/without-loader.tsx b/e2e/solid-router/basic-file-based-code-splitting/src/routes/without-loader.tsx index 1506595204..af692bdaca 100644 --- a/e2e/solid-router/basic-file-based-code-splitting/src/routes/without-loader.tsx +++ b/e2e/solid-router/basic-file-based-code-splitting/src/routes/without-loader.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/without-loader')({ +export const Route = createFileRoute({ component: () =>
Hello /without-loader!
, }) diff --git a/e2e/solid-router/basic-file-based-code-splitting/vite.config.ts b/e2e/solid-router/basic-file-based-code-splitting/vite.config.ts index df642f3222..694cb2914f 100644 --- a/e2e/solid-router/basic-file-based-code-splitting/vite.config.ts +++ b/e2e/solid-router/basic-file-based-code-splitting/vite.config.ts @@ -1,13 +1,14 @@ import { defineConfig } from 'vite' import solid from 'vite-plugin-solid' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'solid', autoCodeSplitting: true, + verboseFileRoutes: false, codeSplittingOptions: { splitBehavior: ({ routeId }) => { if (routeId === '/posts') { diff --git a/e2e/solid-router/basic-file-based/package.json b/e2e/solid-router/basic-file-based/package.json index 9bfd059a6d..47fd6a1a73 100644 --- a/e2e/solid-router/basic-file-based/package.json +++ b/e2e/solid-router/basic-file-based/package.json @@ -27,6 +27,6 @@ "@tanstack/router-e2e-utils": "workspace:^", "vite-plugin-solid": "^2.11.2", "combinate": "^1.1.11", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/solid-router/basic-file-based/src/routeTree.gen.ts b/e2e/solid-router/basic-file-based/src/routeTree.gen.ts index e41dbee76d..8da46dd71d 100644 --- a/e2e/solid-router/basic-file-based/src/routeTree.gen.ts +++ b/e2e/solid-router/basic-file-based/src/routeTree.gen.ts @@ -13,110 +13,110 @@ import { createFileRoute } from '@tanstack/solid-router' // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PostsImport } from './routes/posts' -import { Route as EditingBImport } from './routes/editing-b' -import { Route as EditingAImport } from './routes/editing-a' -import { Route as AnchorImport } from './routes/anchor' -import { Route as LayoutImport } from './routes/_layout' -import { Route as IndexImport } from './routes/index' -import { Route as RedirectIndexImport } from './routes/redirect/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as RedirectTargetImport } from './routes/redirect/$target' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as LayoutLayout2Import } from './routes/_layout/_layout-2' -import { Route as groupLazyinsideImport } from './routes/(group)/lazyinside' -import { Route as groupInsideImport } from './routes/(group)/inside' -import { Route as groupLayoutImport } from './routes/(group)/_layout' -import { Route as anotherGroupOnlyrouteinsideImport } from './routes/(another-group)/onlyrouteinside' -import { Route as RedirectTargetIndexImport } from './routes/redirect/$target/index' -import { Route as RedirectPreloadThirdImport } from './routes/redirect/preload/third' -import { Route as RedirectPreloadSecondImport } from './routes/redirect/preload/second' -import { Route as RedirectPreloadFirstImport } from './routes/redirect/preload/first' -import { Route as RedirectTargetViaLoaderImport } from './routes/redirect/$target/via-loader' -import { Route as RedirectTargetViaBeforeLoadImport } from './routes/redirect/$target/via-beforeLoad' -import { Route as PostsPostIdEditImport } from './routes/posts_.$postId.edit' -import { Route as ParamsSingleValueImport } from './routes/params.single.$value' -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 groupSubfolderInsideImport } from './routes/(group)/subfolder/inside' -import { Route as groupLayoutInsidelayoutImport } from './routes/(group)/_layout.insidelayout' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as EditingBRouteImport } from './routes/editing-b' +import { Route as EditingARouteImport } from './routes/editing-a' +import { Route as AnchorRouteImport } from './routes/anchor' +import { Route as LayoutRouteImport } from './routes/_layout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as RedirectIndexRouteImport } from './routes/redirect/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as RedirectTargetRouteImport } from './routes/redirect/$target' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2' +import { Route as groupLazyinsideRouteImport } from './routes/(group)/lazyinside' +import { Route as groupInsideRouteImport } from './routes/(group)/inside' +import { Route as groupLayoutRouteImport } from './routes/(group)/_layout' +import { Route as anotherGroupOnlyrouteinsideRouteImport } from './routes/(another-group)/onlyrouteinside' +import { Route as RedirectTargetIndexRouteImport } from './routes/redirect/$target/index' +import { Route as RedirectPreloadThirdRouteImport } from './routes/redirect/preload/third' +import { Route as RedirectPreloadSecondRouteImport } from './routes/redirect/preload/second' +import { Route as RedirectPreloadFirstRouteImport } from './routes/redirect/preload/first' +import { Route as RedirectTargetViaLoaderRouteImport } from './routes/redirect/$target/via-loader' +import { Route as RedirectTargetViaBeforeLoadRouteImport } from './routes/redirect/$target/via-beforeLoad' +import { Route as PostsPostIdEditRouteImport } from './routes/posts_.$postId.edit' +import { Route as ParamsSingleValueRouteImport } from './routes/params.single.$value' +import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b' +import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' +import { Route as groupSubfolderInsideRouteImport } from './routes/(group)/subfolder/inside' +import { Route as groupLayoutInsidelayoutRouteImport } from './routes/(group)/_layout.insidelayout' // Create Virtual Routes -const groupImport = createFileRoute('/(group)')() +const groupRouteImport = createFileRoute('/(group)')() // Create/Update Routes -const groupRoute = groupImport.update({ +const groupRoute = groupRouteImport.update({ id: '/(group)', getParentRoute: () => rootRoute, } as any) -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const EditingBRoute = EditingBImport.update({ +const EditingBRoute = EditingBRouteImport.update({ id: '/editing-b', path: '/editing-b', getParentRoute: () => rootRoute, } as any) -const EditingARoute = EditingAImport.update({ +const EditingARoute = EditingARouteImport.update({ id: '/editing-a', path: '/editing-a', getParentRoute: () => rootRoute, } as any) -const AnchorRoute = AnchorImport.update({ +const AnchorRoute = AnchorRouteImport.update({ id: '/anchor', path: '/anchor', getParentRoute: () => rootRoute, } as any) -const LayoutRoute = LayoutImport.update({ +const LayoutRoute = LayoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const RedirectIndexRoute = RedirectIndexImport.update({ +const RedirectIndexRoute = RedirectIndexRouteImport.update({ id: '/redirect/', path: '/redirect/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const RedirectTargetRoute = RedirectTargetImport.update({ +const RedirectTargetRoute = RedirectTargetRouteImport.update({ id: '/redirect/$target', path: '/redirect/$target', getParentRoute: () => rootRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const LayoutLayout2Route = LayoutLayout2Import.update({ +const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) -const groupLazyinsideRoute = groupLazyinsideImport +const groupLazyinsideRoute = groupLazyinsideRouteImport .update({ id: '/lazyinside', path: '/lazyinside', @@ -124,92 +124,92 @@ const groupLazyinsideRoute = groupLazyinsideImport } as any) .lazy(() => import('./routes/(group)/lazyinside.lazy').then((d) => d.Route)) -const groupInsideRoute = groupInsideImport.update({ +const groupInsideRoute = groupInsideRouteImport.update({ id: '/inside', path: '/inside', getParentRoute: () => groupRoute, } as any) -const groupLayoutRoute = groupLayoutImport.update({ +const groupLayoutRoute = groupLayoutRouteImport.update({ id: '/_layout', getParentRoute: () => groupRoute, } as any) const anotherGroupOnlyrouteinsideRoute = - anotherGroupOnlyrouteinsideImport.update({ + anotherGroupOnlyrouteinsideRouteImport.update({ id: '/(another-group)/onlyrouteinside', path: '/onlyrouteinside', getParentRoute: () => rootRoute, } as any) -const RedirectTargetIndexRoute = RedirectTargetIndexImport.update({ +const RedirectTargetIndexRoute = RedirectTargetIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => RedirectTargetRoute, } as any) -const RedirectPreloadThirdRoute = RedirectPreloadThirdImport.update({ +const RedirectPreloadThirdRoute = RedirectPreloadThirdRouteImport.update({ id: '/redirect/preload/third', path: '/redirect/preload/third', getParentRoute: () => rootRoute, } as any) -const RedirectPreloadSecondRoute = RedirectPreloadSecondImport.update({ +const RedirectPreloadSecondRoute = RedirectPreloadSecondRouteImport.update({ id: '/redirect/preload/second', path: '/redirect/preload/second', getParentRoute: () => rootRoute, } as any) -const RedirectPreloadFirstRoute = RedirectPreloadFirstImport.update({ +const RedirectPreloadFirstRoute = RedirectPreloadFirstRouteImport.update({ id: '/redirect/preload/first', path: '/redirect/preload/first', getParentRoute: () => rootRoute, } as any) -const RedirectTargetViaLoaderRoute = RedirectTargetViaLoaderImport.update({ +const RedirectTargetViaLoaderRoute = RedirectTargetViaLoaderRouteImport.update({ id: '/via-loader', path: '/via-loader', getParentRoute: () => RedirectTargetRoute, } as any) const RedirectTargetViaBeforeLoadRoute = - RedirectTargetViaBeforeLoadImport.update({ + RedirectTargetViaBeforeLoadRouteImport.update({ id: '/via-beforeLoad', path: '/via-beforeLoad', getParentRoute: () => RedirectTargetRoute, } as any) -const PostsPostIdEditRoute = PostsPostIdEditImport.update({ +const PostsPostIdEditRoute = PostsPostIdEditRouteImport.update({ id: '/posts_/$postId/edit', path: '/posts/$postId/edit', getParentRoute: () => rootRoute, } as any) -const ParamsSingleValueRoute = ParamsSingleValueImport.update({ +const ParamsSingleValueRoute = ParamsSingleValueRouteImport.update({ id: '/params/single/$value', path: '/params/single/$value', getParentRoute: () => rootRoute, } as any) -const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBImport.update({ +const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => LayoutLayout2Route, } as any) -const LayoutLayout2LayoutARoute = LayoutLayout2LayoutAImport.update({ +const LayoutLayout2LayoutARoute = LayoutLayout2LayoutARouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => LayoutLayout2Route, } as any) -const groupSubfolderInsideRoute = groupSubfolderInsideImport.update({ +const groupSubfolderInsideRoute = groupSubfolderInsideRouteImport.update({ id: '/subfolder/inside', path: '/subfolder/inside', getParentRoute: () => groupRoute, } as any) -const groupLayoutInsidelayoutRoute = groupLayoutInsidelayoutImport.update({ +const groupLayoutInsidelayoutRoute = groupLayoutInsidelayoutRouteImport.update({ id: '/insidelayout', path: '/insidelayout', getParentRoute: () => groupLayoutRoute, @@ -223,197 +223,197 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutRouteImport parentRoute: typeof rootRoute } '/anchor': { id: '/anchor' path: '/anchor' fullPath: '/anchor' - preLoaderRoute: typeof AnchorImport + preLoaderRoute: typeof AnchorRouteImport parentRoute: typeof rootRoute } '/editing-a': { id: '/editing-a' path: '/editing-a' fullPath: '/editing-a' - preLoaderRoute: typeof EditingAImport + preLoaderRoute: typeof EditingARouteImport parentRoute: typeof rootRoute } '/editing-b': { id: '/editing-b' path: '/editing-b' fullPath: '/editing-b' - preLoaderRoute: typeof EditingBImport + preLoaderRoute: typeof EditingBRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/(another-group)/onlyrouteinside': { id: '/(another-group)/onlyrouteinside' path: '/onlyrouteinside' fullPath: '/onlyrouteinside' - preLoaderRoute: typeof anotherGroupOnlyrouteinsideImport + preLoaderRoute: typeof anotherGroupOnlyrouteinsideRouteImport parentRoute: typeof rootRoute } '/(group)': { id: '/(group)' path: '/' fullPath: '/' - preLoaderRoute: typeof groupImport + preLoaderRoute: typeof groupRouteImport parentRoute: typeof rootRoute } '/(group)/_layout': { id: '/(group)/_layout' path: '/' fullPath: '/' - preLoaderRoute: typeof groupLayoutImport + preLoaderRoute: typeof groupLayoutRouteImport parentRoute: typeof groupRoute } '/(group)/inside': { id: '/(group)/inside' path: '/inside' fullPath: '/inside' - preLoaderRoute: typeof groupInsideImport - parentRoute: typeof groupImport + preLoaderRoute: typeof groupInsideRouteImport + parentRoute: typeof groupRouteImport } '/(group)/lazyinside': { id: '/(group)/lazyinside' path: '/lazyinside' fullPath: '/lazyinside' - preLoaderRoute: typeof groupLazyinsideImport - parentRoute: typeof groupImport + preLoaderRoute: typeof groupLazyinsideRouteImport + parentRoute: typeof groupRouteImport } '/_layout/_layout-2': { id: '/_layout/_layout-2' path: '' fullPath: '' - preLoaderRoute: typeof LayoutLayout2Import - parentRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutLayout2RouteImport + parentRoute: typeof LayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/redirect/$target': { id: '/redirect/$target' path: '/redirect/$target' fullPath: '/redirect/$target' - preLoaderRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetRouteImport parentRoute: typeof rootRoute } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/redirect/': { id: '/redirect/' path: '/redirect' fullPath: '/redirect' - preLoaderRoute: typeof RedirectIndexImport + preLoaderRoute: typeof RedirectIndexRouteImport parentRoute: typeof rootRoute } '/(group)/_layout/insidelayout': { id: '/(group)/_layout/insidelayout' path: '/insidelayout' fullPath: '/insidelayout' - preLoaderRoute: typeof groupLayoutInsidelayoutImport - parentRoute: typeof groupLayoutImport + preLoaderRoute: typeof groupLayoutInsidelayoutRouteImport + parentRoute: typeof groupLayoutRouteImport } '/(group)/subfolder/inside': { id: '/(group)/subfolder/inside' path: '/subfolder/inside' fullPath: '/subfolder/inside' - preLoaderRoute: typeof groupSubfolderInsideImport - parentRoute: typeof groupImport + preLoaderRoute: typeof groupSubfolderInsideRouteImport + parentRoute: typeof groupRouteImport } '/_layout/_layout-2/layout-a': { id: '/_layout/_layout-2/layout-a' path: '/layout-a' fullPath: '/layout-a' - preLoaderRoute: typeof LayoutLayout2LayoutAImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutARouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/_layout/_layout-2/layout-b': { id: '/_layout/_layout-2/layout-b' path: '/layout-b' fullPath: '/layout-b' - preLoaderRoute: typeof LayoutLayout2LayoutBImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutBRouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/params/single/$value': { id: '/params/single/$value' path: '/params/single/$value' fullPath: '/params/single/$value' - preLoaderRoute: typeof ParamsSingleValueImport + preLoaderRoute: typeof ParamsSingleValueRouteImport parentRoute: typeof rootRoute } '/posts_/$postId/edit': { id: '/posts_/$postId/edit' path: '/posts/$postId/edit' fullPath: '/posts/$postId/edit' - preLoaderRoute: typeof PostsPostIdEditImport + preLoaderRoute: typeof PostsPostIdEditRouteImport parentRoute: typeof rootRoute } '/redirect/$target/via-beforeLoad': { id: '/redirect/$target/via-beforeLoad' path: '/via-beforeLoad' fullPath: '/redirect/$target/via-beforeLoad' - preLoaderRoute: typeof RedirectTargetViaBeforeLoadImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetViaBeforeLoadRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/via-loader': { id: '/redirect/$target/via-loader' path: '/via-loader' fullPath: '/redirect/$target/via-loader' - preLoaderRoute: typeof RedirectTargetViaLoaderImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetViaLoaderRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/preload/first': { id: '/redirect/preload/first' path: '/redirect/preload/first' fullPath: '/redirect/preload/first' - preLoaderRoute: typeof RedirectPreloadFirstImport + preLoaderRoute: typeof RedirectPreloadFirstRouteImport parentRoute: typeof rootRoute } '/redirect/preload/second': { id: '/redirect/preload/second' path: '/redirect/preload/second' fullPath: '/redirect/preload/second' - preLoaderRoute: typeof RedirectPreloadSecondImport + preLoaderRoute: typeof RedirectPreloadSecondRouteImport parentRoute: typeof rootRoute } '/redirect/preload/third': { id: '/redirect/preload/third' path: '/redirect/preload/third' fullPath: '/redirect/preload/third' - preLoaderRoute: typeof RedirectPreloadThirdImport + preLoaderRoute: typeof RedirectPreloadThirdRouteImport parentRoute: typeof rootRoute } '/redirect/$target/': { id: '/redirect/$target/' path: '/' fullPath: '/redirect/$target/' - preLoaderRoute: typeof RedirectTargetIndexImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetIndexRouteImport + parentRoute: typeof RedirectTargetRouteImport } } } diff --git a/e2e/solid-router/basic-file-based/src/routes/(another-group)/onlyrouteinside.tsx b/e2e/solid-router/basic-file-based/src/routes/(another-group)/onlyrouteinside.tsx index 5dfc82fc33..d935e88ed6 100644 --- a/e2e/solid-router/basic-file-based/src/routes/(another-group)/onlyrouteinside.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/(another-group)/onlyrouteinside.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, getRouteApi, useSearch } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { getRouteApi, useSearch } from '@tanstack/solid-router' import { z } from 'zod' import { zodValidator } from '@tanstack/zod-adapter' diff --git a/e2e/solid-router/basic-file-based/src/routes/(group)/_layout.insidelayout.tsx b/e2e/solid-router/basic-file-based/src/routes/(group)/_layout.insidelayout.tsx index dd06459a35..6ad8947caa 100644 --- a/e2e/solid-router/basic-file-based/src/routes/(group)/_layout.insidelayout.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/(group)/_layout.insidelayout.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, getRouteApi, useSearch } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { getRouteApi, useSearch } from '@tanstack/solid-router' import { z } from 'zod' import { zodValidator } from '@tanstack/zod-adapter' diff --git a/e2e/solid-router/basic-file-based/src/routes/(group)/_layout.tsx b/e2e/solid-router/basic-file-based/src/routes/(group)/_layout.tsx index 660cfb70e6..f403f766aa 100644 --- a/e2e/solid-router/basic-file-based/src/routes/(group)/_layout.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/(group)/_layout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/(group)/_layout')({ component: () => ( diff --git a/e2e/solid-router/basic-file-based/src/routes/(group)/inside.tsx b/e2e/solid-router/basic-file-based/src/routes/(group)/inside.tsx index 76ed0e8a07..fbb420e112 100644 --- a/e2e/solid-router/basic-file-based/src/routes/(group)/inside.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/(group)/inside.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, getRouteApi, useSearch } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { getRouteApi, useSearch } from '@tanstack/solid-router' import { z } from 'zod' import { zodValidator } from '@tanstack/zod-adapter' diff --git a/e2e/solid-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx b/e2e/solid-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx index a68febeadd..ed9b6acb5a 100644 --- a/e2e/solid-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx @@ -1,8 +1,5 @@ -import { - createLazyFileRoute, - getRouteApi, - useSearch, -} from '@tanstack/solid-router' +import { createLazyFileRoute } from '@tanstack/solid-router' +import { getRouteApi, useSearch } from '@tanstack/solid-router' const routeApi = getRouteApi('/(group)/lazyinside') diff --git a/e2e/solid-router/basic-file-based/src/routes/(group)/subfolder/inside.tsx b/e2e/solid-router/basic-file-based/src/routes/(group)/subfolder/inside.tsx index 9e963d170c..4f91b5a4f2 100644 --- a/e2e/solid-router/basic-file-based/src/routes/(group)/subfolder/inside.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/(group)/subfolder/inside.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, getRouteApi, useSearch } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { getRouteApi, useSearch } from '@tanstack/solid-router' import { z } from 'zod' import { zodValidator } from '@tanstack/zod-adapter' diff --git a/e2e/solid-router/basic-file-based/src/routes/_layout.tsx b/e2e/solid-router/basic-file-based/src/routes/_layout.tsx index d43b4ef5f5..5525c0c297 100644 --- a/e2e/solid-router/basic-file-based/src/routes/_layout.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/_layout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/_layout')({ component: LayoutComponent, diff --git a/e2e/solid-router/basic-file-based/src/routes/_layout/_layout-2.tsx b/e2e/solid-router/basic-file-based/src/routes/_layout/_layout-2.tsx index 7a5a3623a0..000a19e988 100644 --- a/e2e/solid-router/basic-file-based/src/routes/_layout/_layout-2.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/_layout/_layout-2.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/_layout/_layout-2')({ component: LayoutComponent, diff --git a/e2e/solid-router/basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx b/e2e/solid-router/basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx index b69951b246..997e6caf80 100644 --- a/e2e/solid-router/basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ component: LayoutAComponent, }) diff --git a/e2e/solid-router/basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx b/e2e/solid-router/basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx index 30dbcce90f..70135c5809 100644 --- a/e2e/solid-router/basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ component: LayoutBComponent, }) diff --git a/e2e/solid-router/basic-file-based/src/routes/anchor.tsx b/e2e/solid-router/basic-file-based/src/routes/anchor.tsx index 77c0e5a6de..944182db7a 100644 --- a/e2e/solid-router/basic-file-based/src/routes/anchor.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/anchor.tsx @@ -1,9 +1,5 @@ -import { - Link, - createFileRoute, - useLocation, - useNavigate, -} from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, useLocation, useNavigate } from '@tanstack/solid-router' import { createEffect, createRenderEffect, diff --git a/e2e/solid-router/basic-file-based/src/routes/editing-a.tsx b/e2e/solid-router/basic-file-based/src/routes/editing-a.tsx index e893169025..ad7b579f33 100644 --- a/e2e/solid-router/basic-file-based/src/routes/editing-a.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/editing-a.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, useBlocker } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { useBlocker } from '@tanstack/solid-router' import { createSignal } from 'solid-js' export const Route = createFileRoute('/editing-a')({ diff --git a/e2e/solid-router/basic-file-based/src/routes/editing-b.tsx b/e2e/solid-router/basic-file-based/src/routes/editing-b.tsx index 3dc2d1655f..660c8fd63b 100644 --- a/e2e/solid-router/basic-file-based/src/routes/editing-b.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/editing-b.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, useBlocker } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { useBlocker } from '@tanstack/solid-router' import { createEffect, createSignal, createMemo } from 'solid-js' export const Route = createFileRoute('/editing-b')({ diff --git a/e2e/solid-router/basic-file-based/src/routes/index.tsx b/e2e/solid-router/basic-file-based/src/routes/index.tsx index bdfb4c7676..3f905db60c 100644 --- a/e2e/solid-router/basic-file-based/src/routes/index.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/')({ component: Home, }) diff --git a/e2e/solid-router/basic-file-based/src/routes/params.single.$value.tsx b/e2e/solid-router/basic-file-based/src/routes/params.single.$value.tsx index 4aca878470..b16c4b47b5 100644 --- a/e2e/solid-router/basic-file-based/src/routes/params.single.$value.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/params.single.$value.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/solid-router' import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' export const Route = createFileRoute('/params/single/$value')({ component: RouteComponent, diff --git a/e2e/solid-router/basic-file-based/src/routes/posts.$postId.tsx b/e2e/solid-router/basic-file-based/src/routes/posts.$postId.tsx index a48895f339..a112484f11 100644 --- a/e2e/solid-router/basic-file-based/src/routes/posts.$postId.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/posts.$postId.tsx @@ -1,4 +1,5 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { ErrorComponent } from '@tanstack/solid-router' import { fetchPost } from '../posts' import type { ErrorComponentProps } from '@tanstack/solid-router' diff --git a/e2e/solid-router/basic-file-based/src/routes/posts.index.tsx b/e2e/solid-router/basic-file-based/src/routes/posts.index.tsx index c7d8cfe19c..ac7c378e60 100644 --- a/e2e/solid-router/basic-file-based/src/routes/posts.index.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/posts.index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, }) diff --git a/e2e/solid-router/basic-file-based/src/routes/posts.tsx b/e2e/solid-router/basic-file-based/src/routes/posts.tsx index 9a9568837f..5a31160395 100644 --- a/e2e/solid-router/basic-file-based/src/routes/posts.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/posts.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import { fetchPosts } from '../posts' export const Route = createFileRoute('/posts')({ diff --git a/e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx b/e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx index f38f369b7a..a1a0cc0b7a 100644 --- a/e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, getRouteApi, useParams } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { getRouteApi, useParams } from '@tanstack/solid-router' export const Route = createFileRoute('/posts_/$postId/edit')({ component: PostEditPage, diff --git a/e2e/solid-router/basic-file-based/src/routes/redirect/$target.tsx b/e2e/solid-router/basic-file-based/src/routes/redirect/$target.tsx index 525dd9da25..1672e7ac3a 100644 --- a/e2e/solid-router/basic-file-based/src/routes/redirect/$target.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/redirect/$target.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, retainSearchParams } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { retainSearchParams } from '@tanstack/solid-router' import z from 'zod' export const Route = createFileRoute('/redirect/$target')({ diff --git a/e2e/solid-router/basic-file-based/src/routes/redirect/$target/index.tsx b/e2e/solid-router/basic-file-based/src/routes/redirect/$target/index.tsx index a44008e3c6..0454fe0a7f 100644 --- a/e2e/solid-router/basic-file-based/src/routes/redirect/$target/index.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/redirect/$target/index.tsx @@ -1,4 +1,5 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' export const Route = createFileRoute('/redirect/$target/')({ component: () => { diff --git a/e2e/solid-router/basic-file-based/src/routes/redirect/$target/via-beforeLoad.tsx b/e2e/solid-router/basic-file-based/src/routes/redirect/$target/via-beforeLoad.tsx index c88cc07986..bc36059052 100644 --- a/e2e/solid-router/basic-file-based/src/routes/redirect/$target/via-beforeLoad.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/redirect/$target/via-beforeLoad.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, redirect } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { redirect } from '@tanstack/solid-router' export const Route = createFileRoute('/redirect/$target/via-beforeLoad')({ beforeLoad: ({ diff --git a/e2e/solid-router/basic-file-based/src/routes/redirect/$target/via-loader.tsx b/e2e/solid-router/basic-file-based/src/routes/redirect/$target/via-loader.tsx index 5c059717c5..0878aaea49 100644 --- a/e2e/solid-router/basic-file-based/src/routes/redirect/$target/via-loader.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/redirect/$target/via-loader.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, redirect } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { redirect } from '@tanstack/solid-router' export const Route = createFileRoute('/redirect/$target/via-loader')({ loaderDeps: ({ search: { reloadDocument, externalHost } }) => ({ diff --git a/e2e/solid-router/basic-file-based/src/routes/redirect/index.tsx b/e2e/solid-router/basic-file-based/src/routes/redirect/index.tsx index 043f305e57..a49aa819ce 100644 --- a/e2e/solid-router/basic-file-based/src/routes/redirect/index.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/redirect/index.tsx @@ -1,4 +1,5 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' export const Route = createFileRoute('/redirect/')({ component: () => ( diff --git a/e2e/solid-router/basic-file-based/src/routes/redirect/preload/first.tsx b/e2e/solid-router/basic-file-based/src/routes/redirect/preload/first.tsx index 68752e5a23..d093f16051 100644 --- a/e2e/solid-router/basic-file-based/src/routes/redirect/preload/first.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/redirect/preload/first.tsx @@ -1,4 +1,5 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' export const Route = createFileRoute('/redirect/preload/first')({ component: RouteComponent, diff --git a/e2e/solid-router/basic-file-based/src/routes/redirect/preload/second.tsx b/e2e/solid-router/basic-file-based/src/routes/redirect/preload/second.tsx index 0ecd74ef80..c4084e43fb 100644 --- a/e2e/solid-router/basic-file-based/src/routes/redirect/preload/second.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/redirect/preload/second.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, redirect } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { redirect } from '@tanstack/solid-router' export const Route = createFileRoute('/redirect/preload/second')({ loader: async () => { diff --git a/e2e/solid-router/basic-file-based/src/routes/redirect/preload/third.tsx b/e2e/solid-router/basic-file-based/src/routes/redirect/preload/third.tsx index e831276d29..35cacf7934 100644 --- a/e2e/solid-router/basic-file-based/src/routes/redirect/preload/third.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/redirect/preload/third.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/redirect/preload/third')({ component: RouteComponent, }) diff --git a/e2e/solid-router/basic-file-based/vite.config.js b/e2e/solid-router/basic-file-based/vite.config.js index 0d2f08b695..1fc0fce40a 100644 --- a/e2e/solid-router/basic-file-based/vite.config.js +++ b/e2e/solid-router/basic-file-based/vite.config.js @@ -1,8 +1,8 @@ import { defineConfig } from 'vite' import solid from 'vite-plugin-solid' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ - plugins: [TanStackRouterVite({ target: 'solid' }), solid()], + plugins: [tanstackRouter({ target: 'solid' }), solid()], }) diff --git a/e2e/solid-router/basic-scroll-restoration/package.json b/e2e/solid-router/basic-scroll-restoration/package.json index f488bb854d..3907e98194 100644 --- a/e2e/solid-router/basic-scroll-restoration/package.json +++ b/e2e/solid-router/basic-scroll-restoration/package.json @@ -24,6 +24,6 @@ "@playwright/test": "^1.50.1", "@tanstack/router-e2e-utils": "workspace:^", "vite-plugin-solid": "^2.11.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/solid-router/basic-solid-query-file-based/package.json b/e2e/solid-router/basic-solid-query-file-based/package.json index 6ff1893b5d..886d34868e 100644 --- a/e2e/solid-router/basic-solid-query-file-based/package.json +++ b/e2e/solid-router/basic-solid-query-file-based/package.json @@ -27,6 +27,6 @@ "@playwright/test": "^1.50.1", "@tanstack/router-e2e-utils": "workspace:^", "vite-plugin-solid": "^2.11.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/solid-router/basic-solid-query-file-based/src/routeTree.gen.ts b/e2e/solid-router/basic-solid-query-file-based/src/routeTree.gen.ts index 06f55406fb..c61533fa24 100644 --- a/e2e/solid-router/basic-solid-query-file-based/src/routeTree.gen.ts +++ b/e2e/solid-router/basic-solid-query-file-based/src/routeTree.gen.ts @@ -11,58 +11,58 @@ // 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 PostsIndexImport } from './routes/posts.index' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as LayoutLayout2Import } from './routes/_layout/_layout-2' -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 PostsRouteImport } from './routes/posts' +import { Route as LayoutRouteImport } from './routes/_layout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2' +import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b' +import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' // Create/Update Routes -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const LayoutRoute = LayoutImport.update({ +const LayoutRoute = LayoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const LayoutLayout2Route = LayoutLayout2Import.update({ +const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) -const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBImport.update({ +const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => LayoutLayout2Route, } as any) -const LayoutLayout2LayoutARoute = LayoutLayout2LayoutAImport.update({ +const LayoutLayout2LayoutARoute = LayoutLayout2LayoutARouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => LayoutLayout2Route, @@ -76,57 +76,57 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/_layout/_layout-2': { id: '/_layout/_layout-2' path: '' fullPath: '' - preLoaderRoute: typeof LayoutLayout2Import - parentRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutLayout2RouteImport + parentRoute: typeof LayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/_layout/_layout-2/layout-a': { id: '/_layout/_layout-2/layout-a' path: '/layout-a' fullPath: '/layout-a' - preLoaderRoute: typeof LayoutLayout2LayoutAImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutARouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/_layout/_layout-2/layout-b': { id: '/_layout/_layout-2/layout-b' path: '/layout-b' fullPath: '/layout-b' - preLoaderRoute: typeof LayoutLayout2LayoutBImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutBRouteImport + parentRoute: typeof LayoutLayout2RouteImport } } } diff --git a/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout.tsx b/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout.tsx index d43b4ef5f5..5525c0c297 100644 --- a/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout.tsx +++ b/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/_layout')({ component: LayoutComponent, diff --git a/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout/_layout-2.tsx b/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout/_layout-2.tsx index 7a5a3623a0..000a19e988 100644 --- a/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout/_layout-2.tsx +++ b/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout/_layout-2.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/_layout/_layout-2')({ component: LayoutComponent, diff --git a/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx b/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx index b69951b246..997e6caf80 100644 --- a/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx +++ b/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ component: LayoutAComponent, }) diff --git a/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx b/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx index 30dbcce90f..70135c5809 100644 --- a/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx +++ b/e2e/solid-router/basic-solid-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ component: LayoutBComponent, }) diff --git a/e2e/solid-router/basic-solid-query-file-based/src/routes/index.tsx b/e2e/solid-router/basic-solid-query-file-based/src/routes/index.tsx index bdfb4c7676..3f905db60c 100644 --- a/e2e/solid-router/basic-solid-query-file-based/src/routes/index.tsx +++ b/e2e/solid-router/basic-solid-query-file-based/src/routes/index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/')({ component: Home, }) diff --git a/e2e/solid-router/basic-solid-query-file-based/src/routes/posts.$postId.tsx b/e2e/solid-router/basic-solid-query-file-based/src/routes/posts.$postId.tsx index 619428c4b5..f771b7be7e 100644 --- a/e2e/solid-router/basic-solid-query-file-based/src/routes/posts.$postId.tsx +++ b/e2e/solid-router/basic-solid-query-file-based/src/routes/posts.$postId.tsx @@ -1,8 +1,5 @@ -import { - ErrorComponent, - createFileRoute, - useRouter, -} from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { ErrorComponent, useRouter } from '@tanstack/solid-router' import { useQuery } from '@tanstack/solid-query' import { createEffect, createMemo } from 'solid-js' import { PostNotFoundError } from '../posts' diff --git a/e2e/solid-router/basic-solid-query-file-based/src/routes/posts.index.tsx b/e2e/solid-router/basic-solid-query-file-based/src/routes/posts.index.tsx index 33d0386c19..812b581e0a 100644 --- a/e2e/solid-router/basic-solid-query-file-based/src/routes/posts.index.tsx +++ b/e2e/solid-router/basic-solid-query-file-based/src/routes/posts.index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, }) diff --git a/e2e/solid-router/basic-solid-query-file-based/src/routes/posts.tsx b/e2e/solid-router/basic-solid-query-file-based/src/routes/posts.tsx index 75d902a00c..d194367647 100644 --- a/e2e/solid-router/basic-solid-query-file-based/src/routes/posts.tsx +++ b/e2e/solid-router/basic-solid-query-file-based/src/routes/posts.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import { useQuery } from '@tanstack/solid-query' import { createMemo } from 'solid-js' import { postsQueryOptions } from '../postsQueryOptions' diff --git a/e2e/solid-router/basic-solid-query-file-based/vite.config.js b/e2e/solid-router/basic-solid-query-file-based/vite.config.js index 4af89e7520..1660a56c17 100644 --- a/e2e/solid-router/basic-solid-query-file-based/vite.config.js +++ b/e2e/solid-router/basic-solid-query-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import solid from 'vite-plugin-solid' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'solid', autoCodeSplitting: true }), + tanstackRouter({ target: 'solid', autoCodeSplitting: true }), solid(), ], }) diff --git a/e2e/solid-router/basic-solid-query/package.json b/e2e/solid-router/basic-solid-query/package.json index db2fa275fa..c9ed84942d 100644 --- a/e2e/solid-router/basic-solid-query/package.json +++ b/e2e/solid-router/basic-solid-query/package.json @@ -25,6 +25,6 @@ "@playwright/test": "^1.50.1", "@tanstack/router-e2e-utils": "workspace:^", "vite-plugin-solid": "^2.11.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/solid-router/basic-virtual-file-based/package.json b/e2e/solid-router/basic-virtual-file-based/package.json index 3d302dee67..53ce56d459 100644 --- a/e2e/solid-router/basic-virtual-file-based/package.json +++ b/e2e/solid-router/basic-virtual-file-based/package.json @@ -26,6 +26,6 @@ "@playwright/test": "^1.50.1", "@tanstack/router-e2e-utils": "workspace:^", "vite-plugin-solid": "^2.11.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/solid-router/basic-virtual-file-based/src/routeTree.gen.ts b/e2e/solid-router/basic-virtual-file-based/src/routeTree.gen.ts index fc2a2b44e1..288a42a970 100644 --- a/e2e/solid-router/basic-virtual-file-based/src/routeTree.gen.ts +++ b/e2e/solid-router/basic-virtual-file-based/src/routeTree.gen.ts @@ -8,89 +8,91 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/solid-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' +import { Route as postsPostsRouteImport } from './routes/posts/posts' +import { Route as layoutFirstLayoutRouteImport } from './routes/layout/first-layout' +import { Route as homeRouteImport } from './routes/home' +import { Route as postsPostsDetailRouteImport } from './routes/posts/posts-detail' +import { Route as layoutSecondLayoutRouteImport } from './routes/layout/second-layout' +import { Route as postsPostsHomeRouteImport } from './routes/posts/posts-home' +import { Route as ClassicHelloRouteRouteImport } from './routes/file-based-subtree/hello/route' +import { Route as ClassicHelloIndexRouteImport } from './routes/file-based-subtree/hello/index' +import { Route as ClassicHelloWorldRouteImport } from './routes/file-based-subtree/hello/world' +import { Route as ClassicHelloUniverseRouteImport } from './routes/file-based-subtree/hello/universe' +import { Route as bRouteImport } from './routes/b' +import { Route as aRouteImport } from './routes/a' // Create/Update Routes -const postsPostsRoute = postsPostsImport.update({ +const postsPostsRoute = postsPostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const layoutFirstLayoutRoute = layoutFirstLayoutImport.update({ +const layoutFirstLayoutRoute = layoutFirstLayoutRouteImport.update({ id: '/_first', getParentRoute: () => rootRoute, } as any) -const homeRoute = homeImport.update({ +const homeRoute = homeRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const postsPostsDetailRoute = postsPostsDetailImport.update({ +const postsPostsDetailRoute = postsPostsDetailRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => postsPostsRoute, } as any) -const layoutSecondLayoutRoute = layoutSecondLayoutImport.update({ +const layoutSecondLayoutRoute = layoutSecondLayoutRouteImport.update({ id: '/_second', getParentRoute: () => layoutFirstLayoutRoute, } as any) -const postsPostsHomeRoute = postsPostsHomeImport.update({ +const postsPostsHomeRoute = postsPostsHomeRouteImport.update({ id: '/', path: '/', getParentRoute: () => postsPostsRoute, } as any) -const ClassicHelloRouteRoute = ClassicHelloRouteImport.update({ +const ClassicHelloRouteRoute = ClassicHelloRouteRouteImport.update({ id: '/classic/hello', path: '/classic/hello', getParentRoute: () => rootRoute, } as any) -const ClassicHelloIndexRoute = ClassicHelloIndexImport.update({ +const ClassicHelloIndexRoute = ClassicHelloIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => ClassicHelloRouteRoute, } as any) -const ClassicHelloWorldRoute = ClassicHelloWorldImport.update({ +const ClassicHelloWorldRoute = ClassicHelloWorldRouteImport.update({ id: '/world', path: '/world', getParentRoute: () => ClassicHelloRouteRoute, } as any) -const ClassicHelloUniverseRoute = ClassicHelloUniverseImport.update({ +const ClassicHelloUniverseRoute = ClassicHelloUniverseRouteImport.update({ id: '/universe', path: '/universe', getParentRoute: () => ClassicHelloRouteRoute, } as any) -const bRoute = bImport.update({ +const bRoute = bRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => layoutSecondLayoutRoute, } as any) -const aRoute = aImport.update({ +const aRoute = aRouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => layoutSecondLayoutRoute, @@ -104,89 +106,200 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof homeImport + preLoaderRoute: typeof homeRouteImport parentRoute: typeof rootRoute } '/_first': { id: '/_first' path: '' fullPath: '' - preLoaderRoute: typeof layoutFirstLayoutImport + preLoaderRoute: typeof layoutFirstLayoutRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof postsPostsImport + preLoaderRoute: typeof postsPostsRouteImport parentRoute: typeof rootRoute } '/classic/hello': { id: '/classic/hello' path: '/classic/hello' fullPath: '/classic/hello' - preLoaderRoute: typeof ClassicHelloRouteImport + preLoaderRoute: typeof ClassicHelloRouteRouteImport parentRoute: typeof rootRoute } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof postsPostsHomeImport - parentRoute: typeof postsPostsImport + preLoaderRoute: typeof postsPostsHomeRouteImport + parentRoute: typeof postsPostsRouteImport } '/_first/_second': { id: '/_first/_second' path: '' fullPath: '' - preLoaderRoute: typeof layoutSecondLayoutImport - parentRoute: typeof layoutFirstLayoutImport + preLoaderRoute: typeof layoutSecondLayoutRouteImport + parentRoute: typeof layoutFirstLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof postsPostsDetailImport - parentRoute: typeof postsPostsImport + preLoaderRoute: typeof postsPostsDetailRouteImport + parentRoute: typeof postsPostsRouteImport } '/_first/_second/layout-a': { id: '/_first/_second/layout-a' path: '/layout-a' fullPath: '/layout-a' - preLoaderRoute: typeof aImport - parentRoute: typeof layoutSecondLayoutImport + preLoaderRoute: typeof aRouteImport + parentRoute: typeof layoutSecondLayoutRouteImport } '/_first/_second/layout-b': { id: '/_first/_second/layout-b' path: '/layout-b' fullPath: '/layout-b' - preLoaderRoute: typeof bImport - parentRoute: typeof layoutSecondLayoutImport + preLoaderRoute: typeof bRouteImport + parentRoute: typeof layoutSecondLayoutRouteImport } '/classic/hello/universe': { id: '/classic/hello/universe' path: '/universe' fullPath: '/classic/hello/universe' - preLoaderRoute: typeof ClassicHelloUniverseImport - parentRoute: typeof ClassicHelloRouteImport + preLoaderRoute: typeof ClassicHelloUniverseRouteImport + parentRoute: typeof ClassicHelloRouteRouteImport } '/classic/hello/world': { id: '/classic/hello/world' path: '/world' fullPath: '/classic/hello/world' - preLoaderRoute: typeof ClassicHelloWorldImport - parentRoute: typeof ClassicHelloRouteImport + preLoaderRoute: typeof ClassicHelloWorldRouteImport + parentRoute: typeof ClassicHelloRouteRouteImport } '/classic/hello/': { id: '/classic/hello/' path: '/' fullPath: '/classic/hello/' - preLoaderRoute: typeof ClassicHelloIndexImport - parentRoute: typeof ClassicHelloRouteImport + preLoaderRoute: typeof ClassicHelloIndexRouteImport + parentRoute: typeof ClassicHelloRouteRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/home' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/layout/first-layout' { + const createFileRoute: CreateFileRoute< + '/_first', + FileRoutesByPath['/_first']['parentRoute'], + FileRoutesByPath['/_first']['id'], + FileRoutesByPath['/_first']['path'], + FileRoutesByPath['/_first']['fullPath'] + > +} +declare module './routes/posts/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/route' { + const createFileRoute: CreateFileRoute< + '/classic/hello', + FileRoutesByPath['/classic/hello']['parentRoute'], + FileRoutesByPath['/classic/hello']['id'], + FileRoutesByPath['/classic/hello']['path'], + FileRoutesByPath['/classic/hello']['fullPath'] + > +} +declare module './routes/posts/posts-home' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/layout/second-layout' { + const createFileRoute: CreateFileRoute< + '/_first/_second', + FileRoutesByPath['/_first/_second']['parentRoute'], + FileRoutesByPath['/_first/_second']['id'], + FileRoutesByPath['/_first/_second']['path'], + FileRoutesByPath['/_first/_second']['fullPath'] + > +} +declare module './routes/posts/posts-detail' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/a' { + const createFileRoute: CreateFileRoute< + '/_first/_second/layout-a', + FileRoutesByPath['/_first/_second/layout-a']['parentRoute'], + FileRoutesByPath['/_first/_second/layout-a']['id'], + FileRoutesByPath['/_first/_second/layout-a']['path'], + FileRoutesByPath['/_first/_second/layout-a']['fullPath'] + > +} +declare module './routes/b' { + const createFileRoute: CreateFileRoute< + '/_first/_second/layout-b', + FileRoutesByPath['/_first/_second/layout-b']['parentRoute'], + FileRoutesByPath['/_first/_second/layout-b']['id'], + FileRoutesByPath['/_first/_second/layout-b']['path'], + FileRoutesByPath['/_first/_second/layout-b']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/universe' { + const createFileRoute: CreateFileRoute< + '/classic/hello/universe', + FileRoutesByPath['/classic/hello/universe']['parentRoute'], + FileRoutesByPath['/classic/hello/universe']['id'], + FileRoutesByPath['/classic/hello/universe']['path'], + FileRoutesByPath['/classic/hello/universe']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/world' { + const createFileRoute: CreateFileRoute< + '/classic/hello/world', + FileRoutesByPath['/classic/hello/world']['parentRoute'], + FileRoutesByPath['/classic/hello/world']['id'], + FileRoutesByPath['/classic/hello/world']['path'], + FileRoutesByPath['/classic/hello/world']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/index' { + const createFileRoute: CreateFileRoute< + '/classic/hello/', + FileRoutesByPath['/classic/hello/']['parentRoute'], + FileRoutesByPath['/classic/hello/']['id'], + FileRoutesByPath['/classic/hello/']['path'], + FileRoutesByPath['/classic/hello/']['fullPath'] + > +} + // Create and export the route tree interface layoutSecondLayoutRouteChildren { @@ -343,3 +456,79 @@ const rootRouteChildren: RootRouteChildren = { export const routeTree = rootRoute ._addFileChildren(rootRouteChildren) ._addFileTypes() + +/* 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/e2e/solid-router/basic-virtual-file-based/src/routes/a.tsx b/e2e/solid-router/basic-virtual-file-based/src/routes/a.tsx index 055cba1e6f..a190b24202 100644 --- a/e2e/solid-router/basic-virtual-file-based/src/routes/a.tsx +++ b/e2e/solid-router/basic-virtual-file-based/src/routes/a.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/_first/_second/layout-a')({ +export const Route = createFileRoute({ component: LayoutAComponent, }) diff --git a/e2e/solid-router/basic-virtual-file-based/src/routes/b.tsx b/e2e/solid-router/basic-virtual-file-based/src/routes/b.tsx index c5bb8051af..505f8f6fbf 100644 --- a/e2e/solid-router/basic-virtual-file-based/src/routes/b.tsx +++ b/e2e/solid-router/basic-virtual-file-based/src/routes/b.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/_first/_second/layout-b')({ +export const Route = createFileRoute({ component: LayoutBComponent, }) diff --git a/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/index.tsx b/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/index.tsx index f7ff537916..f86335e291 100644 --- a/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/index.tsx +++ b/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/classic/hello/')({ +export const Route = createFileRoute({ component: () =>
This is the index
, }) diff --git a/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/route.tsx b/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/route.tsx index f4f30d8425..5b95eea555 100644 --- a/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/route.tsx +++ b/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/route.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/classic/hello')({ +export const Route = createFileRoute({ component: () => (
Hello! diff --git a/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/universe.tsx b/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/universe.tsx index 2a6bf16c37..20b07c41cc 100644 --- a/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/universe.tsx +++ b/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/universe.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/classic/hello/universe')({ +export const Route = createFileRoute({ component: () =>
Hello /classic/hello/universe!
, }) diff --git a/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/world.tsx b/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/world.tsx index 03edc7f484..4af11357a2 100644 --- a/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/world.tsx +++ b/e2e/solid-router/basic-virtual-file-based/src/routes/file-based-subtree/hello/world.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/classic/hello/world')({ +export const Route = createFileRoute({ component: () =>
Hello /classic/hello/world!
, }) diff --git a/e2e/solid-router/basic-virtual-file-based/src/routes/home.tsx b/e2e/solid-router/basic-virtual-file-based/src/routes/home.tsx index bdfb4c7676..510db79b73 100644 --- a/e2e/solid-router/basic-virtual-file-based/src/routes/home.tsx +++ b/e2e/solid-router/basic-virtual-file-based/src/routes/home.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/solid-router/basic-virtual-file-based/src/routes/layout/first-layout.tsx b/e2e/solid-router/basic-virtual-file-based/src/routes/layout/first-layout.tsx index 5c77421bb2..c549175638 100644 --- a/e2e/solid-router/basic-virtual-file-based/src/routes/layout/first-layout.tsx +++ b/e2e/solid-router/basic-virtual-file-based/src/routes/layout/first-layout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/_first')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/solid-router/basic-virtual-file-based/src/routes/layout/second-layout.tsx b/e2e/solid-router/basic-virtual-file-based/src/routes/layout/second-layout.tsx index 9ab147de5e..efeca5ce86 100644 --- a/e2e/solid-router/basic-virtual-file-based/src/routes/layout/second-layout.tsx +++ b/e2e/solid-router/basic-virtual-file-based/src/routes/layout/second-layout.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/_first/_second')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/solid-router/basic-virtual-file-based/src/routes/posts/posts-detail.tsx b/e2e/solid-router/basic-virtual-file-based/src/routes/posts/posts-detail.tsx index 990f473ae8..ef413c1be0 100644 --- a/e2e/solid-router/basic-virtual-file-based/src/routes/posts/posts-detail.tsx +++ b/e2e/solid-router/basic-virtual-file-based/src/routes/posts/posts-detail.tsx @@ -1,4 +1,4 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/solid-router' +import { ErrorComponent } from '@tanstack/solid-router' import { fetchPost } from '../../posts' import type { ErrorComponentProps } from '@tanstack/solid-router' @@ -6,7 +6,7 @@ export function PostErrorComponent({ error }: ErrorComponentProps) { return } -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost(postId), errorComponent: PostErrorComponent as any, notFoundComponent: () => { diff --git a/e2e/solid-router/basic-virtual-file-based/src/routes/posts/posts-home.tsx b/e2e/solid-router/basic-virtual-file-based/src/routes/posts/posts-home.tsx index 33d0386c19..13529228bb 100644 --- a/e2e/solid-router/basic-virtual-file-based/src/routes/posts/posts-home.tsx +++ b/e2e/solid-router/basic-virtual-file-based/src/routes/posts/posts-home.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/e2e/solid-router/basic-virtual-file-based/src/routes/posts/posts.tsx b/e2e/solid-router/basic-virtual-file-based/src/routes/posts/posts.tsx index 9ae6dfc747..46203594d1 100644 --- a/e2e/solid-router/basic-virtual-file-based/src/routes/posts/posts.tsx +++ b/e2e/solid-router/basic-virtual-file-based/src/routes/posts/posts.tsx @@ -1,7 +1,7 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import { fetchPosts } from '../../posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: fetchPosts, component: PostsComponent, }) diff --git a/e2e/solid-router/basic-virtual-file-based/vite.config.ts b/e2e/solid-router/basic-virtual-file-based/vite.config.ts index f87f32286a..1bebd08210 100644 --- a/e2e/solid-router/basic-virtual-file-based/vite.config.ts +++ b/e2e/solid-router/basic-virtual-file-based/vite.config.ts @@ -1,14 +1,15 @@ import { defineConfig } from 'vite' import solid from 'vite-plugin-solid' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' import { routes } from './routes' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'solid', autoCodeSplitting: true, + verboseFileRoutes: false, virtualRouteConfig: routes, }), solid(), diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/package.json b/e2e/solid-router/basic-virtual-named-export-config-file-based/package.json index b79d571fb7..5103593208 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/package.json +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/package.json @@ -26,6 +26,6 @@ "@playwright/test": "^1.50.1", "@tanstack/router-e2e-utils": "workspace:^", "vite-plugin-solid": "^2.11.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/a.tsx b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/a.tsx index 055cba1e6f..a190b24202 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/a.tsx +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/a.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/_first/_second/layout-a')({ +export const Route = createFileRoute({ component: LayoutAComponent, }) diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/b.tsx b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/b.tsx index c5bb8051af..505f8f6fbf 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/b.tsx +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/b.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/_first/_second/layout-b')({ +export const Route = createFileRoute({ component: LayoutBComponent, }) diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx index f7ff537916..f86335e291 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/classic/hello/')({ +export const Route = createFileRoute({ component: () =>
This is the index
, }) diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx index f4f30d8425..5b95eea555 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/classic/hello')({ +export const Route = createFileRoute({ component: () => (
Hello! diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx index 2a6bf16c37..20b07c41cc 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/classic/hello/universe')({ +export const Route = createFileRoute({ component: () =>
Hello /classic/hello/universe!
, }) diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx index 03edc7f484..4af11357a2 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/classic/hello/world')({ +export const Route = createFileRoute({ component: () =>
Hello /classic/hello/world!
, }) diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/home.tsx b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/home.tsx index bdfb4c7676..510db79b73 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/home.tsx +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/home.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx index 5c77421bb2..c549175638 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/_first')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx index 9ab147de5e..efeca5ce86 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/_first/_second')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx index 990f473ae8..ef413c1be0 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx @@ -1,4 +1,4 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/solid-router' +import { ErrorComponent } from '@tanstack/solid-router' import { fetchPost } from '../../posts' import type { ErrorComponentProps } from '@tanstack/solid-router' @@ -6,7 +6,7 @@ export function PostErrorComponent({ error }: ErrorComponentProps) { return } -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost(postId), errorComponent: PostErrorComponent as any, notFoundComponent: () => { diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx index 33d0386c19..13529228bb 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx index 9ae6dfc747..46203594d1 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx @@ -1,7 +1,7 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import { fetchPosts } from '../../posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: fetchPosts, component: PostsComponent, }) diff --git a/e2e/solid-router/basic-virtual-named-export-config-file-based/vite.config.ts b/e2e/solid-router/basic-virtual-named-export-config-file-based/vite.config.ts index 91280315f2..635aa70940 100644 --- a/e2e/solid-router/basic-virtual-named-export-config-file-based/vite.config.ts +++ b/e2e/solid-router/basic-virtual-named-export-config-file-based/vite.config.ts @@ -1,13 +1,14 @@ import { defineConfig } from 'vite' import solid from 'vite-plugin-solid' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'solid', autoCodeSplitting: true, + verboseFileRoutes: false, virtualRouteConfig: './routes.ts', }), solid(), diff --git a/e2e/solid-router/basic/package.json b/e2e/solid-router/basic/package.json index a3316c5ec2..1f557d00c3 100644 --- a/e2e/solid-router/basic/package.json +++ b/e2e/solid-router/basic/package.json @@ -23,6 +23,6 @@ "@playwright/test": "^1.50.1", "@tanstack/router-e2e-utils": "workspace:^", "vite-plugin-solid": "^2.11.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/solid-router/rspack-basic-file-based/rsbuild.config.ts b/e2e/solid-router/rspack-basic-file-based/rsbuild.config.ts index 19909e9d77..27be8f1dfa 100644 --- a/e2e/solid-router/rspack-basic-file-based/rsbuild.config.ts +++ b/e2e/solid-router/rspack-basic-file-based/rsbuild.config.ts @@ -1,6 +1,6 @@ import { defineConfig } from '@rsbuild/core' import { pluginSolid } from '@rsbuild/plugin-solid' -import { TanStackRouterRspack } from '@tanstack/router-plugin/rspack' +import { tanstackRouter } from '@tanstack/router-plugin/rspack' import { pluginBabel } from '@rsbuild/plugin-babel' export default defineConfig({ @@ -12,9 +12,7 @@ export default defineConfig({ ], tools: { rspack: { - plugins: [ - TanStackRouterRspack({ target: 'solid', autoCodeSplitting: true }), - ], + plugins: [tanstackRouter({ target: 'solid', autoCodeSplitting: true })], }, }, }) diff --git a/e2e/solid-router/rspack-basic-file-based/src/routes/_layout.tsx b/e2e/solid-router/rspack-basic-file-based/src/routes/_layout.tsx index d43b4ef5f5..5525c0c297 100644 --- a/e2e/solid-router/rspack-basic-file-based/src/routes/_layout.tsx +++ b/e2e/solid-router/rspack-basic-file-based/src/routes/_layout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/_layout')({ component: LayoutComponent, diff --git a/e2e/solid-router/rspack-basic-file-based/src/routes/_layout/_layout-2.tsx b/e2e/solid-router/rspack-basic-file-based/src/routes/_layout/_layout-2.tsx index 7a5a3623a0..000a19e988 100644 --- a/e2e/solid-router/rspack-basic-file-based/src/routes/_layout/_layout-2.tsx +++ b/e2e/solid-router/rspack-basic-file-based/src/routes/_layout/_layout-2.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/_layout/_layout-2')({ component: LayoutComponent, diff --git a/e2e/solid-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx b/e2e/solid-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx index b69951b246..997e6caf80 100644 --- a/e2e/solid-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx +++ b/e2e/solid-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ component: LayoutAComponent, }) diff --git a/e2e/solid-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx b/e2e/solid-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx index 30dbcce90f..70135c5809 100644 --- a/e2e/solid-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx +++ b/e2e/solid-router/rspack-basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ component: LayoutBComponent, }) diff --git a/e2e/solid-router/rspack-basic-file-based/src/routes/index.tsx b/e2e/solid-router/rspack-basic-file-based/src/routes/index.tsx index bdfb4c7676..3f905db60c 100644 --- a/e2e/solid-router/rspack-basic-file-based/src/routes/index.tsx +++ b/e2e/solid-router/rspack-basic-file-based/src/routes/index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/')({ component: Home, }) diff --git a/e2e/solid-router/rspack-basic-file-based/src/routes/posts.$postId.tsx b/e2e/solid-router/rspack-basic-file-based/src/routes/posts.$postId.tsx index 55f8871d03..7a74c9adec 100644 --- a/e2e/solid-router/rspack-basic-file-based/src/routes/posts.$postId.tsx +++ b/e2e/solid-router/rspack-basic-file-based/src/routes/posts.$postId.tsx @@ -1,4 +1,5 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { ErrorComponent } from '@tanstack/solid-router' import { fetchPost } from '../posts' import type { ErrorComponentProps } from '@tanstack/solid-router' diff --git a/e2e/solid-router/rspack-basic-file-based/src/routes/posts.index.tsx b/e2e/solid-router/rspack-basic-file-based/src/routes/posts.index.tsx index 33d0386c19..812b581e0a 100644 --- a/e2e/solid-router/rspack-basic-file-based/src/routes/posts.index.tsx +++ b/e2e/solid-router/rspack-basic-file-based/src/routes/posts.index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, }) diff --git a/e2e/solid-router/rspack-basic-file-based/src/routes/posts.tsx b/e2e/solid-router/rspack-basic-file-based/src/routes/posts.tsx index 11a999f50a..86fb7a1841 100644 --- a/e2e/solid-router/rspack-basic-file-based/src/routes/posts.tsx +++ b/e2e/solid-router/rspack-basic-file-based/src/routes/posts.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import { fetchPosts } from '../posts' export const Route = createFileRoute('/posts')({ diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/rsbuild.config.ts b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/rsbuild.config.ts index f7b2c574f6..956d9edb08 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/rsbuild.config.ts +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/rsbuild.config.ts @@ -1,6 +1,6 @@ import { defineConfig } from '@rsbuild/core' import { pluginSolid } from '@rsbuild/plugin-solid' -import { TanStackRouterRspack } from '@tanstack/router-plugin/rspack' +import { tanstackRouter } from '@tanstack/router-plugin/rspack' import { pluginBabel } from '@rsbuild/plugin-babel' export default defineConfig({ @@ -13,7 +13,7 @@ export default defineConfig({ tools: { rspack: { plugins: [ - TanStackRouterRspack({ + tanstackRouter({ target: 'solid', autoCodeSplitting: true, virtualRouteConfig: './routes.ts', diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/a.tsx b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/a.tsx index 055cba1e6f..be88a87cbe 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/a.tsx +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_first/_second/layout-a')({ component: LayoutAComponent, }) diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/b.tsx b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/b.tsx index c5bb8051af..c26087837b 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/b.tsx +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_first/_second/layout-b')({ component: LayoutBComponent, }) diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx index f7ff537916..6cc8bb1a6f 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/classic/hello/')({ component: () =>
This is the index
, }) diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx index f4f30d8425..3808e5346d 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/route.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/classic/hello')({ component: () => ( diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx index 2a6bf16c37..f250de10c1 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/universe.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/classic/hello/universe')({ component: () =>
Hello /classic/hello/universe!
, }) diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx index 03edc7f484..d207a49114 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/file-based-subtree/hello/world.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/classic/hello/world')({ component: () =>
Hello /classic/hello/world!
, }) diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/home.tsx b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/home.tsx index bdfb4c7676..3f905db60c 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/home.tsx +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/home.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/')({ component: Home, }) diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx index 5c77421bb2..79135e7727 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/first-layout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/_first')({ component: LayoutComponent, diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx index 9ab147de5e..8d843581a0 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/layout/second-layout.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/_first/_second')({ component: LayoutComponent, diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx index 990f473ae8..05383bbade 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-detail.tsx @@ -1,4 +1,5 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { ErrorComponent } from '@tanstack/solid-router' import { fetchPost } from '../../posts' import type { ErrorComponentProps } from '@tanstack/solid-router' diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx index 33d0386c19..812b581e0a 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts-home.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, }) diff --git a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx index 9ae6dfc747..228fab45f1 100644 --- a/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx +++ b/e2e/solid-router/rspack-basic-virtual-named-export-config-file-based/src/routes/posts/posts.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import { fetchPosts } from '../../posts' export const Route = createFileRoute('/posts')({ diff --git a/e2e/solid-router/scroll-restoration-sandbox-vite/package.json b/e2e/solid-router/scroll-restoration-sandbox-vite/package.json index 936a4a3214..acbbd56681 100644 --- a/e2e/solid-router/scroll-restoration-sandbox-vite/package.json +++ b/e2e/solid-router/scroll-restoration-sandbox-vite/package.json @@ -29,6 +29,6 @@ "@playwright/test": "^1.50.1", "@tanstack/router-e2e-utils": "workspace:^", "vite-plugin-solid": "^2.11.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/e2e/solid-router/scroll-restoration-sandbox-vite/src/routeTree.gen.ts b/e2e/solid-router/scroll-restoration-sandbox-vite/src/routeTree.gen.ts index 03f257bbfa..17dd854433 100644 --- a/e2e/solid-router/scroll-restoration-sandbox-vite/src/routeTree.gen.ts +++ b/e2e/solid-router/scroll-restoration-sandbox-vite/src/routeTree.gen.ts @@ -13,25 +13,27 @@ import { createFileRoute } from '@tanstack/solid-router' // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' -import { Route as testsPageWithSearchImport } from './routes/(tests)/page-with-search' -import { Route as testsNormalPageImport } from './routes/(tests)/normal-page' -import { Route as testsLazyWithLoaderPageImport } from './routes/(tests)/lazy-with-loader-page' -import { Route as testsLazyPageImport } from './routes/(tests)/lazy-page' +import { Route as IndexRouteImport } from './routes/index' +import { Route as testsPageWithSearchRouteImport } from './routes/(tests)/page-with-search' +import { Route as testsNormalPageRouteImport } from './routes/(tests)/normal-page' +import { Route as testsLazyWithLoaderPageRouteImport } from './routes/(tests)/lazy-with-loader-page' +import { Route as testsLazyPageRouteImport } from './routes/(tests)/lazy-page' // Create Virtual Routes -const testsVirtualPageLazyImport = createFileRoute('/(tests)/virtual-page')() +const testsVirtualPageLazyRouteImport = createFileRoute( + '/(tests)/virtual-page', +)() // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const testsVirtualPageLazyRoute = testsVirtualPageLazyImport +const testsVirtualPageLazyRoute = testsVirtualPageLazyRouteImport .update({ id: '/(tests)/virtual-page', path: '/virtual-page', @@ -39,19 +41,19 @@ const testsVirtualPageLazyRoute = testsVirtualPageLazyImport } as any) .lazy(() => import('./routes/(tests)/virtual-page.lazy').then((d) => d.Route)) -const testsPageWithSearchRoute = testsPageWithSearchImport.update({ +const testsPageWithSearchRoute = testsPageWithSearchRouteImport.update({ id: '/(tests)/page-with-search', path: '/page-with-search', getParentRoute: () => rootRoute, } as any) -const testsNormalPageRoute = testsNormalPageImport.update({ +const testsNormalPageRoute = testsNormalPageRouteImport.update({ id: '/(tests)/normal-page', path: '/normal-page', getParentRoute: () => rootRoute, } as any) -const testsLazyWithLoaderPageRoute = testsLazyWithLoaderPageImport +const testsLazyWithLoaderPageRoute = testsLazyWithLoaderPageRouteImport .update({ id: '/(tests)/lazy-with-loader-page', path: '/lazy-with-loader-page', @@ -61,7 +63,7 @@ const testsLazyWithLoaderPageRoute = testsLazyWithLoaderPageImport import('./routes/(tests)/lazy-with-loader-page.lazy').then((d) => d.Route), ) -const testsLazyPageRoute = testsLazyPageImport +const testsLazyPageRoute = testsLazyPageRouteImport .update({ id: '/(tests)/lazy-page', path: '/lazy-page', @@ -77,42 +79,42 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/(tests)/lazy-page': { id: '/(tests)/lazy-page' path: '/lazy-page' fullPath: '/lazy-page' - preLoaderRoute: typeof testsLazyPageImport + preLoaderRoute: typeof testsLazyPageRouteImport parentRoute: typeof rootRoute } '/(tests)/lazy-with-loader-page': { id: '/(tests)/lazy-with-loader-page' path: '/lazy-with-loader-page' fullPath: '/lazy-with-loader-page' - preLoaderRoute: typeof testsLazyWithLoaderPageImport + preLoaderRoute: typeof testsLazyWithLoaderPageRouteImport parentRoute: typeof rootRoute } '/(tests)/normal-page': { id: '/(tests)/normal-page' path: '/normal-page' fullPath: '/normal-page' - preLoaderRoute: typeof testsNormalPageImport + preLoaderRoute: typeof testsNormalPageRouteImport parentRoute: typeof rootRoute } '/(tests)/page-with-search': { id: '/(tests)/page-with-search' path: '/page-with-search' fullPath: '/page-with-search' - preLoaderRoute: typeof testsPageWithSearchImport + preLoaderRoute: typeof testsPageWithSearchRouteImport parentRoute: typeof rootRoute } '/(tests)/virtual-page': { id: '/(tests)/virtual-page' path: '/virtual-page' fullPath: '/virtual-page' - preLoaderRoute: typeof testsVirtualPageLazyImport + preLoaderRoute: typeof testsVirtualPageLazyRouteImport parentRoute: typeof rootRoute } } diff --git a/e2e/solid-router/scroll-restoration-sandbox-vite/src/routes/(tests)/lazy-page.tsx b/e2e/solid-router/scroll-restoration-sandbox-vite/src/routes/(tests)/lazy-page.tsx index 042a053765..bec395f32c 100644 --- a/e2e/solid-router/scroll-restoration-sandbox-vite/src/routes/(tests)/lazy-page.tsx +++ b/e2e/solid-router/scroll-restoration-sandbox-vite/src/routes/(tests)/lazy-page.tsx @@ -1,3 +1,2 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/(tests)/lazy-page')({}) diff --git a/e2e/solid-router/scroll-restoration-sandbox-vite/src/routes/index.tsx b/e2e/solid-router/scroll-restoration-sandbox-vite/src/routes/index.tsx index 991ecc3435..ddb3755915 100644 --- a/e2e/solid-router/scroll-restoration-sandbox-vite/src/routes/index.tsx +++ b/e2e/solid-router/scroll-restoration-sandbox-vite/src/routes/index.tsx @@ -1,4 +1,5 @@ -import { Link, createFileRoute, linkOptions } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, linkOptions } from '@tanstack/solid-router' export const Route = createFileRoute('/')({ component: HomeComponent, diff --git a/e2e/solid-router/scroll-restoration-sandbox-vite/vite.config.js b/e2e/solid-router/scroll-restoration-sandbox-vite/vite.config.js index 0d2f08b695..1fc0fce40a 100644 --- a/e2e/solid-router/scroll-restoration-sandbox-vite/vite.config.js +++ b/e2e/solid-router/scroll-restoration-sandbox-vite/vite.config.js @@ -1,8 +1,8 @@ import { defineConfig } from 'vite' import solid from 'vite-plugin-solid' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ - plugins: [TanStackRouterVite({ target: 'solid' }), solid()], + plugins: [tanstackRouter({ target: 'solid' }), solid()], }) diff --git a/e2e/solid-start/basic-tsr-config/.gitignore b/e2e/solid-start/basic-tsr-config/.gitignore index 2b76174be5..14577724eb 100644 --- a/e2e/solid-start/basic-tsr-config/.gitignore +++ b/e2e/solid-start/basic-tsr-config/.gitignore @@ -7,13 +7,11 @@ yarn.lock .env .vercel .output -.vinxi /build/ /api/ /server/build /public/build -.vinxi # Sentry Config File .env.sentry-build-plugin /test-results/ diff --git a/e2e/solid-start/basic-tsr-config/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/solid-start/basic-tsr-config/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..2dc6bfc4bd --- /dev/null +++ b/e2e/solid-start/basic-tsr-config/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/solid-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/solid-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/solid-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/solid-start/basic-tsr-config/app.config.ts b/e2e/solid-start/basic-tsr-config/app.config.ts deleted file mode 100644 index d798414e98..0000000000 --- a/e2e/solid-start/basic-tsr-config/app.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -// app.config.ts -import { defineConfig } from '@tanstack/solid-start/config' - -export default defineConfig({ - tsr: { - appDirectory: './src/app', - }, -}) diff --git a/e2e/solid-start/basic-tsr-config/package.json b/e2e/solid-start/basic-tsr-config/package.json index 475a1d746b..5ad3489cac 100644 --- a/e2e/solid-start/basic-tsr-config/package.json +++ b/e2e/solid-start/basic-tsr-config/package.json @@ -4,10 +4,10 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "rimraf ./count.txt && vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "rimraf ./count.txt && vite build && tsc --noEmit", + "start": "node .output/server/index.mjs", "test:e2e": "playwright test --project=chromium" }, "dependencies": { @@ -15,11 +15,12 @@ "@tanstack/solid-router-devtools": "workspace:^", "@tanstack/solid-start": "workspace:^", "solid-js": "^1.9.5", - "vinxi": "0.5.3" + "vite": "6.3.5" }, "devDependencies": { "@tanstack/router-e2e-utils": "workspace:^", "@types/node": "^22.10.2", - "typescript": "^5.7.2" + "typescript": "^5.7.2", + "vite-tsconfig-paths": "^5.1.4" } } diff --git a/e2e/solid-start/basic-tsr-config/playwright.config.ts b/e2e/solid-start/basic-tsr-config/playwright.config.ts index bb77d0cf70..e834d88cf4 100644 --- a/e2e/solid-start/basic-tsr-config/playwright.config.ts +++ b/e2e/solid-start/basic-tsr-config/playwright.config.ts @@ -4,6 +4,7 @@ import packageJson from './package.json' with { type: 'json' } const PORT = derivePort(packageJson.name) const baseURL = `http://localhost:${PORT}` + /** * See https://playwright.dev/docs/test-configuration. */ @@ -19,7 +20,7 @@ export default defineConfig({ }, webServer: { - command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm start --port ${PORT}`, + command: `pnpm build && VITE_SERVER_PORT=${PORT} PORT=${PORT} pnpm start`, url: baseURL, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/e2e/solid-start/basic-tsr-config/src/app/client.tsx b/e2e/solid-start/basic-tsr-config/src/app/client.tsx deleted file mode 100644 index ba0f02fac0..0000000000 --- a/e2e/solid-start/basic-tsr-config/src/app/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrate } from 'solid-js/web' -import { StartClient } from '@tanstack/solid-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrate(() => , document.body) diff --git a/e2e/solid-start/basic-tsr-config/src/app/routeTree.gen.ts b/e2e/solid-start/basic-tsr-config/src/app/routeTree.gen.ts index c260510053..3a60fd4405 100644 --- a/e2e/solid-start/basic-tsr-config/src/app/routeTree.gen.ts +++ b/e2e/solid-start/basic-tsr-config/src/app/routeTree.gen.ts @@ -8,14 +8,16 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/solid-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -29,12 +31,24 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/e2e/solid-start/basic-tsr-config/src/app/routes/index.tsx b/e2e/solid-start/basic-tsr-config/src/app/routes/index.tsx index 4d15620109..32e530dbbf 100644 --- a/e2e/solid-start/basic-tsr-config/src/app/routes/index.tsx +++ b/e2e/solid-start/basic-tsr-config/src/app/routes/index.tsx @@ -1,5 +1,5 @@ import fs from 'node:fs' -import { createFileRoute, useRouter } from '@tanstack/solid-router' +import { useRouter } from '@tanstack/solid-router' import { createServerFn } from '@tanstack/solid-start' const filePath = 'count.txt' @@ -17,7 +17,7 @@ const updateCount = createServerFn({ method: 'POST' }) const count = await getCount() await fs.promises.writeFile(filePath, `${count + data}`) }) -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, loader: async () => await getCount(), }) diff --git a/e2e/solid-start/basic-tsr-config/src/app/tanstack-start.d.ts b/e2e/solid-start/basic-tsr-config/src/app/tanstack-start.d.ts new file mode 100644 index 0000000000..df36e6de73 --- /dev/null +++ b/e2e/solid-start/basic-tsr-config/src/app/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/solid-start/basic-tsr-config/src/app/vite-env.d.ts b/e2e/solid-start/basic-tsr-config/src/app/vite-env.d.ts new file mode 100644 index 0000000000..0b2af560d6 --- /dev/null +++ b/e2e/solid-start/basic-tsr-config/src/app/vite-env.d.ts @@ -0,0 +1,4 @@ +declare module '*?url' { + const url: string + export default url +} diff --git a/e2e/solid-start/basic-tsr-config/vite.config.ts b/e2e/solid-start/basic-tsr-config/vite.config.ts new file mode 100644 index 0000000000..347962b83d --- /dev/null +++ b/e2e/solid-start/basic-tsr-config/vite.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart({ + tsr: { + srcDirectory: './src/app', + }, + }), + ], +}) diff --git a/e2e/solid-start/basic/.gitignore b/e2e/solid-start/basic/.gitignore index be342025da..a79d5cf129 100644 --- a/e2e/solid-start/basic/.gitignore +++ b/e2e/solid-start/basic/.gitignore @@ -7,13 +7,11 @@ yarn.lock .env .vercel .output -.vinxi /build/ /api/ /server/build /public/build -.vinxi # Sentry Config File .env.sentry-build-plugin /test-results/ diff --git a/e2e/solid-start/basic/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/solid-start/basic/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..e36fccb479 --- /dev/null +++ b/e2e/solid-start/basic/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,155 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/solid-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/solid-start/server' + +import { ServerRoute as ApiUsersRouteImport } from './../../src/routes/api/users' +import { ServerRoute as ApiUsersUserIdRouteImport } from './../../src/routes/api/users.$userId' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +const ApiUsersRoute = ApiUsersRouteImport.update({ + id: '/api/users', + path: '/api/users', + getParentRoute: () => rootRoute, +} as any) + +const ApiUsersUserIdRoute = ApiUsersUserIdRouteImport.update({ + id: '/$userId', + path: '/$userId', + getParentRoute: () => ApiUsersRoute, +} as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/solid-start/server' { + interface FileRoutesByPath { + '/api/users': { + id: '/api/users' + path: '/api/users' + fullPath: '/api/users' + preLoaderRoute: typeof ApiUsersRouteImport + parentRoute: typeof rootRoute + } + '/api/users/$userId': { + id: '/api/users/$userId' + path: '/$userId' + fullPath: '/api/users/$userId' + preLoaderRoute: typeof ApiUsersUserIdRouteImport + parentRoute: typeof ApiUsersRouteImport + } + } +} + +// Add type-safety to the createFileRoute function across the route tree + +declare module './../../src/routes/api/users' { + const createServerFileRoute: CreateServerFileRoute< + FileRoutesByPath['/api/users']['parentRoute'], + FileRoutesByPath['/api/users']['id'], + FileRoutesByPath['/api/users']['path'], + FileRoutesByPath['/api/users']['fullPath'], + ApiUsersRouteChildren + > +} +declare module './../../src/routes/api/users.$userId' { + const createServerFileRoute: CreateServerFileRoute< + FileRoutesByPath['/api/users/$userId']['parentRoute'], + FileRoutesByPath['/api/users/$userId']['id'], + FileRoutesByPath['/api/users/$userId']['path'], + FileRoutesByPath['/api/users/$userId']['fullPath'], + unknown + > +} + +// Create and export the route tree + +interface ApiUsersRouteChildren { + ApiUsersUserIdRoute: typeof ApiUsersUserIdRoute +} + +const ApiUsersRouteChildren: ApiUsersRouteChildren = { + ApiUsersUserIdRoute: ApiUsersUserIdRoute, +} + +const ApiUsersRouteWithChildren = ApiUsersRoute._addFileChildren( + ApiUsersRouteChildren, +) + +export interface FileRoutesByFullPath { + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$userId': typeof ApiUsersUserIdRoute +} + +export interface FileRoutesByTo { + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$userId': typeof ApiUsersUserIdRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$userId': typeof ApiUsersUserIdRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/api/users' | '/api/users/$userId' + fileRoutesByTo: FileRoutesByTo + to: '/api/users' | '/api/users/$userId' + id: '__root__' | '/api/users' | '/api/users/$userId' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + ApiUsersRoute: typeof ApiUsersRouteWithChildren +} + +const rootRouteChildren: RootRouteChildren = { + ApiUsersRoute: ApiUsersRouteWithChildren, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/api/users" + ] + }, + "/api/users": { + "filePath": "api/users.ts", + "children": [ + "/api/users/$userId" + ] + }, + "/api/users/$userId": { + "filePath": "api/users.$userId.ts", + "parent": "/api/users" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/solid-start/basic/app.config.ts b/e2e/solid-start/basic/app.config.ts deleted file mode 100644 index 2a06e3d3f0..0000000000 --- a/e2e/solid-start/basic/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/solid-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/e2e/solid-start/basic/package.json b/e2e/solid-start/basic/package.json index a10fb47d62..791b179916 100644 --- a/e2e/solid-start/basic/package.json +++ b/e2e/solid-start/basic/package.json @@ -4,32 +4,32 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "node .output/server/index.mjs", "test:e2e": "playwright test --project=chromium" }, "dependencies": { "@tanstack/solid-router": "workspace:^", "@tanstack/solid-router-devtools": "workspace:^", "@tanstack/solid-start": "workspace:^", - "solid-js": "^1.9.5", "redaxios": "^0.5.1", + "solid-js": "^1.9.5", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", + "vite": "6.3.5", "zod": "^3.24.2" }, "devDependencies": { "@playwright/test": "^1.50.1", - "@types/node": "^22.10.2", "@tanstack/router-e2e-utils": "workspace:^", - "vite-plugin-solid": "^2.11.2", + "@types/node": "^22.10.2", + "autoprefixer": "^10.4.20", "combinate": "^1.1.11", "postcss": "^8.5.1", - "autoprefixer": "^10.4.20", "tailwindcss": "^3.4.17", "typescript": "^5.7.2", + "vite-plugin-solid": "^2.11.2", "vite-tsconfig-paths": "^5.1.4" } } diff --git a/e2e/solid-start/basic/playwright.config.ts b/e2e/solid-start/basic/playwright.config.ts index 95d043d48b..e834d88cf4 100644 --- a/e2e/solid-start/basic/playwright.config.ts +++ b/e2e/solid-start/basic/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ }, webServer: { - command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm start --port ${PORT}`, + command: `pnpm build && VITE_SERVER_PORT=${PORT} PORT=${PORT} pnpm start`, url: baseURL, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/e2e/solid-start/basic/src/api.ts b/e2e/solid-start/basic/src/api.ts deleted file mode 100644 index ed511bcd26..0000000000 --- a/e2e/solid-start/basic/src/api.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { - createStartAPIHandler, - defaultAPIFileRouteHandler, -} from '@tanstack/solid-start/api' - -export default createStartAPIHandler(defaultAPIFileRouteHandler) diff --git a/e2e/solid-start/basic/src/client.tsx b/e2e/solid-start/basic/src/client.tsx index ba0f02fac0..b2fdcc9505 100644 --- a/e2e/solid-start/basic/src/client.tsx +++ b/e2e/solid-start/basic/src/client.tsx @@ -1,8 +1,11 @@ -/// +// DO NOT DELETE THIS FILE!!! +// This file is a good smoke test to make sure the custom client entry is working import { hydrate } from 'solid-js/web' import { StartClient } from '@tanstack/solid-start' import { createRouter } from './router' +console.log("[client-entry]: using custom client entry in 'src/client.tsx'") + const router = createRouter() hydrate(() => , document.body) diff --git a/e2e/solid-start/basic/src/routeTree.gen.ts b/e2e/solid-start/basic/src/routeTree.gen.ts index db7101d5f5..d4db3b87d4 100644 --- a/e2e/solid-start/basic/src/routeTree.gen.ts +++ b/e2e/solid-start/basic/src/routeTree.gen.ts @@ -8,220 +8,222 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/solid-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as UsersImport } from './routes/users' -import { Route as StreamImport } from './routes/stream' -import { Route as SearchParamsImport } from './routes/search-params' -import { Route as ScriptsImport } from './routes/scripts' -import { Route as PostsImport } from './routes/posts' -import { Route as LinksImport } from './routes/links' -import { Route as DeferredImport } from './routes/deferred' -import { Route as LayoutImport } from './routes/_layout' -import { Route as NotFoundRouteImport } from './routes/not-found/route' -import { Route as IndexImport } from './routes/index' -import { Route as UsersIndexImport } from './routes/users.index' -import { Route as RedirectIndexImport } from './routes/redirect/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as NotFoundIndexImport } from './routes/not-found/index' -import { Route as UsersUserIdImport } from './routes/users.$userId' -import { Route as RedirectTargetImport } from './routes/redirect/$target' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as NotFoundViaLoaderImport } from './routes/not-found/via-loader' -import { Route as NotFoundViaBeforeLoadImport } from './routes/not-found/via-beforeLoad' -import { Route as LayoutLayout2Import } from './routes/_layout/_layout-2' -import { Route as RedirectTargetIndexImport } from './routes/redirect/$target/index' -import { Route as RedirectTargetViaLoaderImport } from './routes/redirect/$target/via-loader' -import { Route as RedirectTargetViaBeforeLoadImport } from './routes/redirect/$target/via-beforeLoad' -import { Route as PostsPostIdDeepImport } from './routes/posts_.$postId.deep' -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 RedirectTargetServerFnIndexImport } from './routes/redirect/$target/serverFn/index' -import { Route as RedirectTargetServerFnViaUseServerFnImport } from './routes/redirect/$target/serverFn/via-useServerFn' -import { Route as RedirectTargetServerFnViaLoaderImport } from './routes/redirect/$target/serverFn/via-loader' -import { Route as RedirectTargetServerFnViaBeforeLoadImport } from './routes/redirect/$target/serverFn/via-beforeLoad' +import { Route as UsersRouteImport } from './routes/users' +import { Route as StreamRouteImport } from './routes/stream' +import { Route as SearchParamsRouteImport } from './routes/search-params' +import { Route as ScriptsRouteImport } from './routes/scripts' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as LinksRouteImport } from './routes/links' +import { Route as DeferredRouteImport } from './routes/deferred' +import { Route as LayoutRouteImport } from './routes/_layout' +import { Route as NotFoundRouteRouteImport } from './routes/not-found/route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as UsersIndexRouteImport } from './routes/users.index' +import { Route as RedirectIndexRouteImport } from './routes/redirect/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as NotFoundIndexRouteImport } from './routes/not-found/index' +import { Route as UsersUserIdRouteImport } from './routes/users.$userId' +import { Route as RedirectTargetRouteImport } from './routes/redirect/$target' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as NotFoundViaLoaderRouteImport } from './routes/not-found/via-loader' +import { Route as NotFoundViaBeforeLoadRouteImport } from './routes/not-found/via-beforeLoad' +import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2' +import { Route as RedirectTargetIndexRouteImport } from './routes/redirect/$target/index' +import { Route as RedirectTargetViaLoaderRouteImport } from './routes/redirect/$target/via-loader' +import { Route as RedirectTargetViaBeforeLoadRouteImport } from './routes/redirect/$target/via-beforeLoad' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts_.$postId.deep' +import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b' +import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' +import { Route as RedirectTargetServerFnIndexRouteImport } from './routes/redirect/$target/serverFn/index' +import { Route as RedirectTargetServerFnViaUseServerFnRouteImport } from './routes/redirect/$target/serverFn/via-useServerFn' +import { Route as RedirectTargetServerFnViaLoaderRouteImport } from './routes/redirect/$target/serverFn/via-loader' +import { Route as RedirectTargetServerFnViaBeforeLoadRouteImport } from './routes/redirect/$target/serverFn/via-beforeLoad' // Create/Update Routes -const UsersRoute = UsersImport.update({ +const UsersRoute = UsersRouteImport.update({ id: '/users', path: '/users', getParentRoute: () => rootRoute, } as any) -const StreamRoute = StreamImport.update({ +const StreamRoute = StreamRouteImport.update({ id: '/stream', path: '/stream', getParentRoute: () => rootRoute, } as any) -const SearchParamsRoute = SearchParamsImport.update({ +const SearchParamsRoute = SearchParamsRouteImport.update({ id: '/search-params', path: '/search-params', getParentRoute: () => rootRoute, } as any) -const ScriptsRoute = ScriptsImport.update({ +const ScriptsRoute = ScriptsRouteImport.update({ id: '/scripts', path: '/scripts', getParentRoute: () => rootRoute, } as any) -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const LinksRoute = LinksImport.update({ +const LinksRoute = LinksRouteImport.update({ id: '/links', path: '/links', getParentRoute: () => rootRoute, } as any) -const DeferredRoute = DeferredImport.update({ +const DeferredRoute = DeferredRouteImport.update({ id: '/deferred', path: '/deferred', getParentRoute: () => rootRoute, } as any) -const LayoutRoute = LayoutImport.update({ +const LayoutRoute = LayoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const NotFoundRouteRoute = NotFoundRouteImport.update({ +const NotFoundRouteRoute = NotFoundRouteRouteImport.update({ id: '/not-found', path: '/not-found', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const UsersIndexRoute = UsersIndexImport.update({ +const UsersIndexRoute = UsersIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => UsersRoute, } as any) -const RedirectIndexRoute = RedirectIndexImport.update({ +const RedirectIndexRoute = RedirectIndexRouteImport.update({ id: '/redirect/', path: '/redirect/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const NotFoundIndexRoute = NotFoundIndexImport.update({ +const NotFoundIndexRoute = NotFoundIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => NotFoundRouteRoute, } as any) -const UsersUserIdRoute = UsersUserIdImport.update({ +const UsersUserIdRoute = UsersUserIdRouteImport.update({ id: '/$userId', path: '/$userId', getParentRoute: () => UsersRoute, } as any) -const RedirectTargetRoute = RedirectTargetImport.update({ +const RedirectTargetRoute = RedirectTargetRouteImport.update({ id: '/redirect/$target', path: '/redirect/$target', getParentRoute: () => rootRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const NotFoundViaLoaderRoute = NotFoundViaLoaderImport.update({ +const NotFoundViaLoaderRoute = NotFoundViaLoaderRouteImport.update({ id: '/via-loader', path: '/via-loader', getParentRoute: () => NotFoundRouteRoute, } as any) -const NotFoundViaBeforeLoadRoute = NotFoundViaBeforeLoadImport.update({ +const NotFoundViaBeforeLoadRoute = NotFoundViaBeforeLoadRouteImport.update({ id: '/via-beforeLoad', path: '/via-beforeLoad', getParentRoute: () => NotFoundRouteRoute, } as any) -const LayoutLayout2Route = LayoutLayout2Import.update({ +const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) -const RedirectTargetIndexRoute = RedirectTargetIndexImport.update({ +const RedirectTargetIndexRoute = RedirectTargetIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => RedirectTargetRoute, } as any) -const RedirectTargetViaLoaderRoute = RedirectTargetViaLoaderImport.update({ +const RedirectTargetViaLoaderRoute = RedirectTargetViaLoaderRouteImport.update({ id: '/via-loader', path: '/via-loader', getParentRoute: () => RedirectTargetRoute, } as any) const RedirectTargetViaBeforeLoadRoute = - RedirectTargetViaBeforeLoadImport.update({ + RedirectTargetViaBeforeLoadRouteImport.update({ id: '/via-beforeLoad', path: '/via-beforeLoad', getParentRoute: () => RedirectTargetRoute, } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/posts_/$postId/deep', path: '/posts/$postId/deep', getParentRoute: () => rootRoute, } as any) -const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBImport.update({ +const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => LayoutLayout2Route, } as any) -const LayoutLayout2LayoutARoute = LayoutLayout2LayoutAImport.update({ +const LayoutLayout2LayoutARoute = LayoutLayout2LayoutARouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => LayoutLayout2Route, } as any) const RedirectTargetServerFnIndexRoute = - RedirectTargetServerFnIndexImport.update({ + RedirectTargetServerFnIndexRouteImport.update({ id: '/serverFn/', path: '/serverFn/', getParentRoute: () => RedirectTargetRoute, } as any) const RedirectTargetServerFnViaUseServerFnRoute = - RedirectTargetServerFnViaUseServerFnImport.update({ + RedirectTargetServerFnViaUseServerFnRouteImport.update({ id: '/serverFn/via-useServerFn', path: '/serverFn/via-useServerFn', getParentRoute: () => RedirectTargetRoute, } as any) const RedirectTargetServerFnViaLoaderRoute = - RedirectTargetServerFnViaLoaderImport.update({ + RedirectTargetServerFnViaLoaderRouteImport.update({ id: '/serverFn/via-loader', path: '/serverFn/via-loader', getParentRoute: () => RedirectTargetRoute, } as any) const RedirectTargetServerFnViaBeforeLoadRoute = - RedirectTargetServerFnViaBeforeLoadImport.update({ + RedirectTargetServerFnViaBeforeLoadRouteImport.update({ id: '/serverFn/via-beforeLoad', path: '/serverFn/via-beforeLoad', getParentRoute: () => RedirectTargetRoute, @@ -235,215 +237,488 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/not-found': { id: '/not-found' path: '/not-found' fullPath: '/not-found' - preLoaderRoute: typeof NotFoundRouteImport + preLoaderRoute: typeof NotFoundRouteRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutRouteImport parentRoute: typeof rootRoute } '/deferred': { id: '/deferred' path: '/deferred' fullPath: '/deferred' - preLoaderRoute: typeof DeferredImport + preLoaderRoute: typeof DeferredRouteImport parentRoute: typeof rootRoute } '/links': { id: '/links' path: '/links' fullPath: '/links' - preLoaderRoute: typeof LinksImport + preLoaderRoute: typeof LinksRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/scripts': { id: '/scripts' path: '/scripts' fullPath: '/scripts' - preLoaderRoute: typeof ScriptsImport + preLoaderRoute: typeof ScriptsRouteImport parentRoute: typeof rootRoute } '/search-params': { id: '/search-params' path: '/search-params' fullPath: '/search-params' - preLoaderRoute: typeof SearchParamsImport + preLoaderRoute: typeof SearchParamsRouteImport parentRoute: typeof rootRoute } '/stream': { id: '/stream' path: '/stream' fullPath: '/stream' - preLoaderRoute: typeof StreamImport + preLoaderRoute: typeof StreamRouteImport parentRoute: typeof rootRoute } '/users': { id: '/users' path: '/users' fullPath: '/users' - preLoaderRoute: typeof UsersImport + preLoaderRoute: typeof UsersRouteImport parentRoute: typeof rootRoute } '/_layout/_layout-2': { id: '/_layout/_layout-2' path: '' fullPath: '' - preLoaderRoute: typeof LayoutLayout2Import - parentRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutLayout2RouteImport + parentRoute: typeof LayoutRouteImport } '/not-found/via-beforeLoad': { id: '/not-found/via-beforeLoad' path: '/via-beforeLoad' fullPath: '/not-found/via-beforeLoad' - preLoaderRoute: typeof NotFoundViaBeforeLoadImport - parentRoute: typeof NotFoundRouteImport + preLoaderRoute: typeof NotFoundViaBeforeLoadRouteImport + parentRoute: typeof NotFoundRouteRouteImport } '/not-found/via-loader': { id: '/not-found/via-loader' path: '/via-loader' fullPath: '/not-found/via-loader' - preLoaderRoute: typeof NotFoundViaLoaderImport - parentRoute: typeof NotFoundRouteImport + preLoaderRoute: typeof NotFoundViaLoaderRouteImport + parentRoute: typeof NotFoundRouteRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/redirect/$target': { id: '/redirect/$target' path: '/redirect/$target' fullPath: '/redirect/$target' - preLoaderRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetRouteImport parentRoute: typeof rootRoute } '/users/$userId': { id: '/users/$userId' path: '/$userId' fullPath: '/users/$userId' - preLoaderRoute: typeof UsersUserIdImport - parentRoute: typeof UsersImport + preLoaderRoute: typeof UsersUserIdRouteImport + parentRoute: typeof UsersRouteImport } '/not-found/': { id: '/not-found/' path: '/' fullPath: '/not-found/' - preLoaderRoute: typeof NotFoundIndexImport - parentRoute: typeof NotFoundRouteImport + preLoaderRoute: typeof NotFoundIndexRouteImport + parentRoute: typeof NotFoundRouteRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/redirect/': { id: '/redirect/' path: '/redirect' fullPath: '/redirect' - preLoaderRoute: typeof RedirectIndexImport + preLoaderRoute: typeof RedirectIndexRouteImport parentRoute: typeof rootRoute } '/users/': { id: '/users/' path: '/' fullPath: '/users/' - preLoaderRoute: typeof UsersIndexImport - parentRoute: typeof UsersImport + preLoaderRoute: typeof UsersIndexRouteImport + parentRoute: typeof UsersRouteImport } '/_layout/_layout-2/layout-a': { id: '/_layout/_layout-2/layout-a' path: '/layout-a' fullPath: '/layout-a' - preLoaderRoute: typeof LayoutLayout2LayoutAImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutARouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/_layout/_layout-2/layout-b': { id: '/_layout/_layout-2/layout-b' path: '/layout-b' fullPath: '/layout-b' - preLoaderRoute: typeof LayoutLayout2LayoutBImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutBRouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/posts_/$postId/deep': { id: '/posts_/$postId/deep' path: '/posts/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport + preLoaderRoute: typeof PostsPostIdDeepRouteImport parentRoute: typeof rootRoute } '/redirect/$target/via-beforeLoad': { id: '/redirect/$target/via-beforeLoad' path: '/via-beforeLoad' fullPath: '/redirect/$target/via-beforeLoad' - preLoaderRoute: typeof RedirectTargetViaBeforeLoadImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetViaBeforeLoadRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/via-loader': { id: '/redirect/$target/via-loader' path: '/via-loader' fullPath: '/redirect/$target/via-loader' - preLoaderRoute: typeof RedirectTargetViaLoaderImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetViaLoaderRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/': { id: '/redirect/$target/' path: '/' fullPath: '/redirect/$target/' - preLoaderRoute: typeof RedirectTargetIndexImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetIndexRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/serverFn/via-beforeLoad': { id: '/redirect/$target/serverFn/via-beforeLoad' path: '/serverFn/via-beforeLoad' fullPath: '/redirect/$target/serverFn/via-beforeLoad' - preLoaderRoute: typeof RedirectTargetServerFnViaBeforeLoadImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetServerFnViaBeforeLoadRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/serverFn/via-loader': { id: '/redirect/$target/serverFn/via-loader' path: '/serverFn/via-loader' fullPath: '/redirect/$target/serverFn/via-loader' - preLoaderRoute: typeof RedirectTargetServerFnViaLoaderImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetServerFnViaLoaderRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/serverFn/via-useServerFn': { id: '/redirect/$target/serverFn/via-useServerFn' path: '/serverFn/via-useServerFn' fullPath: '/redirect/$target/serverFn/via-useServerFn' - preLoaderRoute: typeof RedirectTargetServerFnViaUseServerFnImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetServerFnViaUseServerFnRouteImport + parentRoute: typeof RedirectTargetRouteImport } '/redirect/$target/serverFn/': { id: '/redirect/$target/serverFn/' path: '/serverFn' fullPath: '/redirect/$target/serverFn' - preLoaderRoute: typeof RedirectTargetServerFnIndexImport - parentRoute: typeof RedirectTargetImport + preLoaderRoute: typeof RedirectTargetServerFnIndexRouteImport + parentRoute: typeof RedirectTargetRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/not-found/route' { + const createFileRoute: CreateFileRoute< + '/not-found', + FileRoutesByPath['/not-found']['parentRoute'], + FileRoutesByPath['/not-found']['id'], + FileRoutesByPath['/not-found']['path'], + FileRoutesByPath['/not-found']['fullPath'] + > +} +declare module './routes/_layout' { + const createFileRoute: CreateFileRoute< + '/_layout', + FileRoutesByPath['/_layout']['parentRoute'], + FileRoutesByPath['/_layout']['id'], + FileRoutesByPath['/_layout']['path'], + FileRoutesByPath['/_layout']['fullPath'] + > +} +declare module './routes/deferred' { + const createFileRoute: CreateFileRoute< + '/deferred', + FileRoutesByPath['/deferred']['parentRoute'], + FileRoutesByPath['/deferred']['id'], + FileRoutesByPath['/deferred']['path'], + FileRoutesByPath['/deferred']['fullPath'] + > +} +declare module './routes/links' { + const createFileRoute: CreateFileRoute< + '/links', + FileRoutesByPath['/links']['parentRoute'], + FileRoutesByPath['/links']['id'], + FileRoutesByPath['/links']['path'], + FileRoutesByPath['/links']['fullPath'] + > +} +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/scripts' { + const createFileRoute: CreateFileRoute< + '/scripts', + FileRoutesByPath['/scripts']['parentRoute'], + FileRoutesByPath['/scripts']['id'], + FileRoutesByPath['/scripts']['path'], + FileRoutesByPath['/scripts']['fullPath'] + > +} +declare module './routes/search-params' { + const createFileRoute: CreateFileRoute< + '/search-params', + FileRoutesByPath['/search-params']['parentRoute'], + FileRoutesByPath['/search-params']['id'], + FileRoutesByPath['/search-params']['path'], + FileRoutesByPath['/search-params']['fullPath'] + > +} +declare module './routes/stream' { + const createFileRoute: CreateFileRoute< + '/stream', + FileRoutesByPath['/stream']['parentRoute'], + FileRoutesByPath['/stream']['id'], + FileRoutesByPath['/stream']['path'], + FileRoutesByPath['/stream']['fullPath'] + > +} +declare module './routes/users' { + const createFileRoute: CreateFileRoute< + '/users', + FileRoutesByPath['/users']['parentRoute'], + FileRoutesByPath['/users']['id'], + FileRoutesByPath['/users']['path'], + FileRoutesByPath['/users']['fullPath'] + > +} +declare module './routes/_layout/_layout-2' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2', + FileRoutesByPath['/_layout/_layout-2']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2']['id'], + FileRoutesByPath['/_layout/_layout-2']['path'], + FileRoutesByPath['/_layout/_layout-2']['fullPath'] + > +} +declare module './routes/not-found/via-beforeLoad' { + const createFileRoute: CreateFileRoute< + '/not-found/via-beforeLoad', + FileRoutesByPath['/not-found/via-beforeLoad']['parentRoute'], + FileRoutesByPath['/not-found/via-beforeLoad']['id'], + FileRoutesByPath['/not-found/via-beforeLoad']['path'], + FileRoutesByPath['/not-found/via-beforeLoad']['fullPath'] + > +} +declare module './routes/not-found/via-loader' { + const createFileRoute: CreateFileRoute< + '/not-found/via-loader', + FileRoutesByPath['/not-found/via-loader']['parentRoute'], + FileRoutesByPath['/not-found/via-loader']['id'], + FileRoutesByPath['/not-found/via-loader']['path'], + FileRoutesByPath['/not-found/via-loader']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/redirect/$target' { + const createFileRoute: CreateFileRoute< + '/redirect/$target', + FileRoutesByPath['/redirect/$target']['parentRoute'], + FileRoutesByPath['/redirect/$target']['id'], + FileRoutesByPath['/redirect/$target']['path'], + FileRoutesByPath['/redirect/$target']['fullPath'] + > +} +declare module './routes/users.$userId' { + const createFileRoute: CreateFileRoute< + '/users/$userId', + FileRoutesByPath['/users/$userId']['parentRoute'], + FileRoutesByPath['/users/$userId']['id'], + FileRoutesByPath['/users/$userId']['path'], + FileRoutesByPath['/users/$userId']['fullPath'] + > +} +declare module './routes/not-found/index' { + const createFileRoute: CreateFileRoute< + '/not-found/', + FileRoutesByPath['/not-found/']['parentRoute'], + FileRoutesByPath['/not-found/']['id'], + FileRoutesByPath['/not-found/']['path'], + FileRoutesByPath['/not-found/']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/redirect/index' { + const createFileRoute: CreateFileRoute< + '/redirect/', + FileRoutesByPath['/redirect/']['parentRoute'], + FileRoutesByPath['/redirect/']['id'], + FileRoutesByPath['/redirect/']['path'], + FileRoutesByPath['/redirect/']['fullPath'] + > +} +declare module './routes/users.index' { + const createFileRoute: CreateFileRoute< + '/users/', + FileRoutesByPath['/users/']['parentRoute'], + FileRoutesByPath['/users/']['id'], + FileRoutesByPath['/users/']['path'], + FileRoutesByPath['/users/']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-a' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-a', + FileRoutesByPath['/_layout/_layout-2/layout-a']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-b' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-b', + FileRoutesByPath['/_layout/_layout-2/layout-b']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['fullPath'] + > +} +declare module './routes/posts_.$postId.deep' { + const createFileRoute: CreateFileRoute< + '/posts_/$postId/deep', + FileRoutesByPath['/posts_/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > +} +declare module './routes/redirect/$target/via-beforeLoad' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/via-beforeLoad', + FileRoutesByPath['/redirect/$target/via-beforeLoad']['parentRoute'], + FileRoutesByPath['/redirect/$target/via-beforeLoad']['id'], + FileRoutesByPath['/redirect/$target/via-beforeLoad']['path'], + FileRoutesByPath['/redirect/$target/via-beforeLoad']['fullPath'] + > +} +declare module './routes/redirect/$target/via-loader' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/via-loader', + FileRoutesByPath['/redirect/$target/via-loader']['parentRoute'], + FileRoutesByPath['/redirect/$target/via-loader']['id'], + FileRoutesByPath['/redirect/$target/via-loader']['path'], + FileRoutesByPath['/redirect/$target/via-loader']['fullPath'] + > +} +declare module './routes/redirect/$target/index' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/', + FileRoutesByPath['/redirect/$target/']['parentRoute'], + FileRoutesByPath['/redirect/$target/']['id'], + FileRoutesByPath['/redirect/$target/']['path'], + FileRoutesByPath['/redirect/$target/']['fullPath'] + > +} +declare module './routes/redirect/$target/serverFn/via-beforeLoad' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/serverFn/via-beforeLoad', + FileRoutesByPath['/redirect/$target/serverFn/via-beforeLoad']['parentRoute'], + FileRoutesByPath['/redirect/$target/serverFn/via-beforeLoad']['id'], + FileRoutesByPath['/redirect/$target/serverFn/via-beforeLoad']['path'], + FileRoutesByPath['/redirect/$target/serverFn/via-beforeLoad']['fullPath'] + > +} +declare module './routes/redirect/$target/serverFn/via-loader' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/serverFn/via-loader', + FileRoutesByPath['/redirect/$target/serverFn/via-loader']['parentRoute'], + FileRoutesByPath['/redirect/$target/serverFn/via-loader']['id'], + FileRoutesByPath['/redirect/$target/serverFn/via-loader']['path'], + FileRoutesByPath['/redirect/$target/serverFn/via-loader']['fullPath'] + > +} +declare module './routes/redirect/$target/serverFn/via-useServerFn' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/serverFn/via-useServerFn', + FileRoutesByPath['/redirect/$target/serverFn/via-useServerFn']['parentRoute'], + FileRoutesByPath['/redirect/$target/serverFn/via-useServerFn']['id'], + FileRoutesByPath['/redirect/$target/serverFn/via-useServerFn']['path'], + FileRoutesByPath['/redirect/$target/serverFn/via-useServerFn']['fullPath'] + > +} +declare module './routes/redirect/$target/serverFn/index' { + const createFileRoute: CreateFileRoute< + '/redirect/$target/serverFn/', + FileRoutesByPath['/redirect/$target/serverFn/']['parentRoute'], + FileRoutesByPath['/redirect/$target/serverFn/']['id'], + FileRoutesByPath['/redirect/$target/serverFn/']['path'], + FileRoutesByPath['/redirect/$target/serverFn/']['fullPath'] + > +} + // Create and export the route tree interface NotFoundRouteRouteChildren { diff --git a/e2e/solid-start/basic/src/routes/__root.tsx b/e2e/solid-start/basic/src/routes/__root.tsx index 5ef4d4653b..89c60f9113 100644 --- a/e2e/solid-start/basic/src/routes/__root.tsx +++ b/e2e/solid-start/basic/src/routes/__root.tsx @@ -1,9 +1,9 @@ import { Link, Outlet, createRootRoute } from '@tanstack/solid-router' +import { TanStackRouterDevtoolsInProd } from '@tanstack/solid-router-devtools' import { NotFound } from '~/components/NotFound' import appCss from '~/styles/app.css?url' import { seo } from '~/utils/seo' -import { TanStackRouterDevtoolsInProd } from '@tanstack/solid-router-devtools' export const Route = createRootRoute({ head: () => ({ diff --git a/e2e/solid-start/basic/src/routes/_layout.tsx b/e2e/solid-start/basic/src/routes/_layout.tsx index d43b4ef5f5..c549175638 100644 --- a/e2e/solid-start/basic/src/routes/_layout.tsx +++ b/e2e/solid-start/basic/src/routes/_layout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/_layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/solid-start/basic/src/routes/_layout/_layout-2.tsx b/e2e/solid-start/basic/src/routes/_layout/_layout-2.tsx index 7a5a3623a0..efeca5ce86 100644 --- a/e2e/solid-start/basic/src/routes/_layout/_layout-2.tsx +++ b/e2e/solid-start/basic/src/routes/_layout/_layout-2.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/_layout/_layout-2')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/solid-start/basic/src/routes/_layout/_layout-2/layout-a.tsx b/e2e/solid-start/basic/src/routes/_layout/_layout-2/layout-a.tsx index b69951b246..a190b24202 100644 --- a/e2e/solid-start/basic/src/routes/_layout/_layout-2/layout-a.tsx +++ b/e2e/solid-start/basic/src/routes/_layout/_layout-2/layout-a.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ +export const Route = createFileRoute({ component: LayoutAComponent, }) diff --git a/e2e/solid-start/basic/src/routes/_layout/_layout-2/layout-b.tsx b/e2e/solid-start/basic/src/routes/_layout/_layout-2/layout-b.tsx index 30dbcce90f..505f8f6fbf 100644 --- a/e2e/solid-start/basic/src/routes/_layout/_layout-2/layout-b.tsx +++ b/e2e/solid-start/basic/src/routes/_layout/_layout-2/layout-b.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ +export const Route = createFileRoute({ component: LayoutBComponent, }) diff --git a/e2e/solid-start/basic/src/routes/api.users.ts b/e2e/solid-start/basic/src/routes/api.users.ts deleted file mode 100644 index 45ac83b2f0..0000000000 --- a/e2e/solid-start/basic/src/routes/api.users.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { json } from '@tanstack/solid-start' -import { createAPIFileRoute } from '@tanstack/solid-start/api' -import axios from 'redaxios' - -import type { User } from '~/utils/users' - -export const APIRoute = createAPIFileRoute('/api/users')({ - GET: async ({ request }) => { - console.info('Fetching users... @', request.url) - const res = await axios.get>( - 'https://jsonplaceholder.typicode.com/users', - ) - - const list = res.data.slice(0, 10) - - return json(list.map((u) => ({ id: u.id, name: u.name, email: u.email }))) - }, -}) diff --git a/e2e/solid-start/basic/src/routes/api/users.$id.ts b/e2e/solid-start/basic/src/routes/api/users.$id.ts deleted file mode 100644 index 7ee1fccbb4..0000000000 --- a/e2e/solid-start/basic/src/routes/api/users.$id.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { json } from '@tanstack/solid-start' -import { createAPIFileRoute } from '@tanstack/solid-start/api' -import axios from 'redaxios' - -import type { User } from '~/utils/users' - -export const APIRoute = createAPIFileRoute('/api/users/$id')({ - GET: async ({ request, params }) => { - console.info(`Fetching users by id=${params.id}... @`, request.url) - try { - const res = await axios.get( - 'https://jsonplaceholder.typicode.com/users/' + params.id, - ) - - return json({ - id: res.data.id, - name: res.data.name, - email: res.data.email, - }) - } catch (e) { - console.error(e) - return json({ error: 'User not found' }, { status: 404 }) - } - }, -}) diff --git a/e2e/solid-start/basic/src/routes/api/users.$userId.ts b/e2e/solid-start/basic/src/routes/api/users.$userId.ts new file mode 100644 index 0000000000..69d966d982 --- /dev/null +++ b/e2e/solid-start/basic/src/routes/api/users.$userId.ts @@ -0,0 +1,27 @@ +import { json } from '@tanstack/solid-start' +import type { User } from '~/utils/users' + +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ params, request }) => { + console.info(`Fetching users by id=${params.userId}... @`, request.url) + try { + const res = await fetch( + 'https://jsonplaceholder.typicode.com/users/' + params.userId, + ) + if (!res.ok) { + throw new Error('Failed to fetch user') + } + + const user = (await res.json()) as User + + return json({ + id: user.id, + name: user.name, + email: user.email, + }) + } catch (e) { + console.error(e) + return json({ error: 'User not found' }, { status: 404 }) + } + }, +}) diff --git a/e2e/solid-start/basic/src/routes/api/users.ts b/e2e/solid-start/basic/src/routes/api/users.ts new file mode 100644 index 0000000000..c0a6a1a6a2 --- /dev/null +++ b/e2e/solid-start/basic/src/routes/api/users.ts @@ -0,0 +1,58 @@ +import { createMiddleware, json } from '@tanstack/solid-start' +import type { User } from '~/utils/users' + +const userLoggerMiddleware = createMiddleware({ type: 'request' }).server( + async ({ next, request }) => { + console.info('In: /users') + const result = await next() + result.response.headers.set('x-users', 'true') + console.info('Out: /users') + return result + }, +) + +const testParentMiddleware = createMiddleware({ type: 'request' }).server( + async ({ next, request }) => { + console.info('In: testParentMiddleware') + const result = await next() + result.response.headers.set('x-test-parent', 'true') + console.info('Out: testParentMiddleware') + return result + }, +) + +const testMiddleware = createMiddleware({ type: 'request' }) + .middleware([testParentMiddleware]) + .server(async ({ next, request }) => { + console.info('In: testMiddleware') + const result = await next() + result.response.headers.set('x-test', 'true') + + // if (Math.random() > 0.5) { + // throw new Response(null, { + // status: 302, + // headers: { Location: 'https://www.google.com' }, + // }) + // } + + console.info('Out: testMiddleware') + return result + }) + +export const ServerRoute = createServerFileRoute() + .middleware([testMiddleware, userLoggerMiddleware, testParentMiddleware]) + .methods({ + GET: async ({ request }) => { + console.info('Fetching users... @', request.url) + const res = await fetch('https://jsonplaceholder.typicode.com/users') + if (!res.ok) { + throw new Error('Failed to fetch users') + } + + const data = (await res.json()) as Array + + const list = data.slice(0, 10) + + return json(list.map((u) => ({ id: u.id, name: u.name, email: u.email }))) + }, + }) diff --git a/e2e/solid-start/basic/src/routes/deferred.tsx b/e2e/solid-start/basic/src/routes/deferred.tsx index 2a53643453..5bb96ca571 100644 --- a/e2e/solid-start/basic/src/routes/deferred.tsx +++ b/e2e/solid-start/basic/src/routes/deferred.tsx @@ -1,4 +1,4 @@ -import { Await, createFileRoute } from '@tanstack/solid-router' +import { Await } from '@tanstack/solid-router' import { createServerFn } from '@tanstack/solid-start' import { Suspense, createSignal } from 'solid-js' @@ -15,7 +15,7 @@ const slowServerFn = createServerFn({ method: 'GET' }) return { name: data.name, randomNumber: Math.floor(Math.random() * 100) } }) -export const Route = createFileRoute('/deferred')({ +export const Route = createFileRoute({ loader: async () => { return { deferredStuff: new Promise((r) => diff --git a/e2e/solid-start/basic/src/routes/index.tsx b/e2e/solid-start/basic/src/routes/index.tsx index 6b23caf87b..4024800b8e 100644 --- a/e2e/solid-start/basic/src/routes/index.tsx +++ b/e2e/solid-start/basic/src/routes/index.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' import { CustomMessage } from '~/components/CustomMessage' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/solid-start/basic/src/routes/links.tsx b/e2e/solid-start/basic/src/routes/links.tsx index d6ce6a449b..05fd8f0494 100644 --- a/e2e/solid-start/basic/src/routes/links.tsx +++ b/e2e/solid-start/basic/src/routes/links.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' -export const Route = createFileRoute('/links')({ +export const Route = createFileRoute({ component: () => { const navigate = Route.useNavigate() return ( diff --git a/e2e/solid-start/basic/src/routes/not-found/index.tsx b/e2e/solid-start/basic/src/routes/not-found/index.tsx index 34c8ef6146..79e7b5ae56 100644 --- a/e2e/solid-start/basic/src/routes/not-found/index.tsx +++ b/e2e/solid-start/basic/src/routes/not-found/index.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' -export const Route = createFileRoute('/not-found/')({ +export const Route = createFileRoute({ component: () => { const preload = Route.useSearch({ select: (s) => s.preload }) return ( diff --git a/e2e/solid-start/basic/src/routes/not-found/route.tsx b/e2e/solid-start/basic/src/routes/not-found/route.tsx index 84f5ef81a5..b8343167f5 100644 --- a/e2e/solid-start/basic/src/routes/not-found/route.tsx +++ b/e2e/solid-start/basic/src/routes/not-found/route.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' import z from 'zod' -export const Route = createFileRoute('/not-found')({ +export const Route = createFileRoute({ validateSearch: z.object({ preload: z.literal(false).optional(), }), diff --git a/e2e/solid-start/basic/src/routes/not-found/via-beforeLoad.tsx b/e2e/solid-start/basic/src/routes/not-found/via-beforeLoad.tsx index 5badde63bd..5277edd901 100644 --- a/e2e/solid-start/basic/src/routes/not-found/via-beforeLoad.tsx +++ b/e2e/solid-start/basic/src/routes/not-found/via-beforeLoad.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, notFound } from '@tanstack/solid-router' +import { notFound } from '@tanstack/solid-router' -export const Route = createFileRoute('/not-found/via-beforeLoad')({ +export const Route = createFileRoute({ beforeLoad: () => { throw notFound() }, diff --git a/e2e/solid-start/basic/src/routes/not-found/via-loader.tsx b/e2e/solid-start/basic/src/routes/not-found/via-loader.tsx index 20956cc43d..bc0fad6c58 100644 --- a/e2e/solid-start/basic/src/routes/not-found/via-loader.tsx +++ b/e2e/solid-start/basic/src/routes/not-found/via-loader.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, notFound } from '@tanstack/solid-router' +import { notFound } from '@tanstack/solid-router' -export const Route = createFileRoute('/not-found/via-loader')({ +export const Route = createFileRoute({ loader: () => { throw notFound() }, diff --git a/e2e/solid-start/basic/src/routes/posts.$postId.tsx b/e2e/solid-start/basic/src/routes/posts.$postId.tsx index c6b2fcf5f9..cefc75cdf1 100644 --- a/e2e/solid-start/basic/src/routes/posts.$postId.tsx +++ b/e2e/solid-start/basic/src/routes/posts.$postId.tsx @@ -1,11 +1,11 @@ -import { ErrorComponent, Link, createFileRoute } from '@tanstack/solid-router' +import { ErrorComponent, Link } from '@tanstack/solid-router' import type { ErrorComponentProps } from '@tanstack/solid-router' import { fetchPost } from '~/utils/posts' import { NotFound } from '~/components/NotFound' import { PostErrorComponent } from '~/components/PostErrorComponent' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, diff --git a/e2e/solid-start/basic/src/routes/posts.index.tsx b/e2e/solid-start/basic/src/routes/posts.index.tsx index c7d8cfe19c..07e41d1b0b 100644 --- a/e2e/solid-start/basic/src/routes/posts.index.tsx +++ b/e2e/solid-start/basic/src/routes/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/e2e/solid-start/basic/src/routes/posts.tsx b/e2e/solid-start/basic/src/routes/posts.tsx index 0e94cd4d2c..c053d0de56 100644 --- a/e2e/solid-start/basic/src/routes/posts.tsx +++ b/e2e/solid-start/basic/src/routes/posts.tsx @@ -1,9 +1,9 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import { For } from 'solid-js' import { fetchPosts } from '~/utils/posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ head: () => ({ meta: [ { diff --git a/e2e/solid-start/basic/src/routes/posts_.$postId.deep.tsx b/e2e/solid-start/basic/src/routes/posts_.$postId.deep.tsx index f8d4627914..4133a9ade9 100644 --- a/e2e/solid-start/basic/src/routes/posts_.$postId.deep.tsx +++ b/e2e/solid-start/basic/src/routes/posts_.$postId.deep.tsx @@ -1,9 +1,9 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' import { PostErrorComponent } from '~/components/PostErrorComponent' import { fetchPost } from '~/utils/posts' -export const Route = createFileRoute('/posts_/$postId/deep')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostDeepComponent, diff --git a/e2e/solid-start/basic/src/routes/redirect/$target.tsx b/e2e/solid-start/basic/src/routes/redirect/$target.tsx index 525dd9da25..c4c78070d3 100644 --- a/e2e/solid-start/basic/src/routes/redirect/$target.tsx +++ b/e2e/solid-start/basic/src/routes/redirect/$target.tsx @@ -1,7 +1,7 @@ -import { createFileRoute, retainSearchParams } from '@tanstack/solid-router' +import { retainSearchParams } from '@tanstack/solid-router' import z from 'zod' -export const Route = createFileRoute('/redirect/$target')({ +export const Route = createFileRoute({ params: { parse: (p) => z diff --git a/e2e/solid-start/basic/src/routes/redirect/$target/index.tsx b/e2e/solid-start/basic/src/routes/redirect/$target/index.tsx index 916afd450b..0dde05d9e1 100644 --- a/e2e/solid-start/basic/src/routes/redirect/$target/index.tsx +++ b/e2e/solid-start/basic/src/routes/redirect/$target/index.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' -export const Route = createFileRoute('/redirect/$target/')({ +export const Route = createFileRoute({ component: () => { const preload = Route.useSearch({ select: (s) => s.preload }) return ( diff --git a/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/index.tsx b/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/index.tsx index d404672372..6be32366eb 100644 --- a/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/index.tsx +++ b/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/index.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' -export const Route = createFileRoute('/redirect/$target/serverFn/')({ +export const Route = createFileRoute({ component: () => (

diff --git a/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/via-beforeLoad.tsx b/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/via-beforeLoad.tsx index 81f9dd2d36..3aad8bffa4 100644 --- a/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/via-beforeLoad.tsx +++ b/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/via-beforeLoad.tsx @@ -1,9 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' import { throwRedirect } from '~/components/throwRedirect' -export const Route = createFileRoute( - '/redirect/$target/serverFn/via-beforeLoad', -)({ +export const Route = createFileRoute({ beforeLoad: ({ params: { target }, search: { reloadDocument, externalHost }, diff --git a/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/via-loader.tsx b/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/via-loader.tsx index 0b6ac91c15..3087fa2e15 100644 --- a/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/via-loader.tsx +++ b/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/via-loader.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' import { throwRedirect } from '~/components/throwRedirect' -export const Route = createFileRoute('/redirect/$target/serverFn/via-loader')({ +export const Route = createFileRoute({ loaderDeps: ({ search: { reloadDocument, externalHost } }) => ({ reloadDocument, externalHost, diff --git a/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/via-useServerFn.tsx b/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/via-useServerFn.tsx index 5b0c246474..969f6c02c2 100644 --- a/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/via-useServerFn.tsx +++ b/e2e/solid-start/basic/src/routes/redirect/$target/serverFn/via-useServerFn.tsx @@ -1,9 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' import { RedirectOnClick } from '~/components/RedirectOnClick' -export const Route = createFileRoute( - '/redirect/$target/serverFn/via-useServerFn', -)({ +export const Route = createFileRoute({ component: () => { const params = Route.useParams() const search = Route.useSearch() diff --git a/e2e/solid-start/basic/src/routes/redirect/$target/via-beforeLoad.tsx b/e2e/solid-start/basic/src/routes/redirect/$target/via-beforeLoad.tsx index c88cc07986..bac534bfc5 100644 --- a/e2e/solid-start/basic/src/routes/redirect/$target/via-beforeLoad.tsx +++ b/e2e/solid-start/basic/src/routes/redirect/$target/via-beforeLoad.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, redirect } from '@tanstack/solid-router' +import { redirect } from '@tanstack/solid-router' -export const Route = createFileRoute('/redirect/$target/via-beforeLoad')({ +export const Route = createFileRoute({ beforeLoad: ({ params: { target }, search: { reloadDocument, externalHost }, diff --git a/e2e/solid-start/basic/src/routes/redirect/$target/via-loader.tsx b/e2e/solid-start/basic/src/routes/redirect/$target/via-loader.tsx index 5c059717c5..686c0d8971 100644 --- a/e2e/solid-start/basic/src/routes/redirect/$target/via-loader.tsx +++ b/e2e/solid-start/basic/src/routes/redirect/$target/via-loader.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, redirect } from '@tanstack/solid-router' +import { redirect } from '@tanstack/solid-router' -export const Route = createFileRoute('/redirect/$target/via-loader')({ +export const Route = createFileRoute({ loaderDeps: ({ search: { reloadDocument, externalHost } }) => ({ reloadDocument, externalHost, diff --git a/e2e/solid-start/basic/src/routes/redirect/index.tsx b/e2e/solid-start/basic/src/routes/redirect/index.tsx index 043f305e57..26aefc154c 100644 --- a/e2e/solid-start/basic/src/routes/redirect/index.tsx +++ b/e2e/solid-start/basic/src/routes/redirect/index.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' -export const Route = createFileRoute('/redirect/')({ +export const Route = createFileRoute({ component: () => (
({ scripts: [ { diff --git a/e2e/solid-start/basic/src/routes/search-params.tsx b/e2e/solid-start/basic/src/routes/search-params.tsx index ec941d9a4c..fbacb055ac 100644 --- a/e2e/solid-start/basic/src/routes/search-params.tsx +++ b/e2e/solid-start/basic/src/routes/search-params.tsx @@ -1,7 +1,7 @@ -import { createFileRoute, redirect } from '@tanstack/solid-router' +import { redirect } from '@tanstack/solid-router' import { z } from 'zod' -export const Route = createFileRoute('/search-params')({ +export const Route = createFileRoute({ component: () => { const search = Route.useSearch() return ( diff --git a/e2e/solid-start/basic/src/routes/stream.tsx b/e2e/solid-start/basic/src/routes/stream.tsx index d1d21e344a..d0fb3f82cf 100644 --- a/e2e/solid-start/basic/src/routes/stream.tsx +++ b/e2e/solid-start/basic/src/routes/stream.tsx @@ -1,7 +1,7 @@ -import { Await, createFileRoute } from '@tanstack/solid-router' +import { Await } from '@tanstack/solid-router' import { createEffect, createSignal } from 'solid-js' -export const Route = createFileRoute('/stream')({ +export const Route = createFileRoute({ component: Home, loader() { return { diff --git a/e2e/solid-start/basic/src/routes/users.$userId.tsx b/e2e/solid-start/basic/src/routes/users.$userId.tsx index 6f95652e53..276249aef6 100644 --- a/e2e/solid-start/basic/src/routes/users.$userId.tsx +++ b/e2e/solid-start/basic/src/routes/users.$userId.tsx @@ -1,16 +1,13 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/solid-router' import axios from 'redaxios' -import type { ErrorComponentProps } from '@tanstack/solid-router' import type { User } from '~/utils/users' -import { DEPLOY_URL } from '~/utils/users' import { NotFound } from '~/components/NotFound' import { UserErrorComponent } from '~/components/UserErrorComponent' -export const Route = createFileRoute('/users/$userId')({ +export const Route = createFileRoute({ loader: async ({ params: { userId } }) => { return await axios - .get(DEPLOY_URL + '/api/users/' + userId) + .get('/api/users/' + userId) .then((r) => r.data) .catch(() => { throw new Error('Failed to fetch user') diff --git a/e2e/solid-start/basic/src/routes/users.index.tsx b/e2e/solid-start/basic/src/routes/users.index.tsx index bbc96801a9..662e8b6c68 100644 --- a/e2e/solid-start/basic/src/routes/users.index.tsx +++ b/e2e/solid-start/basic/src/routes/users.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/users/')({ +export const Route = createFileRoute({ component: UsersIndexComponent, }) diff --git a/e2e/solid-start/basic/src/routes/users.tsx b/e2e/solid-start/basic/src/routes/users.tsx index 3c26badbb4..36b7573e64 100644 --- a/e2e/solid-start/basic/src/routes/users.tsx +++ b/e2e/solid-start/basic/src/routes/users.tsx @@ -1,13 +1,12 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import axios from 'redaxios' import type { User } from '~/utils/users' -import { DEPLOY_URL } from '~/utils/users' -export const Route = createFileRoute('/users')({ +export const Route = createFileRoute({ loader: async () => { return await axios - .get>(DEPLOY_URL + '/api/users') + .get>('/api/users') .then((r) => r.data) .catch(() => { throw new Error('Failed to fetch users') diff --git a/e2e/solid-start/basic-tsr-config/src/app/ssr.tsx b/e2e/solid-start/basic/src/server.ts similarity index 53% rename from e2e/solid-start/basic-tsr-config/src/app/ssr.tsx rename to e2e/solid-start/basic/src/server.ts index ebd14c8120..f9fbb3a2d5 100644 --- a/e2e/solid-start/basic-tsr-config/src/app/ssr.tsx +++ b/e2e/solid-start/basic/src/server.ts @@ -1,13 +1,13 @@ -/// +// DO NOT DELETE THIS FILE!!! +// This file is a good smoke test to make sure the custom server entry is working import { createStartHandler, defaultStreamHandler, } from '@tanstack/solid-start/server' -import { getRouterManifest } from '@tanstack/solid-start/router-manifest' - import { createRouter } from './router' +console.log("[server-entry]: using custom server entry in 'src/server.ts'") + export default createStartHandler({ createRouter, - getRouterManifest, })(defaultStreamHandler) diff --git a/e2e/solid-start/basic/src/ssr.tsx b/e2e/solid-start/basic/src/ssr.tsx deleted file mode 100644 index 6d10bea05f..0000000000 --- a/e2e/solid-start/basic/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/solid-start/server' -import { getRouterManifest } from '@tanstack/solid-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/e2e/solid-start/basic/src/tanstack-start.d.ts b/e2e/solid-start/basic/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/e2e/solid-start/basic/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/solid-start/basic/src/utils/users.tsx b/e2e/solid-start/basic/src/utils/users.tsx index 79b45867d5..46be4b1580 100644 --- a/e2e/solid-start/basic/src/utils/users.tsx +++ b/e2e/solid-start/basic/src/utils/users.tsx @@ -4,7 +4,6 @@ export type User = { email: string } -const PORT = - import.meta.env.VITE_SERVER_PORT || process.env.VITE_SERVER_PORT || 3000 +const PORT = process.env.VITE_SERVER_PORT || 3000 export const DEPLOY_URL = `http://localhost:${PORT}` diff --git a/e2e/solid-start/basic/src/vite-env.d.ts b/e2e/solid-start/basic/src/vite-env.d.ts new file mode 100644 index 0000000000..0b2af560d6 --- /dev/null +++ b/e2e/solid-start/basic/src/vite-env.d.ts @@ -0,0 +1,4 @@ +declare module '*?url' { + const url: string + export default url +} diff --git a/e2e/solid-start/basic/tests/redirect.spec.ts b/e2e/solid-start/basic/tests/redirect.spec.ts index 4f4cb73b1c..1664d16a50 100644 --- a/e2e/solid-start/basic/tests/redirect.spec.ts +++ b/e2e/solid-start/basic/tests/redirect.spec.ts @@ -1,10 +1,10 @@ +import queryString from 'node:querystring' import { expect } from '@playwright/test' import combinateImport from 'combinate' import { derivePort, localDummyServer } from '@tanstack/router-e2e-utils' import packageJson from '../package.json' with { type: 'json' } import { test } from './fixture' -import { Server } from 'node:http' -import queryString from 'node:querystring' +import type { Server } from 'node:http' // somehow playwright does not correctly import default exports const combinate = (combinateImport as any).default as typeof combinateImport @@ -44,7 +44,9 @@ test.describe('redirects', () => { const requestPromise = new Promise((resolve) => { page.on('request', (request) => { - if (request.url().startsWith(`http://localhost:${PORT}/_server/`)) { + if ( + request.url().startsWith(`http://localhost:${PORT}/_serverFn/`) + ) { requestHappened = true resolve() } @@ -104,7 +106,7 @@ test.describe('redirects', () => { test(`external target: scenario: ${scenario}, thrower: ${thrower}`, async ({ page, }) => { - let q = queryString.stringify({ + const q = queryString.stringify({ externalHost: `http://localhost:${EXTERNAL_HOST_PORT}/`, }) @@ -138,7 +140,7 @@ test.describe('redirects', () => { page, }) => { let fullPageLoad = false - let q = queryString.stringify({ + const q = queryString.stringify({ externalHost: `http://localhost:${EXTERNAL_HOST_PORT}/`, reloadDocument, }) diff --git a/e2e/solid-start/basic/vite.config.ts b/e2e/solid-start/basic/vite.config.ts new file mode 100644 index 0000000000..3af67d62ad --- /dev/null +++ b/e2e/solid-start/basic/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart({}), + ], +}) diff --git a/e2e/solid-start/scroll-restoration/.gitignore b/e2e/solid-start/scroll-restoration/.gitignore index be342025da..a79d5cf129 100644 --- a/e2e/solid-start/scroll-restoration/.gitignore +++ b/e2e/solid-start/scroll-restoration/.gitignore @@ -7,13 +7,11 @@ yarn.lock .env .vercel .output -.vinxi /build/ /api/ /server/build /public/build -.vinxi # Sentry Config File .env.sentry-build-plugin /test-results/ diff --git a/e2e/solid-start/scroll-restoration/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/solid-start/scroll-restoration/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..2dc6bfc4bd --- /dev/null +++ b/e2e/solid-start/scroll-restoration/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/solid-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/solid-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/solid-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/solid-start/scroll-restoration/app.config.ts b/e2e/solid-start/scroll-restoration/app.config.ts deleted file mode 100644 index 2a06e3d3f0..0000000000 --- a/e2e/solid-start/scroll-restoration/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/solid-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/e2e/solid-start/scroll-restoration/package.json b/e2e/solid-start/scroll-restoration/package.json index 81fce6eaea..e72dbb657c 100644 --- a/e2e/solid-start/scroll-restoration/package.json +++ b/e2e/solid-start/scroll-restoration/package.json @@ -4,10 +4,10 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "node .output/server/index.mjs", "test:e2e": "playwright test --project=chromium" }, "dependencies": { @@ -15,22 +15,22 @@ "@tanstack/solid-router-devtools": "workspace:^", "@tanstack/solid-start": "workspace:^", "@tanstack/zod-adapter": "workspace:^", - "solid-js": "^1.9.5", "redaxios": "^0.5.1", + "solid-js": "^1.9.5", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", + "vite": "6.3.5", "zod": "^3.24.2" }, "devDependencies": { "@playwright/test": "^1.50.1", "@tanstack/router-e2e-utils": "workspace:^", "@types/node": "^22.10.2", - "vite-plugin-solid": "^2.11.6", "autoprefixer": "^10.4.20", "combinate": "^1.1.11", "postcss": "^8.5.1", "tailwindcss": "^3.4.17", "typescript": "^5.7.2", + "vite-plugin-solid": "^2.11.6", "vite-tsconfig-paths": "^5.1.4" } } diff --git a/e2e/solid-start/scroll-restoration/playwright.config.ts b/e2e/solid-start/scroll-restoration/playwright.config.ts index 95d043d48b..e834d88cf4 100644 --- a/e2e/solid-start/scroll-restoration/playwright.config.ts +++ b/e2e/solid-start/scroll-restoration/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ }, webServer: { - command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm start --port ${PORT}`, + command: `pnpm build && VITE_SERVER_PORT=${PORT} PORT=${PORT} pnpm start`, url: baseURL, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/e2e/solid-start/scroll-restoration/src/api.ts b/e2e/solid-start/scroll-restoration/src/api.ts deleted file mode 100644 index ed511bcd26..0000000000 --- a/e2e/solid-start/scroll-restoration/src/api.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { - createStartAPIHandler, - defaultAPIFileRouteHandler, -} from '@tanstack/solid-start/api' - -export default createStartAPIHandler(defaultAPIFileRouteHandler) diff --git a/e2e/solid-start/scroll-restoration/src/client.tsx b/e2e/solid-start/scroll-restoration/src/client.tsx deleted file mode 100644 index ba0f02fac0..0000000000 --- a/e2e/solid-start/scroll-restoration/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrate } from 'solid-js/web' -import { StartClient } from '@tanstack/solid-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrate(() => , document.body) diff --git a/e2e/solid-start/scroll-restoration/src/routeTree.gen.ts b/e2e/solid-start/scroll-restoration/src/routeTree.gen.ts index d5cbca5b25..36562a9510 100644 --- a/e2e/solid-start/scroll-restoration/src/routeTree.gen.ts +++ b/e2e/solid-start/scroll-restoration/src/routeTree.gen.ts @@ -8,35 +8,37 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/solid-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' -import { Route as testsWithSearchImport } from './routes/(tests)/with-search' -import { Route as testsWithLoaderImport } from './routes/(tests)/with-loader' -import { Route as testsNormalPageImport } from './routes/(tests)/normal-page' +import { Route as IndexRouteImport } from './routes/index' +import { Route as testsWithSearchRouteImport } from './routes/(tests)/with-search' +import { Route as testsWithLoaderRouteImport } from './routes/(tests)/with-loader' +import { Route as testsNormalPageRouteImport } from './routes/(tests)/normal-page' // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const testsWithSearchRoute = testsWithSearchImport.update({ +const testsWithSearchRoute = testsWithSearchRouteImport.update({ id: '/(tests)/with-search', path: '/with-search', getParentRoute: () => rootRoute, } as any) -const testsWithLoaderRoute = testsWithLoaderImport.update({ +const testsWithLoaderRoute = testsWithLoaderRouteImport.update({ id: '/(tests)/with-loader', path: '/with-loader', getParentRoute: () => rootRoute, } as any) -const testsNormalPageRoute = testsNormalPageImport.update({ +const testsNormalPageRoute = testsNormalPageRouteImport.update({ id: '/(tests)/normal-page', path: '/normal-page', getParentRoute: () => rootRoute, @@ -50,33 +52,72 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/(tests)/normal-page': { id: '/(tests)/normal-page' path: '/normal-page' fullPath: '/normal-page' - preLoaderRoute: typeof testsNormalPageImport + preLoaderRoute: typeof testsNormalPageRouteImport parentRoute: typeof rootRoute } '/(tests)/with-loader': { id: '/(tests)/with-loader' path: '/with-loader' fullPath: '/with-loader' - preLoaderRoute: typeof testsWithLoaderImport + preLoaderRoute: typeof testsWithLoaderRouteImport parentRoute: typeof rootRoute } '/(tests)/with-search': { id: '/(tests)/with-search' path: '/with-search' fullPath: '/with-search' - preLoaderRoute: typeof testsWithSearchImport + preLoaderRoute: typeof testsWithSearchRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/(tests)/normal-page' { + const createFileRoute: CreateFileRoute< + '/(tests)/normal-page', + FileRoutesByPath['/(tests)/normal-page']['parentRoute'], + FileRoutesByPath['/(tests)/normal-page']['id'], + FileRoutesByPath['/(tests)/normal-page']['path'], + FileRoutesByPath['/(tests)/normal-page']['fullPath'] + > +} +declare module './routes/(tests)/with-loader' { + const createFileRoute: CreateFileRoute< + '/(tests)/with-loader', + FileRoutesByPath['/(tests)/with-loader']['parentRoute'], + FileRoutesByPath['/(tests)/with-loader']['id'], + FileRoutesByPath['/(tests)/with-loader']['path'], + FileRoutesByPath['/(tests)/with-loader']['fullPath'] + > +} +declare module './routes/(tests)/with-search' { + const createFileRoute: CreateFileRoute< + '/(tests)/with-search', + FileRoutesByPath['/(tests)/with-search']['parentRoute'], + FileRoutesByPath['/(tests)/with-search']['id'], + FileRoutesByPath['/(tests)/with-search']['path'], + FileRoutesByPath['/(tests)/with-search']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/e2e/solid-start/scroll-restoration/src/routes/(tests)/normal-page.tsx b/e2e/solid-start/scroll-restoration/src/routes/(tests)/normal-page.tsx index 76d32719ef..b58a556b4f 100644 --- a/e2e/solid-start/scroll-restoration/src/routes/(tests)/normal-page.tsx +++ b/e2e/solid-start/scroll-restoration/src/routes/(tests)/normal-page.tsx @@ -1,8 +1,8 @@ import * as Solid from 'solid-js' -import { createFileRoute } from '@tanstack/solid-router' + import { ScrollBlock } from '../-components/scroll-block' -export const Route = createFileRoute('/(tests)/normal-page')({ +export const Route = createFileRoute({ component: Component, }) diff --git a/e2e/solid-start/scroll-restoration/src/routes/(tests)/with-loader.tsx b/e2e/solid-start/scroll-restoration/src/routes/(tests)/with-loader.tsx index aae7611b51..212ea0457f 100644 --- a/e2e/solid-start/scroll-restoration/src/routes/(tests)/with-loader.tsx +++ b/e2e/solid-start/scroll-restoration/src/routes/(tests)/with-loader.tsx @@ -1,8 +1,7 @@ -import { createFileRoute } from '@tanstack/solid-router' +import { sleep } from 'src/utils/posts' import { ScrollBlock } from '../-components/scroll-block' -import { sleep } from '~/utils/posts' -export const Route = createFileRoute('/(tests)/with-loader')({ +export const Route = createFileRoute({ loader: async () => { await sleep(1000) return { foo: 'bar' } diff --git a/e2e/solid-start/scroll-restoration/src/routes/(tests)/with-search.tsx b/e2e/solid-start/scroll-restoration/src/routes/(tests)/with-search.tsx index 5d43b7f9bb..073dd2501c 100644 --- a/e2e/solid-start/scroll-restoration/src/routes/(tests)/with-search.tsx +++ b/e2e/solid-start/scroll-restoration/src/routes/(tests)/with-search.tsx @@ -1,9 +1,8 @@ -import { createFileRoute } from '@tanstack/solid-router' import { z } from 'zod' import { zodValidator } from '@tanstack/zod-adapter' import { ScrollBlock } from '../-components/scroll-block' -export const Route = createFileRoute('/(tests)/with-search')({ +export const Route = createFileRoute({ validateSearch: zodValidator(z.object({ where: z.string() })), component: Component, }) diff --git a/e2e/solid-start/scroll-restoration/src/routes/__root.tsx b/e2e/solid-start/scroll-restoration/src/routes/__root.tsx index 5907fa6ecd..4af70096a1 100644 --- a/e2e/solid-start/scroll-restoration/src/routes/__root.tsx +++ b/e2e/solid-start/scroll-restoration/src/routes/__root.tsx @@ -1,18 +1,14 @@ -import * as Solid from 'solid-js' import { Link, Outlet, createRootRoute, linkOptions, - HeadContent, - Scripts, } from '@tanstack/solid-router' -import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary' +import { Dynamic } from 'solid-js/web' +import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools' import { NotFound } from '~/components/NotFound' import appCss from '~/styles/app.css?url' import { seo } from '~/utils/seo' -import { Dynamic } from 'solid-js/web' -import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools' export const Route = createRootRoute({ head: () => ({ diff --git a/e2e/solid-start/scroll-restoration/src/routes/index.tsx b/e2e/solid-start/scroll-restoration/src/routes/index.tsx index e950ce86c9..15c0376e3d 100644 --- a/e2e/solid-start/scroll-restoration/src/routes/index.tsx +++ b/e2e/solid-start/scroll-restoration/src/routes/index.tsx @@ -1,7 +1,7 @@ import * as Solid from 'solid-js' -import { Link, createFileRoute, linkOptions } from '@tanstack/solid-router' +import { Link, linkOptions } from '@tanstack/solid-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: HomeComponent, }) diff --git a/e2e/solid-start/scroll-restoration/src/ssr.tsx b/e2e/solid-start/scroll-restoration/src/ssr.tsx deleted file mode 100644 index 6d10bea05f..0000000000 --- a/e2e/solid-start/scroll-restoration/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/solid-start/server' -import { getRouterManifest } from '@tanstack/solid-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/e2e/solid-start/scroll-restoration/src/tanstack-start.d.ts b/e2e/solid-start/scroll-restoration/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/e2e/solid-start/scroll-restoration/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/solid-start/scroll-restoration/src/utils/users.tsx b/e2e/solid-start/scroll-restoration/src/utils/users.tsx index 79b45867d5..46be4b1580 100644 --- a/e2e/solid-start/scroll-restoration/src/utils/users.tsx +++ b/e2e/solid-start/scroll-restoration/src/utils/users.tsx @@ -4,7 +4,6 @@ export type User = { email: string } -const PORT = - import.meta.env.VITE_SERVER_PORT || process.env.VITE_SERVER_PORT || 3000 +const PORT = process.env.VITE_SERVER_PORT || 3000 export const DEPLOY_URL = `http://localhost:${PORT}` diff --git a/e2e/solid-start/scroll-restoration/src/vite-env.d.ts b/e2e/solid-start/scroll-restoration/src/vite-env.d.ts new file mode 100644 index 0000000000..0b2af560d6 --- /dev/null +++ b/e2e/solid-start/scroll-restoration/src/vite-env.d.ts @@ -0,0 +1,4 @@ +declare module '*?url' { + const url: string + export default url +} diff --git a/e2e/solid-start/scroll-restoration/vite.config.ts b/e2e/solid-start/scroll-restoration/vite.config.ts new file mode 100644 index 0000000000..3af67d62ad --- /dev/null +++ b/e2e/solid-start/scroll-restoration/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart({}), + ], +}) diff --git a/e2e/solid-start/server-functions/.gitignore b/e2e/solid-start/server-functions/.gitignore index be342025da..a79d5cf129 100644 --- a/e2e/solid-start/server-functions/.gitignore +++ b/e2e/solid-start/server-functions/.gitignore @@ -7,13 +7,11 @@ yarn.lock .env .vercel .output -.vinxi /build/ /api/ /server/build /public/build -.vinxi # Sentry Config File .env.sentry-build-plugin /test-results/ diff --git a/e2e/solid-start/server-functions/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/solid-start/server-functions/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..2dc6bfc4bd --- /dev/null +++ b/e2e/solid-start/server-functions/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/solid-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/solid-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/solid-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/solid-start/server-functions/app.config.ts b/e2e/solid-start/server-functions/app.config.ts deleted file mode 100644 index 2a06e3d3f0..0000000000 --- a/e2e/solid-start/server-functions/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/solid-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/e2e/solid-start/server-functions/package.json b/e2e/solid-start/server-functions/package.json index cdb85c86ae..c3e457b6f2 100644 --- a/e2e/solid-start/server-functions/package.json +++ b/e2e/solid-start/server-functions/package.json @@ -4,10 +4,10 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "node .output/server/index.mjs", "test:e2e": "playwright test --project=chromium" }, "dependencies": { @@ -15,10 +15,10 @@ "@tanstack/solid-router-devtools": "workspace:^", "@tanstack/solid-start": "workspace:^", "js-cookie": "^3.0.5", - "solid-js": "^1.9.5", "redaxios": "^0.5.1", + "solid-js": "^1.9.5", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", + "vite": "6.3.5", "zod": "^3.24.2" }, "devDependencies": { @@ -26,12 +26,12 @@ "@tanstack/router-e2e-utils": "workspace:^", "@types/js-cookie": "^3.0.6", "@types/node": "^22.10.2", - "vite-plugin-solid": "^2.11.6", "autoprefixer": "^10.4.20", "combinate": "^1.1.11", "postcss": "^8.5.1", "tailwindcss": "^3.4.17", "typescript": "^5.7.2", + "vite-plugin-solid": "^2.11.6", "vite-tsconfig-paths": "^5.1.4" } } diff --git a/e2e/solid-start/server-functions/playwright.config.ts b/e2e/solid-start/server-functions/playwright.config.ts index 409765549f..afe39a46b1 100644 --- a/e2e/solid-start/server-functions/playwright.config.ts +++ b/e2e/solid-start/server-functions/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ }, webServer: { - command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm start --port ${PORT}`, + command: `pnpm build && VITE_SERVER_PORT=${PORT} PORT=${PORT} pnpm start`, url: baseURL, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/e2e/solid-start/server-functions/src/client.tsx b/e2e/solid-start/server-functions/src/client.tsx deleted file mode 100644 index ba0f02fac0..0000000000 --- a/e2e/solid-start/server-functions/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrate } from 'solid-js/web' -import { StartClient } from '@tanstack/solid-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrate(() => , document.body) diff --git a/e2e/solid-start/server-functions/src/routeTree.gen.ts b/e2e/solid-start/server-functions/src/routeTree.gen.ts index 4a34fccd1c..eb73211d02 100644 --- a/e2e/solid-start/server-functions/src/routeTree.gen.ts +++ b/e2e/solid-start/server-functions/src/routeTree.gen.ts @@ -8,112 +8,114 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/solid-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as SubmitPostFormdataImport } from './routes/submit-post-formdata' -import { Route as StatusImport } from './routes/status' -import { Route as SerializeFormDataImport } from './routes/serialize-form-data' -import { Route as ReturnNullImport } from './routes/return-null' -import { Route as RawResponseImport } from './routes/raw-response' -import { Route as MultipartImport } from './routes/multipart' -import { Route as IsomorphicFnsImport } from './routes/isomorphic-fns' -import { Route as HeadersImport } from './routes/headers' -import { Route as EnvOnlyImport } from './routes/env-only' -import { Route as DeadCodePreserveImport } from './routes/dead-code-preserve' -import { Route as ConsistentImport } from './routes/consistent' -import { Route as AbortSignalImport } from './routes/abort-signal' -import { Route as IndexImport } from './routes/index' -import { Route as CookiesIndexImport } from './routes/cookies/index' -import { Route as CookiesSetImport } from './routes/cookies/set' +import { Route as SubmitPostFormdataRouteImport } from './routes/submit-post-formdata' +import { Route as StatusRouteImport } from './routes/status' +import { Route as SerializeFormDataRouteImport } from './routes/serialize-form-data' +import { Route as ReturnNullRouteImport } from './routes/return-null' +import { Route as RawResponseRouteImport } from './routes/raw-response' +import { Route as MultipartRouteImport } from './routes/multipart' +import { Route as IsomorphicFnsRouteImport } from './routes/isomorphic-fns' +import { Route as HeadersRouteImport } from './routes/headers' +import { Route as EnvOnlyRouteImport } from './routes/env-only' +import { Route as DeadCodePreserveRouteImport } from './routes/dead-code-preserve' +import { Route as ConsistentRouteImport } from './routes/consistent' +import { Route as AbortSignalRouteImport } from './routes/abort-signal' +import { Route as IndexRouteImport } from './routes/index' +import { Route as CookiesIndexRouteImport } from './routes/cookies/index' +import { Route as CookiesSetRouteImport } from './routes/cookies/set' // Create/Update Routes -const SubmitPostFormdataRoute = SubmitPostFormdataImport.update({ +const SubmitPostFormdataRoute = SubmitPostFormdataRouteImport.update({ id: '/submit-post-formdata', path: '/submit-post-formdata', getParentRoute: () => rootRoute, } as any) -const StatusRoute = StatusImport.update({ +const StatusRoute = StatusRouteImport.update({ id: '/status', path: '/status', getParentRoute: () => rootRoute, } as any) -const SerializeFormDataRoute = SerializeFormDataImport.update({ +const SerializeFormDataRoute = SerializeFormDataRouteImport.update({ id: '/serialize-form-data', path: '/serialize-form-data', getParentRoute: () => rootRoute, } as any) -const ReturnNullRoute = ReturnNullImport.update({ +const ReturnNullRoute = ReturnNullRouteImport.update({ id: '/return-null', path: '/return-null', getParentRoute: () => rootRoute, } as any) -const RawResponseRoute = RawResponseImport.update({ +const RawResponseRoute = RawResponseRouteImport.update({ id: '/raw-response', path: '/raw-response', getParentRoute: () => rootRoute, } as any) -const MultipartRoute = MultipartImport.update({ +const MultipartRoute = MultipartRouteImport.update({ id: '/multipart', path: '/multipart', getParentRoute: () => rootRoute, } as any) -const IsomorphicFnsRoute = IsomorphicFnsImport.update({ +const IsomorphicFnsRoute = IsomorphicFnsRouteImport.update({ id: '/isomorphic-fns', path: '/isomorphic-fns', getParentRoute: () => rootRoute, } as any) -const HeadersRoute = HeadersImport.update({ +const HeadersRoute = HeadersRouteImport.update({ id: '/headers', path: '/headers', getParentRoute: () => rootRoute, } as any) -const EnvOnlyRoute = EnvOnlyImport.update({ +const EnvOnlyRoute = EnvOnlyRouteImport.update({ id: '/env-only', path: '/env-only', getParentRoute: () => rootRoute, } as any) -const DeadCodePreserveRoute = DeadCodePreserveImport.update({ +const DeadCodePreserveRoute = DeadCodePreserveRouteImport.update({ id: '/dead-code-preserve', path: '/dead-code-preserve', getParentRoute: () => rootRoute, } as any) -const ConsistentRoute = ConsistentImport.update({ +const ConsistentRoute = ConsistentRouteImport.update({ id: '/consistent', path: '/consistent', getParentRoute: () => rootRoute, } as any) -const AbortSignalRoute = AbortSignalImport.update({ +const AbortSignalRoute = AbortSignalRouteImport.update({ id: '/abort-signal', path: '/abort-signal', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const CookiesIndexRoute = CookiesIndexImport.update({ +const CookiesIndexRoute = CookiesIndexRouteImport.update({ id: '/cookies/', path: '/cookies/', getParentRoute: () => rootRoute, } as any) -const CookiesSetRoute = CookiesSetImport.update({ +const CookiesSetRoute = CookiesSetRouteImport.update({ id: '/cookies/set', path: '/cookies/set', getParentRoute: () => rootRoute, @@ -127,110 +129,248 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/abort-signal': { id: '/abort-signal' path: '/abort-signal' fullPath: '/abort-signal' - preLoaderRoute: typeof AbortSignalImport + preLoaderRoute: typeof AbortSignalRouteImport parentRoute: typeof rootRoute } '/consistent': { id: '/consistent' path: '/consistent' fullPath: '/consistent' - preLoaderRoute: typeof ConsistentImport + preLoaderRoute: typeof ConsistentRouteImport parentRoute: typeof rootRoute } '/dead-code-preserve': { id: '/dead-code-preserve' path: '/dead-code-preserve' fullPath: '/dead-code-preserve' - preLoaderRoute: typeof DeadCodePreserveImport + preLoaderRoute: typeof DeadCodePreserveRouteImport parentRoute: typeof rootRoute } '/env-only': { id: '/env-only' path: '/env-only' fullPath: '/env-only' - preLoaderRoute: typeof EnvOnlyImport + preLoaderRoute: typeof EnvOnlyRouteImport parentRoute: typeof rootRoute } '/headers': { id: '/headers' path: '/headers' fullPath: '/headers' - preLoaderRoute: typeof HeadersImport + preLoaderRoute: typeof HeadersRouteImport parentRoute: typeof rootRoute } '/isomorphic-fns': { id: '/isomorphic-fns' path: '/isomorphic-fns' fullPath: '/isomorphic-fns' - preLoaderRoute: typeof IsomorphicFnsImport + preLoaderRoute: typeof IsomorphicFnsRouteImport parentRoute: typeof rootRoute } '/multipart': { id: '/multipart' path: '/multipart' fullPath: '/multipart' - preLoaderRoute: typeof MultipartImport + preLoaderRoute: typeof MultipartRouteImport parentRoute: typeof rootRoute } '/raw-response': { id: '/raw-response' path: '/raw-response' fullPath: '/raw-response' - preLoaderRoute: typeof RawResponseImport + preLoaderRoute: typeof RawResponseRouteImport parentRoute: typeof rootRoute } '/return-null': { id: '/return-null' path: '/return-null' fullPath: '/return-null' - preLoaderRoute: typeof ReturnNullImport + preLoaderRoute: typeof ReturnNullRouteImport parentRoute: typeof rootRoute } '/serialize-form-data': { id: '/serialize-form-data' path: '/serialize-form-data' fullPath: '/serialize-form-data' - preLoaderRoute: typeof SerializeFormDataImport + preLoaderRoute: typeof SerializeFormDataRouteImport parentRoute: typeof rootRoute } '/status': { id: '/status' path: '/status' fullPath: '/status' - preLoaderRoute: typeof StatusImport + preLoaderRoute: typeof StatusRouteImport parentRoute: typeof rootRoute } '/submit-post-formdata': { id: '/submit-post-formdata' path: '/submit-post-formdata' fullPath: '/submit-post-formdata' - preLoaderRoute: typeof SubmitPostFormdataImport + preLoaderRoute: typeof SubmitPostFormdataRouteImport parentRoute: typeof rootRoute } '/cookies/set': { id: '/cookies/set' path: '/cookies/set' fullPath: '/cookies/set' - preLoaderRoute: typeof CookiesSetImport + preLoaderRoute: typeof CookiesSetRouteImport parentRoute: typeof rootRoute } '/cookies/': { id: '/cookies/' path: '/cookies' fullPath: '/cookies' - preLoaderRoute: typeof CookiesIndexImport + preLoaderRoute: typeof CookiesIndexRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/abort-signal' { + const createFileRoute: CreateFileRoute< + '/abort-signal', + FileRoutesByPath['/abort-signal']['parentRoute'], + FileRoutesByPath['/abort-signal']['id'], + FileRoutesByPath['/abort-signal']['path'], + FileRoutesByPath['/abort-signal']['fullPath'] + > +} +declare module './routes/consistent' { + const createFileRoute: CreateFileRoute< + '/consistent', + FileRoutesByPath['/consistent']['parentRoute'], + FileRoutesByPath['/consistent']['id'], + FileRoutesByPath['/consistent']['path'], + FileRoutesByPath['/consistent']['fullPath'] + > +} +declare module './routes/dead-code-preserve' { + const createFileRoute: CreateFileRoute< + '/dead-code-preserve', + FileRoutesByPath['/dead-code-preserve']['parentRoute'], + FileRoutesByPath['/dead-code-preserve']['id'], + FileRoutesByPath['/dead-code-preserve']['path'], + FileRoutesByPath['/dead-code-preserve']['fullPath'] + > +} +declare module './routes/env-only' { + const createFileRoute: CreateFileRoute< + '/env-only', + FileRoutesByPath['/env-only']['parentRoute'], + FileRoutesByPath['/env-only']['id'], + FileRoutesByPath['/env-only']['path'], + FileRoutesByPath['/env-only']['fullPath'] + > +} +declare module './routes/headers' { + const createFileRoute: CreateFileRoute< + '/headers', + FileRoutesByPath['/headers']['parentRoute'], + FileRoutesByPath['/headers']['id'], + FileRoutesByPath['/headers']['path'], + FileRoutesByPath['/headers']['fullPath'] + > +} +declare module './routes/isomorphic-fns' { + const createFileRoute: CreateFileRoute< + '/isomorphic-fns', + FileRoutesByPath['/isomorphic-fns']['parentRoute'], + FileRoutesByPath['/isomorphic-fns']['id'], + FileRoutesByPath['/isomorphic-fns']['path'], + FileRoutesByPath['/isomorphic-fns']['fullPath'] + > +} +declare module './routes/multipart' { + const createFileRoute: CreateFileRoute< + '/multipart', + FileRoutesByPath['/multipart']['parentRoute'], + FileRoutesByPath['/multipart']['id'], + FileRoutesByPath['/multipart']['path'], + FileRoutesByPath['/multipart']['fullPath'] + > +} +declare module './routes/raw-response' { + const createFileRoute: CreateFileRoute< + '/raw-response', + FileRoutesByPath['/raw-response']['parentRoute'], + FileRoutesByPath['/raw-response']['id'], + FileRoutesByPath['/raw-response']['path'], + FileRoutesByPath['/raw-response']['fullPath'] + > +} +declare module './routes/return-null' { + const createFileRoute: CreateFileRoute< + '/return-null', + FileRoutesByPath['/return-null']['parentRoute'], + FileRoutesByPath['/return-null']['id'], + FileRoutesByPath['/return-null']['path'], + FileRoutesByPath['/return-null']['fullPath'] + > +} +declare module './routes/serialize-form-data' { + const createFileRoute: CreateFileRoute< + '/serialize-form-data', + FileRoutesByPath['/serialize-form-data']['parentRoute'], + FileRoutesByPath['/serialize-form-data']['id'], + FileRoutesByPath['/serialize-form-data']['path'], + FileRoutesByPath['/serialize-form-data']['fullPath'] + > +} +declare module './routes/status' { + const createFileRoute: CreateFileRoute< + '/status', + FileRoutesByPath['/status']['parentRoute'], + FileRoutesByPath['/status']['id'], + FileRoutesByPath['/status']['path'], + FileRoutesByPath['/status']['fullPath'] + > +} +declare module './routes/submit-post-formdata' { + const createFileRoute: CreateFileRoute< + '/submit-post-formdata', + FileRoutesByPath['/submit-post-formdata']['parentRoute'], + FileRoutesByPath['/submit-post-formdata']['id'], + FileRoutesByPath['/submit-post-formdata']['path'], + FileRoutesByPath['/submit-post-formdata']['fullPath'] + > +} +declare module './routes/cookies/set' { + const createFileRoute: CreateFileRoute< + '/cookies/set', + FileRoutesByPath['/cookies/set']['parentRoute'], + FileRoutesByPath['/cookies/set']['id'], + FileRoutesByPath['/cookies/set']['path'], + FileRoutesByPath['/cookies/set']['fullPath'] + > +} +declare module './routes/cookies/index' { + const createFileRoute: CreateFileRoute< + '/cookies/', + FileRoutesByPath['/cookies/']['parentRoute'], + FileRoutesByPath['/cookies/']['id'], + FileRoutesByPath['/cookies/']['path'], + FileRoutesByPath['/cookies/']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/e2e/solid-start/server-functions/src/routes/__root.tsx b/e2e/solid-start/server-functions/src/routes/__root.tsx index 52d64bf7a7..c1855d436a 100644 --- a/e2e/solid-start/server-functions/src/routes/__root.tsx +++ b/e2e/solid-start/server-functions/src/routes/__root.tsx @@ -1,9 +1,8 @@ import { Outlet, createRootRoute } from '@tanstack/solid-router' -import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary' +import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools' import { NotFound } from '~/components/NotFound' import appCss from '~/styles/app.css?url' -import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools' export const Route = createRootRoute({ head: () => ({ diff --git a/e2e/solid-start/server-functions/src/routes/abort-signal.tsx b/e2e/solid-start/server-functions/src/routes/abort-signal.tsx index 752346264e..16aa9bc5b5 100644 --- a/e2e/solid-start/server-functions/src/routes/abort-signal.tsx +++ b/e2e/solid-start/server-functions/src/routes/abort-signal.tsx @@ -1,8 +1,7 @@ -import { createFileRoute } from '@tanstack/solid-router' import { createServerFn } from '@tanstack/solid-start' import * as Solid from 'solid-js' -export const Route = createFileRoute('/abort-signal')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/e2e/solid-start/server-functions/src/routes/consistent.tsx b/e2e/solid-start/server-functions/src/routes/consistent.tsx index 9e4c1b3b08..190c64c0f7 100644 --- a/e2e/solid-start/server-functions/src/routes/consistent.tsx +++ b/e2e/solid-start/server-functions/src/routes/consistent.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' import * as Solid from 'solid-js' import { createServerFn } from '@tanstack/solid-start' @@ -10,7 +9,7 @@ import { createServerFn } from '@tanstack/solid-start' * @link https://github.com/TanStack/router/issues/2481 */ -export const Route = createFileRoute('/consistent')({ +export const Route = createFileRoute({ component: ConsistentServerFnCalls, loader: async () => { const data = await cons_serverGetFn1({ data: { username: 'TEST' } }) diff --git a/e2e/solid-start/server-functions/src/routes/cookies/index.tsx b/e2e/solid-start/server-functions/src/routes/cookies/index.tsx index 5cccd18057..13cfd9cbc1 100644 --- a/e2e/solid-start/server-functions/src/routes/cookies/index.tsx +++ b/e2e/solid-start/server-functions/src/routes/cookies/index.tsx @@ -1,10 +1,10 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' import { z } from 'zod' const cookieSchema = z .object({ value: z.string() }) .catch(() => ({ value: `CLIENT-${Date.now()}` })) -export const Route = createFileRoute('/cookies/')({ +export const Route = createFileRoute({ validateSearch: cookieSchema, component: RouteComponent, }) diff --git a/e2e/solid-start/server-functions/src/routes/cookies/set.tsx b/e2e/solid-start/server-functions/src/routes/cookies/set.tsx index 32e06725cf..0814829dc4 100644 --- a/e2e/solid-start/server-functions/src/routes/cookies/set.tsx +++ b/e2e/solid-start/server-functions/src/routes/cookies/set.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' import { createServerFn } from '@tanstack/solid-start' import { setCookie } from '@tanstack/solid-start/server' import { z } from 'zod' @@ -7,7 +6,7 @@ import * as Solid from 'solid-js' const cookieSchema = z.object({ value: z.string() }) -export const Route = createFileRoute('/cookies/set')({ +export const Route = createFileRoute({ validateSearch: cookieSchema, loaderDeps: ({ search }) => search, loader: async ({ deps }) => { diff --git a/e2e/solid-start/server-functions/src/routes/dead-code-preserve.tsx b/e2e/solid-start/server-functions/src/routes/dead-code-preserve.tsx index 96d7a3ca13..ebf26bfba9 100644 --- a/e2e/solid-start/server-functions/src/routes/dead-code-preserve.tsx +++ b/e2e/solid-start/server-functions/src/routes/dead-code-preserve.tsx @@ -2,9 +2,9 @@ import * as fs from 'node:fs' import { createServerFn } from '@tanstack/solid-start' import { getRequestHeader } from '@tanstack/solid-start/server' import { createSignal } from 'solid-js' -import { createFileRoute } from '@tanstack/solid-router' +import {} from '@tanstack/solid-router' -export const Route = createFileRoute('/dead-code-preserve')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/e2e/solid-start/server-functions/src/routes/env-only.tsx b/e2e/solid-start/server-functions/src/routes/env-only.tsx index df8f08eed2..d888d20c80 100644 --- a/e2e/solid-start/server-functions/src/routes/env-only.tsx +++ b/e2e/solid-start/server-functions/src/routes/env-only.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' import { clientOnly, createServerFn, serverOnly } from '@tanstack/solid-start' import { createSignal } from 'solid-js' @@ -18,7 +17,7 @@ const testOnServer = createServerFn().handler(() => { return { serverOnServer, clientOnServer } }) -export const Route = createFileRoute('/env-only')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/e2e/solid-start/server-functions/src/routes/headers.tsx b/e2e/solid-start/server-functions/src/routes/headers.tsx index 94ef5a05c1..2f3acacdbc 100644 --- a/e2e/solid-start/server-functions/src/routes/headers.tsx +++ b/e2e/solid-start/server-functions/src/routes/headers.tsx @@ -1,10 +1,9 @@ -import { createFileRoute } from '@tanstack/solid-router' import * as Solid from 'solid-js' import { createServerFn } from '@tanstack/solid-start' import { getHeaders, setHeader } from '@tanstack/solid-start/server' import type { HTTPHeaderName } from '@tanstack/solid-start/server' -export const Route = createFileRoute('/headers')({ +export const Route = createFileRoute({ loader: async () => { return { testHeaders: await getTestHeaders(), @@ -36,7 +35,7 @@ function ResponseHeaders({ initialTestHeaders: TestHeadersResult }) { const [testHeadersResult, setTestHeadersResult] = - Solid.createSignal(initialTestHeaders) + Solid.createSignal(null) return (
@@ -58,10 +57,18 @@ function ResponseHeaders({
-

Headers:

-
-          {JSON.stringify(testHeadersResult().headers, null, 2)}
+        

Initial Headers:

+
+          {JSON.stringify(initialTestHeaders.headers, null, 2)}
         
+ {testHeadersResult() && ( + <> +

Updated Headers:

+
+              {JSON.stringify(testHeadersResult()?.headers, null, 2)}
+            
+ + )}
) diff --git a/e2e/solid-start/server-functions/src/routes/index.tsx b/e2e/solid-start/server-functions/src/routes/index.tsx index bf28fb8b00..443c52a21c 100644 --- a/e2e/solid-start/server-functions/src/routes/index.tsx +++ b/e2e/solid-start/server-functions/src/routes/index.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/solid-start/server-functions/src/routes/isomorphic-fns.tsx b/e2e/solid-start/server-functions/src/routes/isomorphic-fns.tsx index 3327b38af7..b01aeb9217 100644 --- a/e2e/solid-start/server-functions/src/routes/isomorphic-fns.tsx +++ b/e2e/solid-start/server-functions/src/routes/isomorphic-fns.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' import { createIsomorphicFn, createServerFn } from '@tanstack/solid-start' import { createSignal } from 'solid-js' @@ -16,7 +15,7 @@ const getServerEcho = createServerFn() .validator((input: string) => input) .handler(({ data }) => getEcho(data)) -export const Route = createFileRoute('/isomorphic-fns')({ +export const Route = createFileRoute({ component: RouteComponent, loader() { return { diff --git a/e2e/solid-start/server-functions/src/routes/multipart.tsx b/e2e/solid-start/server-functions/src/routes/multipart.tsx index 5e959da7ae..5ddb9aa6b5 100644 --- a/e2e/solid-start/server-functions/src/routes/multipart.tsx +++ b/e2e/solid-start/server-functions/src/routes/multipart.tsx @@ -1,8 +1,7 @@ -import { createFileRoute } from '@tanstack/solid-router' import * as Solid from 'solid-js' import { createServerFn } from '@tanstack/solid-start' -export const Route = createFileRoute('/multipart')({ +export const Route = createFileRoute({ component: MultipartServerFnCall, }) diff --git a/e2e/solid-start/server-functions/src/routes/raw-response.tsx b/e2e/solid-start/server-functions/src/routes/raw-response.tsx index d0ff217944..75a605c50b 100644 --- a/e2e/solid-start/server-functions/src/routes/raw-response.tsx +++ b/e2e/solid-start/server-functions/src/routes/raw-response.tsx @@ -1,8 +1,8 @@ import * as Solid from 'solid-js' -import { createFileRoute } from '@tanstack/solid-router' + import { createServerFn } from '@tanstack/solid-start' -export const Route = createFileRoute('/raw-response')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/e2e/solid-start/server-functions/src/routes/return-null.tsx b/e2e/solid-start/server-functions/src/routes/return-null.tsx index 2e789d2eef..319b8ba32a 100644 --- a/e2e/solid-start/server-functions/src/routes/return-null.tsx +++ b/e2e/solid-start/server-functions/src/routes/return-null.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' import { createServerFn } from '@tanstack/solid-start' import * as Solid from 'solid-js' @@ -8,7 +7,7 @@ import * as Solid from 'solid-js' * @link https://github.com/TanStack/router/issues/2776 */ -export const Route = createFileRoute('/return-null')({ +export const Route = createFileRoute({ component: AllowServerFnReturnNull, }) diff --git a/e2e/solid-start/server-functions/src/routes/serialize-form-data.tsx b/e2e/solid-start/server-functions/src/routes/serialize-form-data.tsx index 487d91e86d..d60b4072cf 100644 --- a/e2e/solid-start/server-functions/src/routes/serialize-form-data.tsx +++ b/e2e/solid-start/server-functions/src/routes/serialize-form-data.tsx @@ -1,5 +1,5 @@ import * as Solid from 'solid-js' -import { createFileRoute } from '@tanstack/solid-router' + import { createServerFn } from '@tanstack/solid-start' const testValues = { @@ -79,6 +79,6 @@ export function SerializeFormDataFnCall() { ) } -export const Route = createFileRoute('/serialize-form-data')({ +export const Route = createFileRoute({ component: SerializeFormDataFnCall, }) diff --git a/e2e/solid-start/server-functions/src/routes/status.tsx b/e2e/solid-start/server-functions/src/routes/status.tsx index 22b45bb28f..867bdd6927 100644 --- a/e2e/solid-start/server-functions/src/routes/status.tsx +++ b/e2e/solid-start/server-functions/src/routes/status.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/solid-router' import { createServerFn, useServerFn } from '@tanstack/solid-start' import { setResponseStatus } from '@tanstack/solid-start/server' @@ -9,7 +8,7 @@ const helloFn = createServerFn().handler(() => { } }) -export const Route = createFileRoute('/status')({ +export const Route = createFileRoute({ component: StatusComponent, }) diff --git a/e2e/solid-start/server-functions/src/routes/submit-post-formdata.tsx b/e2e/solid-start/server-functions/src/routes/submit-post-formdata.tsx index 3fb6ea356f..8b881645bb 100644 --- a/e2e/solid-start/server-functions/src/routes/submit-post-formdata.tsx +++ b/e2e/solid-start/server-functions/src/routes/submit-post-formdata.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' import { createServerFn } from '@tanstack/solid-start' -export const Route = createFileRoute('/submit-post-formdata')({ +export const Route = createFileRoute({ component: SubmitPostFormDataFn, }) diff --git a/e2e/solid-start/server-functions/src/ssr.tsx b/e2e/solid-start/server-functions/src/ssr.tsx deleted file mode 100644 index 6d10bea05f..0000000000 --- a/e2e/solid-start/server-functions/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/solid-start/server' -import { getRouterManifest } from '@tanstack/solid-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/e2e/solid-start/server-functions/src/tanstack-start.d.ts b/e2e/solid-start/server-functions/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/e2e/solid-start/server-functions/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/solid-start/server-functions/src/vite-env.d.ts b/e2e/solid-start/server-functions/src/vite-env.d.ts new file mode 100644 index 0000000000..0b2af560d6 --- /dev/null +++ b/e2e/solid-start/server-functions/src/vite-env.d.ts @@ -0,0 +1,4 @@ +declare module '*?url' { + const url: string + export default url +} diff --git a/e2e/solid-start/server-functions/tests/server-functions.spec.ts b/e2e/solid-start/server-functions/tests/server-functions.spec.ts index 56d6608077..80c89004c5 100644 --- a/e2e/solid-start/server-functions/tests/server-functions.spec.ts +++ b/e2e/solid-start/server-functions/tests/server-functions.spec.ts @@ -179,44 +179,24 @@ test('server function can correctly send and receive headers', async ({ await page.goto('/headers') await page.waitForLoadState('networkidle') - // console.log(await page.getByTestId('test-headers-result').textContent()) - await expect(page.getByTestId('test-headers-result')).toContainText(`{ - "accept": "application/json", - "accept-encoding": "gzip, deflate, br, zstd", - "accept-language": "en-US", - "connection": "keep-alive", - "content-type": "application/json", - "host": "localhost:${PORT}", - "sec-ch-ua": "\\"Chromium\\";v=\\"136\\", \\"HeadlessChrome\\";v=\\"136\\", \\"Not.A/Brand\\";v=\\"99\\"", - "sec-ch-ua-mobile": "?0", - "sec-ch-ua-platform": "\\"Windows\\"", - "sec-fetch-dest": "document", - "sec-fetch-mode": "navigate", - "sec-fetch-site": "none", - "sec-fetch-user": "?1", - "upgrade-insecure-requests": "1", - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.7103.25 Safari/537.36" -}`) + let headers = JSON.parse( + await page.getByTestId('initial-headers-result').innerText(), + ) + expect(headers['host']).toBe(`localhost:${PORT}`) + expect(headers['user-agent']).toContain('Mozilla/5.0') + expect(headers['sec-fetch-mode']).toBe('navigate') await page.getByTestId('test-headers-btn').click() - await page.waitForLoadState('networkidle') + await page.waitForSelector('[data-testid="updated-headers-result"]') + + headers = JSON.parse( + await page.getByTestId('updated-headers-result').innerText(), + ) - await expect(page.getByTestId('test-headers-result')).toContainText(`{ - "host": "localhost:${PORT}", - "connection": "keep-alive", - "sec-ch-ua-platform": "\\"Windows\\"", - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.7103.25 Safari/537.36", - "accept": "application/json", - "sec-ch-ua": "\\"Chromium\\";v=\\"136\\", \\"HeadlessChrome\\";v=\\"136\\", \\"Not.A/Brand\\";v=\\"99\\"", - "content-type": "application/json", - "sec-ch-ua-mobile": "?0", - "accept-language": "en-US", - "sec-fetch-site": "same-origin", - "sec-fetch-mode": "cors", - "sec-fetch-dest": "empty", - "referer": "http://localhost:${PORT}/headers", - "accept-encoding": "gzip, deflate, br, zstd" -}`) + expect(headers['host']).toBe(`localhost:${PORT}`) + expect(headers['user-agent']).toContain('Mozilla/5.0') + expect(headers['sec-fetch-mode']).toBe('cors') + expect(headers['referer']).toBe(`http://localhost:${PORT}/headers`) }) test('Direct POST submitting FormData to a Server function returns the correct message', async ({ diff --git a/e2e/solid-start/server-functions/vite.config.ts b/e2e/solid-start/server-functions/vite.config.ts new file mode 100644 index 0000000000..bae1bfaad6 --- /dev/null +++ b/e2e/solid-start/server-functions/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/e2e/solid-start/website/.gitignore b/e2e/solid-start/website/.gitignore index be342025da..a79d5cf129 100644 --- a/e2e/solid-start/website/.gitignore +++ b/e2e/solid-start/website/.gitignore @@ -7,13 +7,11 @@ yarn.lock .env .vercel .output -.vinxi /build/ /api/ /server/build /public/build -.vinxi # Sentry Config File .env.sentry-build-plugin /test-results/ diff --git a/e2e/solid-start/website/.tanstack-start/server-routes/routeTree.gen.ts b/e2e/solid-start/website/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..2dc6bfc4bd --- /dev/null +++ b/e2e/solid-start/website/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/solid-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/solid-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/solid-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/solid-start/website/app.config.ts b/e2e/solid-start/website/app.config.ts deleted file mode 100644 index 2a06e3d3f0..0000000000 --- a/e2e/solid-start/website/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/solid-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/e2e/solid-start/website/package.json b/e2e/solid-start/website/package.json index 1f3a38c036..8c6538a220 100644 --- a/e2e/solid-start/website/package.json +++ b/e2e/solid-start/website/package.json @@ -4,31 +4,31 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "node .output/server/index.mjs", "test:e2e": "playwright test --project=chromium" }, "dependencies": { "@tanstack/solid-router": "workspace:^", "@tanstack/solid-router-devtools": "workspace:^", "@tanstack/solid-start": "workspace:^", - "solid-js": "^1.9.5", "redaxios": "^0.5.1", + "solid-js": "^1.9.5", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", + "vite": "6.3.5", "zod": "^3.24.2" }, "devDependencies": { "@playwright/test": "^1.50.1", "@tanstack/router-e2e-utils": "workspace:^", "@types/node": "^22.10.2", - "vite-plugin-solid": "^2.11.6", - "postcss": "^8.5.1", "autoprefixer": "^10.4.20", + "postcss": "^8.5.1", "tailwindcss": "^3.4.17", "typescript": "^5.7.2", + "vite-plugin-solid": "^2.11.6", "vite-tsconfig-paths": "^5.1.4" } } diff --git a/e2e/solid-start/website/playwright.config.ts b/e2e/solid-start/website/playwright.config.ts index bb77d0cf70..e834d88cf4 100644 --- a/e2e/solid-start/website/playwright.config.ts +++ b/e2e/solid-start/website/playwright.config.ts @@ -4,6 +4,7 @@ import packageJson from './package.json' with { type: 'json' } const PORT = derivePort(packageJson.name) const baseURL = `http://localhost:${PORT}` + /** * See https://playwright.dev/docs/test-configuration. */ @@ -19,7 +20,7 @@ export default defineConfig({ }, webServer: { - command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm start --port ${PORT}`, + command: `pnpm build && VITE_SERVER_PORT=${PORT} PORT=${PORT} pnpm start`, url: baseURL, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/e2e/solid-start/website/src/client.tsx b/e2e/solid-start/website/src/client.tsx deleted file mode 100644 index ba0f02fac0..0000000000 --- a/e2e/solid-start/website/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrate } from 'solid-js/web' -import { StartClient } from '@tanstack/solid-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrate(() => , document.body) diff --git a/e2e/solid-start/website/src/routeTree.gen.ts b/e2e/solid-start/website/src/routeTree.gen.ts index 32515b924b..e28cb9bd55 100644 --- a/e2e/solid-start/website/src/routeTree.gen.ts +++ b/e2e/solid-start/website/src/routeTree.gen.ts @@ -8,82 +8,83 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/solid-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as LibraryImport } from './routes/_library' -import { Route as LibraryIndexImport } from './routes/_library.index' -import { Route as ProjectIndexImport } from './routes/$project.index' -import { Route as LibraryProjectImport } from './routes/_library.$project' -import { Route as LibraryProjectVersionIndexImport } from './routes/_library.$project.$version.index' -import { Route as ProjectVersionDocsIndexImport } from './routes/$project.$version.docs.index' -import { Route as ProjectVersionDocsFrameworkFrameworkImport } from './routes/$project.$version.docs.framework.$framework' -import { Route as ProjectVersionDocsFrameworkFrameworkIndexImport } from './routes/$project.$version.docs.framework.$framework.index' -import { Route as ProjectVersionDocsFrameworkFrameworkSplatImport } from './routes/$project.$version.docs.framework.$framework.$' -import { Route as ProjectVersionDocsFrameworkFrameworkExamplesSplatImport } from './routes/$project.$version.docs.framework.$framework.examples.$' +import { Route as LibraryRouteImport } from './routes/_library' +import { Route as LibraryIndexRouteImport } from './routes/_library.index' +import { Route as ProjectIndexRouteImport } from './routes/$project.index' +import { Route as LibraryProjectRouteImport } from './routes/_library.$project' +import { Route as LibraryProjectVersionIndexRouteImport } from './routes/_library.$project.$version.index' +import { Route as ProjectVersionDocsIndexRouteImport } from './routes/$project.$version.docs.index' +import { Route as ProjectVersionDocsFrameworkFrameworkRouteImport } from './routes/$project.$version.docs.framework.$framework' +import { Route as ProjectVersionDocsFrameworkFrameworkIndexRouteImport } from './routes/$project.$version.docs.framework.$framework.index' +import { Route as ProjectVersionDocsFrameworkFrameworkSplatRouteImport } from './routes/$project.$version.docs.framework.$framework.$' +import { Route as ProjectVersionDocsFrameworkFrameworkExamplesSplatRouteImport } from './routes/$project.$version.docs.framework.$framework.examples.$' // Create/Update Routes -const LibraryRoute = LibraryImport.update({ +const LibraryRoute = LibraryRouteImport.update({ id: '/_library', getParentRoute: () => rootRoute, } as any) -const LibraryIndexRoute = LibraryIndexImport.update({ +const LibraryIndexRoute = LibraryIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => LibraryRoute, } as any) -const ProjectIndexRoute = ProjectIndexImport.update({ +const ProjectIndexRoute = ProjectIndexRouteImport.update({ id: '/$project/', path: '/$project/', getParentRoute: () => rootRoute, } as any) -const LibraryProjectRoute = LibraryProjectImport.update({ +const LibraryProjectRoute = LibraryProjectRouteImport.update({ id: '/$project', path: '/$project', getParentRoute: () => LibraryRoute, } as any) -const LibraryProjectVersionIndexRoute = LibraryProjectVersionIndexImport.update( - { +const LibraryProjectVersionIndexRoute = + LibraryProjectVersionIndexRouteImport.update({ id: '/$version/', path: '/$version/', getParentRoute: () => LibraryProjectRoute, - } as any, -) + } as any) -const ProjectVersionDocsIndexRoute = ProjectVersionDocsIndexImport.update({ +const ProjectVersionDocsIndexRoute = ProjectVersionDocsIndexRouteImport.update({ id: '/$project/$version/docs/', path: '/$project/$version/docs/', getParentRoute: () => rootRoute, } as any) const ProjectVersionDocsFrameworkFrameworkRoute = - ProjectVersionDocsFrameworkFrameworkImport.update({ + ProjectVersionDocsFrameworkFrameworkRouteImport.update({ id: '/$project/$version/docs/framework/$framework', path: '/$project/$version/docs/framework/$framework', getParentRoute: () => rootRoute, } as any) const ProjectVersionDocsFrameworkFrameworkIndexRoute = - ProjectVersionDocsFrameworkFrameworkIndexImport.update({ + ProjectVersionDocsFrameworkFrameworkIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => ProjectVersionDocsFrameworkFrameworkRoute, } as any) const ProjectVersionDocsFrameworkFrameworkSplatRoute = - ProjectVersionDocsFrameworkFrameworkSplatImport.update({ + ProjectVersionDocsFrameworkFrameworkSplatRouteImport.update({ id: '/$', path: '/$', getParentRoute: () => ProjectVersionDocsFrameworkFrameworkRoute, } as any) const ProjectVersionDocsFrameworkFrameworkExamplesSplatRoute = - ProjectVersionDocsFrameworkFrameworkExamplesSplatImport.update({ + ProjectVersionDocsFrameworkFrameworkExamplesSplatRouteImport.update({ id: '/examples/$', path: '/examples/$', getParentRoute: () => ProjectVersionDocsFrameworkFrameworkRoute, @@ -97,75 +98,168 @@ declare module '@tanstack/solid-router' { id: '/_library' path: '' fullPath: '' - preLoaderRoute: typeof LibraryImport + preLoaderRoute: typeof LibraryRouteImport parentRoute: typeof rootRoute } '/_library/$project': { id: '/_library/$project' path: '/$project' fullPath: '/$project' - preLoaderRoute: typeof LibraryProjectImport - parentRoute: typeof LibraryImport + preLoaderRoute: typeof LibraryProjectRouteImport + parentRoute: typeof LibraryRouteImport } '/$project/': { id: '/$project/' path: '/$project' fullPath: '/$project' - preLoaderRoute: typeof ProjectIndexImport + preLoaderRoute: typeof ProjectIndexRouteImport parentRoute: typeof rootRoute } '/_library/': { id: '/_library/' path: '/' fullPath: '/' - preLoaderRoute: typeof LibraryIndexImport - parentRoute: typeof LibraryImport + preLoaderRoute: typeof LibraryIndexRouteImport + parentRoute: typeof LibraryRouteImport } '/$project/$version/docs/': { id: '/$project/$version/docs/' path: '/$project/$version/docs' fullPath: '/$project/$version/docs' - preLoaderRoute: typeof ProjectVersionDocsIndexImport + preLoaderRoute: typeof ProjectVersionDocsIndexRouteImport parentRoute: typeof rootRoute } '/_library/$project/$version/': { id: '/_library/$project/$version/' path: '/$version' fullPath: '/$project/$version' - preLoaderRoute: typeof LibraryProjectVersionIndexImport - parentRoute: typeof LibraryProjectImport + preLoaderRoute: typeof LibraryProjectVersionIndexRouteImport + parentRoute: typeof LibraryProjectRouteImport } '/$project/$version/docs/framework/$framework': { id: '/$project/$version/docs/framework/$framework' path: '/$project/$version/docs/framework/$framework' fullPath: '/$project/$version/docs/framework/$framework' - preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkImport + preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkRouteImport parentRoute: typeof rootRoute } '/$project/$version/docs/framework/$framework/$': { id: '/$project/$version/docs/framework/$framework/$' path: '/$' fullPath: '/$project/$version/docs/framework/$framework/$' - preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkSplatImport - parentRoute: typeof ProjectVersionDocsFrameworkFrameworkImport + preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkSplatRouteImport + parentRoute: typeof ProjectVersionDocsFrameworkFrameworkRouteImport } '/$project/$version/docs/framework/$framework/': { id: '/$project/$version/docs/framework/$framework/' path: '/' fullPath: '/$project/$version/docs/framework/$framework/' - preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkIndexImport - parentRoute: typeof ProjectVersionDocsFrameworkFrameworkImport + preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkIndexRouteImport + parentRoute: typeof ProjectVersionDocsFrameworkFrameworkRouteImport } '/$project/$version/docs/framework/$framework/examples/$': { id: '/$project/$version/docs/framework/$framework/examples/$' path: '/examples/$' fullPath: '/$project/$version/docs/framework/$framework/examples/$' - preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkExamplesSplatImport - parentRoute: typeof ProjectVersionDocsFrameworkFrameworkImport + preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkExamplesSplatRouteImport + parentRoute: typeof ProjectVersionDocsFrameworkFrameworkRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/_library' { + const createFileRoute: CreateFileRoute< + '/_library', + FileRoutesByPath['/_library']['parentRoute'], + FileRoutesByPath['/_library']['id'], + FileRoutesByPath['/_library']['path'], + FileRoutesByPath['/_library']['fullPath'] + > +} +declare module './routes/_library.$project' { + const createFileRoute: CreateFileRoute< + '/_library/$project', + FileRoutesByPath['/_library/$project']['parentRoute'], + FileRoutesByPath['/_library/$project']['id'], + FileRoutesByPath['/_library/$project']['path'], + FileRoutesByPath['/_library/$project']['fullPath'] + > +} +declare module './routes/$project.index' { + const createFileRoute: CreateFileRoute< + '/$project/', + FileRoutesByPath['/$project/']['parentRoute'], + FileRoutesByPath['/$project/']['id'], + FileRoutesByPath['/$project/']['path'], + FileRoutesByPath['/$project/']['fullPath'] + > +} +declare module './routes/_library.index' { + const createFileRoute: CreateFileRoute< + '/_library/', + FileRoutesByPath['/_library/']['parentRoute'], + FileRoutesByPath['/_library/']['id'], + FileRoutesByPath['/_library/']['path'], + FileRoutesByPath['/_library/']['fullPath'] + > +} +declare module './routes/$project.$version.docs.index' { + const createFileRoute: CreateFileRoute< + '/$project/$version/docs/', + FileRoutesByPath['/$project/$version/docs/']['parentRoute'], + FileRoutesByPath['/$project/$version/docs/']['id'], + FileRoutesByPath['/$project/$version/docs/']['path'], + FileRoutesByPath['/$project/$version/docs/']['fullPath'] + > +} +declare module './routes/_library.$project.$version.index' { + const createFileRoute: CreateFileRoute< + '/_library/$project/$version/', + FileRoutesByPath['/_library/$project/$version/']['parentRoute'], + FileRoutesByPath['/_library/$project/$version/']['id'], + FileRoutesByPath['/_library/$project/$version/']['path'], + FileRoutesByPath['/_library/$project/$version/']['fullPath'] + > +} +declare module './routes/$project.$version.docs.framework.$framework' { + const createFileRoute: CreateFileRoute< + '/$project/$version/docs/framework/$framework', + FileRoutesByPath['/$project/$version/docs/framework/$framework']['parentRoute'], + FileRoutesByPath['/$project/$version/docs/framework/$framework']['id'], + FileRoutesByPath['/$project/$version/docs/framework/$framework']['path'], + FileRoutesByPath['/$project/$version/docs/framework/$framework']['fullPath'] + > +} +declare module './routes/$project.$version.docs.framework.$framework.$' { + const createFileRoute: CreateFileRoute< + '/$project/$version/docs/framework/$framework/$', + FileRoutesByPath['/$project/$version/docs/framework/$framework/$']['parentRoute'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/$']['id'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/$']['path'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/$']['fullPath'] + > +} +declare module './routes/$project.$version.docs.framework.$framework.index' { + const createFileRoute: CreateFileRoute< + '/$project/$version/docs/framework/$framework/', + FileRoutesByPath['/$project/$version/docs/framework/$framework/']['parentRoute'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/']['id'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/']['path'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/']['fullPath'] + > +} +declare module './routes/$project.$version.docs.framework.$framework.examples.$' { + const createFileRoute: CreateFileRoute< + '/$project/$version/docs/framework/$framework/examples/$', + FileRoutesByPath['/$project/$version/docs/framework/$framework/examples/$']['parentRoute'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/examples/$']['id'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/examples/$']['path'], + FileRoutesByPath['/$project/$version/docs/framework/$framework/examples/$']['fullPath'] + > +} + // Create and export the route tree interface LibraryProjectRouteChildren { diff --git a/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.$.tsx b/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.$.tsx index 1df208a1c4..e5da7812c9 100644 --- a/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.$.tsx +++ b/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.$.tsx @@ -1,12 +1,10 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/solid-router' +import { ErrorComponent } from '@tanstack/solid-router' import type { ErrorComponentProps } from '@tanstack/solid-router' import { NotFound } from '~/components/NotFound' import { getDocument } from '~/server/document' import { capitalize, seo } from '~/utils/seo' -export const Route = createFileRoute( - '/$project/$version/docs/framework/$framework/$', -)({ +export const Route = createFileRoute({ loader: ({ params: { _splat } }) => getDocument({ data: _splat!, diff --git a/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.examples.$.tsx b/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.examples.$.tsx index 53e0c46c1b..378623cd08 100644 --- a/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.examples.$.tsx +++ b/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.examples.$.tsx @@ -1,10 +1,7 @@ -import { createFileRoute } from '@tanstack/solid-router' import { NotFound } from '~/components/NotFound' import { capitalize, seo } from '~/utils/seo' -export const Route = createFileRoute( - '/$project/$version/docs/framework/$framework/examples/$', -)({ +export const Route = createFileRoute({ head: ({ params }) => ({ meta: seo({ title: `${capitalize(params._splat || '')} Example | TanStack ${capitalize(params.project)} ${capitalize(params.framework)}`, diff --git a/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.index.tsx b/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.index.tsx index 3f6e4af4ef..ca9ac68ae3 100644 --- a/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.index.tsx +++ b/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.index.tsx @@ -1,9 +1,7 @@ -import { createFileRoute, redirect } from '@tanstack/solid-router' +import { redirect } from '@tanstack/solid-router' -export const Route = createFileRoute( - '/$project/$version/docs/framework/$framework/', -)({ - loader: () => { +export const Route = createFileRoute({ + beforeLoad: () => { throw redirect({ from: '/$project/$version/docs/framework/$framework/', to: '/$project/$version/docs/framework/$framework/$', diff --git a/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.tsx b/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.tsx index 62d59befae..20ff5eb2c0 100644 --- a/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.tsx +++ b/e2e/solid-start/website/src/routes/$project.$version.docs.framework.$framework.tsx @@ -1,15 +1,8 @@ -import { - Link, - Outlet, - createFileRoute, - useLocation, -} from '@tanstack/solid-router' +import { Link, Outlet, useLocation } from '@tanstack/solid-router' import { getDocumentHeads } from '~/server/document' import { getProject } from '~/server/projects' -export const Route = createFileRoute( - '/$project/$version/docs/framework/$framework', -)({ +export const Route = createFileRoute({ loader: async ({ params: { project } }) => { const library = await getProject({ data: project }) const documents = await getDocumentHeads() diff --git a/e2e/solid-start/website/src/routes/$project.$version.docs.index.tsx b/e2e/solid-start/website/src/routes/$project.$version.docs.index.tsx index ff049e373c..275b1df1cd 100644 --- a/e2e/solid-start/website/src/routes/$project.$version.docs.index.tsx +++ b/e2e/solid-start/website/src/routes/$project.$version.docs.index.tsx @@ -1,7 +1,7 @@ -import { createFileRoute, redirect } from '@tanstack/solid-router' +import { redirect } from '@tanstack/solid-router' -export const Route = createFileRoute('/$project/$version/docs/')({ - loader: () => { +export const Route = createFileRoute({ + beforeLoad: () => { throw redirect({ from: '/$project/$version/docs', to: '/$project/$version/docs/framework/$framework/$', diff --git a/e2e/solid-start/website/src/routes/$project.index.tsx b/e2e/solid-start/website/src/routes/$project.index.tsx index 6e250ac011..ee2400f806 100644 --- a/e2e/solid-start/website/src/routes/$project.index.tsx +++ b/e2e/solid-start/website/src/routes/$project.index.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, redirect } from '@tanstack/solid-router' +import { redirect } from '@tanstack/solid-router' -export const Route = createFileRoute('/$project/')({ +export const Route = createFileRoute({ loader: ({ params }) => { throw redirect({ to: '/$project/$version', diff --git a/e2e/solid-start/website/src/routes/__root.tsx b/e2e/solid-start/website/src/routes/__root.tsx index d33148818f..145a126851 100644 --- a/e2e/solid-start/website/src/routes/__root.tsx +++ b/e2e/solid-start/website/src/routes/__root.tsx @@ -1,8 +1,8 @@ import { Outlet, createRootRoute } from '@tanstack/solid-router' +import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools' import { NotFound } from '~/components/NotFound' import appCss from '~/styles/app.css?url' import { seo } from '~/utils/seo' -import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools' export const Route = createRootRoute({ head: () => ({ diff --git a/e2e/solid-start/website/src/routes/_library.$project.$version.index.tsx b/e2e/solid-start/website/src/routes/_library.$project.$version.index.tsx index 201e85f8e9..847edba780 100644 --- a/e2e/solid-start/website/src/routes/_library.$project.$version.index.tsx +++ b/e2e/solid-start/website/src/routes/_library.$project.$version.index.tsx @@ -1,6 +1,6 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' -export const Route = createFileRoute('/_library/$project/$version/')({ +export const Route = createFileRoute({ component: Page, }) @@ -14,7 +14,7 @@ function Page() {

version: {params().version}

- + Get started with our documentation.

diff --git a/e2e/solid-start/website/src/routes/_library.$project.tsx b/e2e/solid-start/website/src/routes/_library.$project.tsx index 6fdcb8e530..c057827d8b 100644 --- a/e2e/solid-start/website/src/routes/_library.$project.tsx +++ b/e2e/solid-start/website/src/routes/_library.$project.tsx @@ -1,8 +1,8 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' import { getProject } from '~/server/projects' import { seo } from '~/utils/seo' -export const Route = createFileRoute('/_library/$project')({ +export const Route = createFileRoute({ loader: ({ params: { project } }) => getProject({ data: project }), head: ({ loaderData }) => ({ meta: seo({ title: `TanStack ${loaderData?.name || 'Project'}` }), diff --git a/e2e/solid-start/website/src/routes/_library.index.tsx b/e2e/solid-start/website/src/routes/_library.index.tsx index 25bf776480..5e5b1c6cd8 100644 --- a/e2e/solid-start/website/src/routes/_library.index.tsx +++ b/e2e/solid-start/website/src/routes/_library.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/_library/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/solid-start/website/src/routes/_library.tsx b/e2e/solid-start/website/src/routes/_library.tsx index c25ae5cfe1..17ce91d83b 100644 --- a/e2e/solid-start/website/src/routes/_library.tsx +++ b/e2e/solid-start/website/src/routes/_library.tsx @@ -1,12 +1,7 @@ -import { - Link, - Outlet, - createFileRoute, - useLocation, -} from '@tanstack/solid-router' +import { Link, Outlet, useLocation } from '@tanstack/solid-router' import { getProjects } from '~/server/projects' -export const Route = createFileRoute('/_library')({ +export const Route = createFileRoute({ loader: async () => { const projects = await getProjects() return { diff --git a/e2e/solid-start/website/src/ssr.tsx b/e2e/solid-start/website/src/ssr.tsx deleted file mode 100644 index ebd14c8120..0000000000 --- a/e2e/solid-start/website/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/solid-start/server' -import { getRouterManifest } from '@tanstack/solid-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/e2e/solid-start/website/src/tanstack-start.d.ts b/e2e/solid-start/website/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/e2e/solid-start/website/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/e2e/solid-start/website/src/vite-env.d.ts b/e2e/solid-start/website/src/vite-env.d.ts new file mode 100644 index 0000000000..0b2af560d6 --- /dev/null +++ b/e2e/solid-start/website/src/vite-env.d.ts @@ -0,0 +1,4 @@ +declare module '*?url' { + const url: string + export default url +} diff --git a/e2e/solid-start/website/tests/app.spec.ts b/e2e/solid-start/website/tests/app.spec.ts index 7282086ad4..f697b5c417 100644 --- a/e2e/solid-start/website/tests/app.spec.ts +++ b/e2e/solid-start/website/tests/app.spec.ts @@ -17,3 +17,17 @@ test('resolves to the overview docs page', async ({ page }) => { '/router/latest/docs/framework/solid/overview', ) }) + +test('clicking on Documentation link navigates to the overview docs page', async ({ + page, +}) => { + await page.goto('/router') + await page.waitForLoadState('networkidle') + + const documentationLink = page.getByLabel('Documentation') + await documentationLink.click() + await page.waitForLoadState('networkidle') + + const pathname = new URL(page.url()).pathname + expect(pathname).toBe('/router/latest/docs/framework/solid/overview') +}) diff --git a/e2e/solid-start/website/vite.config.ts b/e2e/solid-start/website/vite.config.ts new file mode 100644 index 0000000000..3af67d62ad --- /dev/null +++ b/e2e/solid-start/website/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart({}), + ], +}) diff --git a/examples/react/authenticated-routes-firebase/package.json b/examples/react/authenticated-routes-firebase/package.json index ac20a7fa3c..37761f7ba5 100644 --- a/examples/react/authenticated-routes-firebase/package.json +++ b/examples/react/authenticated-routes-firebase/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "autoprefixer": "^10.4.20", "firebase": "^11.4.0", "postcss": "^8.5.1", @@ -27,6 +27,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/authenticated-routes-firebase/src/routeTree.gen.ts b/examples/react/authenticated-routes-firebase/src/routeTree.gen.ts index 173f5e2531..f1b2133f5f 100644 --- a/examples/react/authenticated-routes-firebase/src/routeTree.gen.ts +++ b/examples/react/authenticated-routes-firebase/src/routeTree.gen.ts @@ -11,52 +11,52 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as LoginImport } from './routes/login' -import { Route as AuthImport } from './routes/_auth' -import { Route as IndexImport } from './routes/index' -import { Route as AuthInvoicesImport } from './routes/_auth.invoices' -import { Route as AuthDashboardImport } from './routes/_auth.dashboard' -import { Route as AuthInvoicesIndexImport } from './routes/_auth.invoices.index' -import { Route as AuthInvoicesInvoiceIdImport } from './routes/_auth.invoices.$invoiceId' +import { Route as LoginRouteImport } from './routes/login' +import { Route as AuthRouteImport } from './routes/_auth' +import { Route as IndexRouteImport } from './routes/index' +import { Route as AuthInvoicesRouteImport } from './routes/_auth.invoices' +import { Route as AuthDashboardRouteImport } from './routes/_auth.dashboard' +import { Route as AuthInvoicesIndexRouteImport } from './routes/_auth.invoices.index' +import { Route as AuthInvoicesInvoiceIdRouteImport } from './routes/_auth.invoices.$invoiceId' // Create/Update Routes -const LoginRoute = LoginImport.update({ +const LoginRoute = LoginRouteImport.update({ id: '/login', path: '/login', getParentRoute: () => rootRoute, } as any) -const AuthRoute = AuthImport.update({ +const AuthRoute = AuthRouteImport.update({ id: '/_auth', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const AuthInvoicesRoute = AuthInvoicesImport.update({ +const AuthInvoicesRoute = AuthInvoicesRouteImport.update({ id: '/invoices', path: '/invoices', getParentRoute: () => AuthRoute, } as any) -const AuthDashboardRoute = AuthDashboardImport.update({ +const AuthDashboardRoute = AuthDashboardRouteImport.update({ id: '/dashboard', path: '/dashboard', getParentRoute: () => AuthRoute, } as any) -const AuthInvoicesIndexRoute = AuthInvoicesIndexImport.update({ +const AuthInvoicesIndexRoute = AuthInvoicesIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => AuthInvoicesRoute, } as any) -const AuthInvoicesInvoiceIdRoute = AuthInvoicesInvoiceIdImport.update({ +const AuthInvoicesInvoiceIdRoute = AuthInvoicesInvoiceIdRouteImport.update({ id: '/$invoiceId', path: '/$invoiceId', getParentRoute: () => AuthInvoicesRoute, @@ -70,50 +70,50 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_auth': { id: '/_auth' path: '' fullPath: '' - preLoaderRoute: typeof AuthImport + preLoaderRoute: typeof AuthRouteImport parentRoute: typeof rootRoute } '/login': { id: '/login' path: '/login' fullPath: '/login' - preLoaderRoute: typeof LoginImport + preLoaderRoute: typeof LoginRouteImport parentRoute: typeof rootRoute } '/_auth/dashboard': { id: '/_auth/dashboard' path: '/dashboard' fullPath: '/dashboard' - preLoaderRoute: typeof AuthDashboardImport - parentRoute: typeof AuthImport + preLoaderRoute: typeof AuthDashboardRouteImport + parentRoute: typeof AuthRouteImport } '/_auth/invoices': { id: '/_auth/invoices' path: '/invoices' fullPath: '/invoices' - preLoaderRoute: typeof AuthInvoicesImport - parentRoute: typeof AuthImport + preLoaderRoute: typeof AuthInvoicesRouteImport + parentRoute: typeof AuthRouteImport } '/_auth/invoices/$invoiceId': { id: '/_auth/invoices/$invoiceId' path: '/$invoiceId' fullPath: '/invoices/$invoiceId' - preLoaderRoute: typeof AuthInvoicesInvoiceIdImport - parentRoute: typeof AuthInvoicesImport + preLoaderRoute: typeof AuthInvoicesInvoiceIdRouteImport + parentRoute: typeof AuthInvoicesRouteImport } '/_auth/invoices/': { id: '/_auth/invoices/' path: '/' fullPath: '/invoices/' - preLoaderRoute: typeof AuthInvoicesIndexImport - parentRoute: typeof AuthInvoicesImport + preLoaderRoute: typeof AuthInvoicesIndexRouteImport + parentRoute: typeof AuthInvoicesRouteImport } } } diff --git a/examples/react/authenticated-routes-firebase/src/routes/_auth.dashboard.tsx b/examples/react/authenticated-routes-firebase/src/routes/_auth.dashboard.tsx index a4c6fc7cdf..2de930e45f 100644 --- a/examples/react/authenticated-routes-firebase/src/routes/_auth.dashboard.tsx +++ b/examples/react/authenticated-routes-firebase/src/routes/_auth.dashboard.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' import { useAuth } from '../auth' diff --git a/examples/react/authenticated-routes-firebase/src/routes/_auth.invoices.$invoiceId.tsx b/examples/react/authenticated-routes-firebase/src/routes/_auth.invoices.$invoiceId.tsx index 896133db24..09fdda218d 100644 --- a/examples/react/authenticated-routes-firebase/src/routes/_auth.invoices.$invoiceId.tsx +++ b/examples/react/authenticated-routes-firebase/src/routes/_auth.invoices.$invoiceId.tsx @@ -1,5 +1,6 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' + import { fetchInvoiceById } from '../posts' export const Route = createFileRoute('/_auth/invoices/$invoiceId')({ diff --git a/examples/react/authenticated-routes-firebase/src/routes/_auth.invoices.index.tsx b/examples/react/authenticated-routes-firebase/src/routes/_auth.invoices.index.tsx index 5ba27d4cc0..3bb65e5688 100644 --- a/examples/react/authenticated-routes-firebase/src/routes/_auth.invoices.index.tsx +++ b/examples/react/authenticated-routes-firebase/src/routes/_auth.invoices.index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/_auth/invoices/')({ component: () =>
Select an invoice to view it!
, diff --git a/examples/react/authenticated-routes-firebase/src/routes/_auth.invoices.tsx b/examples/react/authenticated-routes-firebase/src/routes/_auth.invoices.tsx index c3cda59142..d7b13eaebb 100644 --- a/examples/react/authenticated-routes-firebase/src/routes/_auth.invoices.tsx +++ b/examples/react/authenticated-routes-firebase/src/routes/_auth.invoices.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchInvoices } from '../posts' diff --git a/examples/react/authenticated-routes-firebase/src/routes/_auth.tsx b/examples/react/authenticated-routes-firebase/src/routes/_auth.tsx index a218577627..09c5b1560d 100644 --- a/examples/react/authenticated-routes-firebase/src/routes/_auth.tsx +++ b/examples/react/authenticated-routes-firebase/src/routes/_auth.tsx @@ -1,10 +1,5 @@ -import { - Link, - Outlet, - createFileRoute, - redirect, - useRouter, -} from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link, Outlet, redirect, useRouter } from '@tanstack/react-router' import { useAuth } from '../auth' export const Route = createFileRoute('/_auth')({ diff --git a/examples/react/authenticated-routes-firebase/src/routes/index.tsx b/examples/react/authenticated-routes-firebase/src/routes/index.tsx index e9264fed15..fa127b12f7 100644 --- a/examples/react/authenticated-routes-firebase/src/routes/index.tsx +++ b/examples/react/authenticated-routes-firebase/src/routes/index.tsx @@ -1,4 +1,5 @@ -import { Link, createFileRoute, redirect } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link, redirect } from '@tanstack/react-router' export const Route = createFileRoute('/')({ beforeLoad: ({ context }) => { diff --git a/examples/react/authenticated-routes-firebase/src/routes/login.tsx b/examples/react/authenticated-routes-firebase/src/routes/login.tsx index 1c665b9fbc..6bdecc4747 100644 --- a/examples/react/authenticated-routes-firebase/src/routes/login.tsx +++ b/examples/react/authenticated-routes-firebase/src/routes/login.tsx @@ -1,10 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { - createFileRoute, - redirect, - useRouter, - useRouterState, -} from '@tanstack/react-router' +import { redirect, useRouter, useRouterState } from '@tanstack/react-router' import { z } from 'zod' import { useAuth } from '../auth' diff --git a/examples/react/authenticated-routes-firebase/vite.config.js b/examples/react/authenticated-routes-firebase/vite.config.js index f22a7fa76f..47e327b746 100644 --- a/examples/react/authenticated-routes-firebase/vite.config.js +++ b/examples/react/authenticated-routes-firebase/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'react', autoCodeSplitting: true, }), diff --git a/examples/react/authenticated-routes/package.json b/examples/react/authenticated-routes/package.json index 5bedf2de76..ae8d80c341 100644 --- a/examples/react/authenticated-routes/package.json +++ b/examples/react/authenticated-routes/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -25,6 +25,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/authenticated-routes/src/routeTree.gen.ts b/examples/react/authenticated-routes/src/routeTree.gen.ts index 173f5e2531..f1b2133f5f 100644 --- a/examples/react/authenticated-routes/src/routeTree.gen.ts +++ b/examples/react/authenticated-routes/src/routeTree.gen.ts @@ -11,52 +11,52 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as LoginImport } from './routes/login' -import { Route as AuthImport } from './routes/_auth' -import { Route as IndexImport } from './routes/index' -import { Route as AuthInvoicesImport } from './routes/_auth.invoices' -import { Route as AuthDashboardImport } from './routes/_auth.dashboard' -import { Route as AuthInvoicesIndexImport } from './routes/_auth.invoices.index' -import { Route as AuthInvoicesInvoiceIdImport } from './routes/_auth.invoices.$invoiceId' +import { Route as LoginRouteImport } from './routes/login' +import { Route as AuthRouteImport } from './routes/_auth' +import { Route as IndexRouteImport } from './routes/index' +import { Route as AuthInvoicesRouteImport } from './routes/_auth.invoices' +import { Route as AuthDashboardRouteImport } from './routes/_auth.dashboard' +import { Route as AuthInvoicesIndexRouteImport } from './routes/_auth.invoices.index' +import { Route as AuthInvoicesInvoiceIdRouteImport } from './routes/_auth.invoices.$invoiceId' // Create/Update Routes -const LoginRoute = LoginImport.update({ +const LoginRoute = LoginRouteImport.update({ id: '/login', path: '/login', getParentRoute: () => rootRoute, } as any) -const AuthRoute = AuthImport.update({ +const AuthRoute = AuthRouteImport.update({ id: '/_auth', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const AuthInvoicesRoute = AuthInvoicesImport.update({ +const AuthInvoicesRoute = AuthInvoicesRouteImport.update({ id: '/invoices', path: '/invoices', getParentRoute: () => AuthRoute, } as any) -const AuthDashboardRoute = AuthDashboardImport.update({ +const AuthDashboardRoute = AuthDashboardRouteImport.update({ id: '/dashboard', path: '/dashboard', getParentRoute: () => AuthRoute, } as any) -const AuthInvoicesIndexRoute = AuthInvoicesIndexImport.update({ +const AuthInvoicesIndexRoute = AuthInvoicesIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => AuthInvoicesRoute, } as any) -const AuthInvoicesInvoiceIdRoute = AuthInvoicesInvoiceIdImport.update({ +const AuthInvoicesInvoiceIdRoute = AuthInvoicesInvoiceIdRouteImport.update({ id: '/$invoiceId', path: '/$invoiceId', getParentRoute: () => AuthInvoicesRoute, @@ -70,50 +70,50 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_auth': { id: '/_auth' path: '' fullPath: '' - preLoaderRoute: typeof AuthImport + preLoaderRoute: typeof AuthRouteImport parentRoute: typeof rootRoute } '/login': { id: '/login' path: '/login' fullPath: '/login' - preLoaderRoute: typeof LoginImport + preLoaderRoute: typeof LoginRouteImport parentRoute: typeof rootRoute } '/_auth/dashboard': { id: '/_auth/dashboard' path: '/dashboard' fullPath: '/dashboard' - preLoaderRoute: typeof AuthDashboardImport - parentRoute: typeof AuthImport + preLoaderRoute: typeof AuthDashboardRouteImport + parentRoute: typeof AuthRouteImport } '/_auth/invoices': { id: '/_auth/invoices' path: '/invoices' fullPath: '/invoices' - preLoaderRoute: typeof AuthInvoicesImport - parentRoute: typeof AuthImport + preLoaderRoute: typeof AuthInvoicesRouteImport + parentRoute: typeof AuthRouteImport } '/_auth/invoices/$invoiceId': { id: '/_auth/invoices/$invoiceId' path: '/$invoiceId' fullPath: '/invoices/$invoiceId' - preLoaderRoute: typeof AuthInvoicesInvoiceIdImport - parentRoute: typeof AuthInvoicesImport + preLoaderRoute: typeof AuthInvoicesInvoiceIdRouteImport + parentRoute: typeof AuthInvoicesRouteImport } '/_auth/invoices/': { id: '/_auth/invoices/' path: '/' fullPath: '/invoices/' - preLoaderRoute: typeof AuthInvoicesIndexImport - parentRoute: typeof AuthInvoicesImport + preLoaderRoute: typeof AuthInvoicesIndexRouteImport + parentRoute: typeof AuthInvoicesRouteImport } } } diff --git a/examples/react/authenticated-routes/src/routes/_auth.dashboard.tsx b/examples/react/authenticated-routes/src/routes/_auth.dashboard.tsx index 51fbf3e81a..2ac2da579a 100644 --- a/examples/react/authenticated-routes/src/routes/_auth.dashboard.tsx +++ b/examples/react/authenticated-routes/src/routes/_auth.dashboard.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' import { useAuth } from '../auth' diff --git a/examples/react/authenticated-routes/src/routes/_auth.invoices.$invoiceId.tsx b/examples/react/authenticated-routes/src/routes/_auth.invoices.$invoiceId.tsx index 15b502d5e9..2ac086c10a 100644 --- a/examples/react/authenticated-routes/src/routes/_auth.invoices.$invoiceId.tsx +++ b/examples/react/authenticated-routes/src/routes/_auth.invoices.$invoiceId.tsx @@ -1,5 +1,6 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' + import { fetchInvoiceById } from '../posts' export const Route = createFileRoute('/_auth/invoices/$invoiceId')({ diff --git a/examples/react/authenticated-routes/src/routes/_auth.invoices.index.tsx b/examples/react/authenticated-routes/src/routes/_auth.invoices.index.tsx index 5ba27d4cc0..3bb65e5688 100644 --- a/examples/react/authenticated-routes/src/routes/_auth.invoices.index.tsx +++ b/examples/react/authenticated-routes/src/routes/_auth.invoices.index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/_auth/invoices/')({ component: () =>
Select an invoice to view it!
, diff --git a/examples/react/authenticated-routes/src/routes/_auth.invoices.tsx b/examples/react/authenticated-routes/src/routes/_auth.invoices.tsx index c3cda59142..d7b13eaebb 100644 --- a/examples/react/authenticated-routes/src/routes/_auth.invoices.tsx +++ b/examples/react/authenticated-routes/src/routes/_auth.invoices.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchInvoices } from '../posts' diff --git a/examples/react/authenticated-routes/src/routes/_auth.tsx b/examples/react/authenticated-routes/src/routes/_auth.tsx index 00c97cbeb7..8d2ff0c145 100644 --- a/examples/react/authenticated-routes/src/routes/_auth.tsx +++ b/examples/react/authenticated-routes/src/routes/_auth.tsx @@ -1,11 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { - Link, - Outlet, - createFileRoute, - redirect, - useRouter, -} from '@tanstack/react-router' +import { Link, Outlet, redirect, useRouter } from '@tanstack/react-router' import { useAuth } from '../auth' diff --git a/examples/react/authenticated-routes/src/routes/index.tsx b/examples/react/authenticated-routes/src/routes/index.tsx index f5fc871378..b4d88a793f 100644 --- a/examples/react/authenticated-routes/src/routes/index.tsx +++ b/examples/react/authenticated-routes/src/routes/index.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' export const Route = createFileRoute('/')({ component: HomeComponent, diff --git a/examples/react/authenticated-routes/src/routes/login.tsx b/examples/react/authenticated-routes/src/routes/login.tsx index dd78f66f9c..fdaba7cc11 100644 --- a/examples/react/authenticated-routes/src/routes/login.tsx +++ b/examples/react/authenticated-routes/src/routes/login.tsx @@ -1,10 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { - createFileRoute, - redirect, - useRouter, - useRouterState, -} from '@tanstack/react-router' +import { redirect, useRouter, useRouterState } from '@tanstack/react-router' import { z } from 'zod' import { useAuth } from '../auth' diff --git a/examples/react/authenticated-routes/vite.config.js b/examples/react/authenticated-routes/vite.config.js index f22a7fa76f..47e327b746 100644 --- a/examples/react/authenticated-routes/vite.config.js +++ b/examples/react/authenticated-routes/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'react', autoCodeSplitting: true, }), diff --git a/examples/react/basic-default-search-params/package.json b/examples/react/basic-default-search-params/package.json index 4ac49178e6..c4d9cd5f00 100644 --- a/examples/react/basic-default-search-params/package.json +++ b/examples/react/basic-default-search-params/package.json @@ -10,8 +10,8 @@ }, "dependencies": { "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -25,6 +25,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/basic-devtools-panel/package.json b/examples/react/basic-devtools-panel/package.json index 6925019d18..6a2aa47b6d 100644 --- a/examples/react/basic-devtools-panel/package.json +++ b/examples/react/basic-devtools-panel/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "@tanstack/react-query-devtools": "^5.67.2", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -24,6 +24,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/basic-file-based/package.json b/examples/react/basic-file-based/package.json index 53e01ca07c..cca2d77598 100644 --- a/examples/react/basic-file-based/package.json +++ b/examples/react/basic-file-based/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -25,6 +25,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/basic-file-based/src/routeTree.gen.ts b/examples/react/basic-file-based/src/routeTree.gen.ts index 1f98acd3e4..b2e40e20c7 100644 --- a/examples/react/basic-file-based/src/routeTree.gen.ts +++ b/examples/react/basic-file-based/src/routeTree.gen.ts @@ -11,69 +11,68 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as AnchorImport } from './routes/anchor' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as PostsRouteImport } from './routes/posts.route' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as PathlessLayoutNestedLayoutImport } from './routes/_pathlessLayout/_nested-layout' -import { Route as PathlessLayoutNestedLayoutRouteBImport } from './routes/_pathlessLayout/_nested-layout/route-b' -import { Route as PathlessLayoutNestedLayoutRouteAImport } from './routes/_pathlessLayout/_nested-layout/route-a' +import { Route as AnchorRouteImport } from './routes/anchor' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as PostsRouteRouteImport } from './routes/posts.route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' +import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' +import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' // Create/Update Routes -const AnchorRoute = AnchorImport.update({ +const AnchorRoute = AnchorRouteImport.update({ id: '/anchor', path: '/anchor', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const PostsRouteRoute = PostsRouteImport.update({ +const PostsRouteRoute = PostsRouteRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRouteRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRouteRoute, } as any) -const PathlessLayoutNestedLayoutRoute = PathlessLayoutNestedLayoutImport.update( - { +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ id: '/_nested-layout', getParentRoute: () => PathlessLayoutRoute, - } as any, -) + } as any) const PathlessLayoutNestedLayoutRouteBRoute = - PathlessLayoutNestedLayoutRouteBImport.update({ + PathlessLayoutNestedLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutNestedLayoutRoute, } as any) const PathlessLayoutNestedLayoutRouteARoute = - PathlessLayoutNestedLayoutRouteAImport.update({ + PathlessLayoutNestedLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutNestedLayoutRoute, @@ -87,64 +86,64 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsRouteRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/anchor': { id: '/anchor' path: '/anchor' fullPath: '/anchor' - preLoaderRoute: typeof AnchorImport + preLoaderRoute: typeof AnchorRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout/_nested-layout': { id: '/_pathlessLayout/_nested-layout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutNestedLayoutImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteRouteImport } '/_pathlessLayout/_nested-layout/route-a': { id: '/_pathlessLayout/_nested-layout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteAImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/_pathlessLayout/_nested-layout/route-b': { id: '/_pathlessLayout/_nested-layout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } } } diff --git a/examples/react/basic-file-based/src/routes/_pathlessLayout.tsx b/examples/react/basic-file-based/src/routes/_pathlessLayout.tsx index 202070f1ff..1e1ef2ebe1 100644 --- a/examples/react/basic-file-based/src/routes/_pathlessLayout.tsx +++ b/examples/react/basic-file-based/src/routes/_pathlessLayout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_pathlessLayout')({ component: LayoutComponent, diff --git a/examples/react/basic-file-based/src/routes/_pathlessLayout/_nested-layout.tsx b/examples/react/basic-file-based/src/routes/_pathlessLayout/_nested-layout.tsx index c5bcffd5a4..9c345694ab 100644 --- a/examples/react/basic-file-based/src/routes/_pathlessLayout/_nested-layout.tsx +++ b/examples/react/basic-file-based/src/routes/_pathlessLayout/_nested-layout.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({ component: LayoutComponent, diff --git a/examples/react/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/examples/react/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx index 5649f77d8e..6b59dbc46f 100644 --- a/examples/react/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +++ b/examples/react/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')( { component: LayoutAComponent, diff --git a/examples/react/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/examples/react/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx index 742e48bfb4..50f864f617 100644 --- a/examples/react/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +++ b/examples/react/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')( { component: LayoutBComponent, diff --git a/examples/react/basic-file-based/src/routes/anchor.tsx b/examples/react/basic-file-based/src/routes/anchor.tsx index fbe16ed55c..b865343adc 100644 --- a/examples/react/basic-file-based/src/routes/anchor.tsx +++ b/examples/react/basic-file-based/src/routes/anchor.tsx @@ -1,10 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import { useLayoutEffect, useRef, useState } from 'react' -import { - Link, - createFileRoute, - useLocation, - useNavigate, -} from '@tanstack/react-router' +import { Link, useLocation, useNavigate } from '@tanstack/react-router' export const Route = createFileRoute('/anchor')({ component: AnchorComponent, diff --git a/examples/react/basic-file-based/src/routes/index.tsx b/examples/react/basic-file-based/src/routes/index.tsx index eac82a9174..0a5b7572ba 100644 --- a/examples/react/basic-file-based/src/routes/index.tsx +++ b/examples/react/basic-file-based/src/routes/index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/')({ component: Home, diff --git a/examples/react/basic-file-based/src/routes/posts.$postId.tsx b/examples/react/basic-file-based/src/routes/posts.$postId.tsx index cded91ef96..956ca50ecd 100644 --- a/examples/react/basic-file-based/src/routes/posts.$postId.tsx +++ b/examples/react/basic-file-based/src/routes/posts.$postId.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import { fetchPost } from '../posts' import type { ErrorComponentProps } from '@tanstack/react-router' diff --git a/examples/react/basic-file-based/src/routes/posts.index.tsx b/examples/react/basic-file-based/src/routes/posts.index.tsx index 056433ca0a..c6b65f1892 100644 --- a/examples/react/basic-file-based/src/routes/posts.index.tsx +++ b/examples/react/basic-file-based/src/routes/posts.index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, diff --git a/examples/react/basic-file-based/src/routes/posts.route.tsx b/examples/react/basic-file-based/src/routes/posts.route.tsx index 0115fc8063..ab5c2ac99f 100644 --- a/examples/react/basic-file-based/src/routes/posts.route.tsx +++ b/examples/react/basic-file-based/src/routes/posts.route.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../posts' export const Route = createFileRoute('/posts')({ diff --git a/examples/react/basic-file-based/vite.config.js b/examples/react/basic-file-based/vite.config.js index f22a7fa76f..47e327b746 100644 --- a/examples/react/basic-file-based/vite.config.js +++ b/examples/react/basic-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'react', autoCodeSplitting: true, }), diff --git a/examples/react/basic-non-nested-devtools/package.json b/examples/react/basic-non-nested-devtools/package.json index 2b45e427a8..b59b7bddca 100644 --- a/examples/react/basic-non-nested-devtools/package.json +++ b/examples/react/basic-non-nested-devtools/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -23,6 +23,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/basic-react-query-file-based/package.json b/examples/react/basic-react-query-file-based/package.json index 0376b204be..21bb9abc0f 100644 --- a/examples/react/basic-react-query-file-based/package.json +++ b/examples/react/basic-react-query-file-based/package.json @@ -11,9 +11,9 @@ "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -27,6 +27,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/basic-react-query-file-based/src/routeTree.gen.ts b/examples/react/basic-react-query-file-based/src/routeTree.gen.ts index 67944b5f0c..7f257ecb1c 100644 --- a/examples/react/basic-react-query-file-based/src/routeTree.gen.ts +++ b/examples/react/basic-react-query-file-based/src/routeTree.gen.ts @@ -11,62 +11,61 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as PostsRouteImport } from './routes/posts.route' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as PathlessLayoutNestedLayoutImport } from './routes/_pathlessLayout/_nested-layout' -import { Route as PathlessLayoutNestedLayoutRouteBImport } from './routes/_pathlessLayout/_nested-layout/route-b' -import { Route as PathlessLayoutNestedLayoutRouteAImport } from './routes/_pathlessLayout/_nested-layout/route-a' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as PostsRouteRouteImport } from './routes/posts.route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' +import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' +import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' // Create/Update Routes -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const PostsRouteRoute = PostsRouteImport.update({ +const PostsRouteRoute = PostsRouteRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRouteRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRouteRoute, } as any) -const PathlessLayoutNestedLayoutRoute = PathlessLayoutNestedLayoutImport.update( - { +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ id: '/_nested-layout', getParentRoute: () => PathlessLayoutRoute, - } as any, -) + } as any) const PathlessLayoutNestedLayoutRouteBRoute = - PathlessLayoutNestedLayoutRouteBImport.update({ + PathlessLayoutNestedLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutNestedLayoutRoute, } as any) const PathlessLayoutNestedLayoutRouteARoute = - PathlessLayoutNestedLayoutRouteAImport.update({ + PathlessLayoutNestedLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutNestedLayoutRoute, @@ -80,57 +79,57 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsRouteRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout/_nested-layout': { id: '/_pathlessLayout/_nested-layout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutNestedLayoutImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteRouteImport } '/_pathlessLayout/_nested-layout/route-a': { id: '/_pathlessLayout/_nested-layout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteAImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/_pathlessLayout/_nested-layout/route-b': { id: '/_pathlessLayout/_nested-layout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } } } diff --git a/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout.tsx b/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout.tsx index c3b12442b8..29a66a7611 100644 --- a/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout.tsx +++ b/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_pathlessLayout')({ component: LayoutComponent, diff --git a/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout/_nested-layout.tsx b/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout/_nested-layout.tsx index 9a48b73a46..3175f0a80e 100644 --- a/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout/_nested-layout.tsx +++ b/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout/_nested-layout.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({ component: LayoutComponent, diff --git a/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx index 5649f77d8e..6b59dbc46f 100644 --- a/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +++ b/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')( { component: LayoutAComponent, diff --git a/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx index 742e48bfb4..50f864f617 100644 --- a/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +++ b/examples/react/basic-react-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')( { component: LayoutBComponent, diff --git a/examples/react/basic-react-query-file-based/src/routes/index.tsx b/examples/react/basic-react-query-file-based/src/routes/index.tsx index eac82a9174..0a5b7572ba 100644 --- a/examples/react/basic-react-query-file-based/src/routes/index.tsx +++ b/examples/react/basic-react-query-file-based/src/routes/index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/')({ component: Home, diff --git a/examples/react/basic-react-query-file-based/src/routes/posts.$postId.tsx b/examples/react/basic-react-query-file-based/src/routes/posts.$postId.tsx index 4cf6beca88..9c7e89fbce 100644 --- a/examples/react/basic-react-query-file-based/src/routes/posts.$postId.tsx +++ b/examples/react/basic-react-query-file-based/src/routes/posts.$postId.tsx @@ -1,9 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { - ErrorComponent, - createFileRoute, - useRouter, -} from '@tanstack/react-router' +import { ErrorComponent, useRouter } from '@tanstack/react-router' import { useQueryErrorResetBoundary, useSuspenseQuery, diff --git a/examples/react/basic-react-query-file-based/src/routes/posts.index.tsx b/examples/react/basic-react-query-file-based/src/routes/posts.index.tsx index 056433ca0a..c6b65f1892 100644 --- a/examples/react/basic-react-query-file-based/src/routes/posts.index.tsx +++ b/examples/react/basic-react-query-file-based/src/routes/posts.index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, diff --git a/examples/react/basic-react-query-file-based/src/routes/posts.route.tsx b/examples/react/basic-react-query-file-based/src/routes/posts.route.tsx index 0ba745c0ab..220cccd027 100644 --- a/examples/react/basic-react-query-file-based/src/routes/posts.route.tsx +++ b/examples/react/basic-react-query-file-based/src/routes/posts.route.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { useSuspenseQuery } from '@tanstack/react-query' import { postsQueryOptions } from '../postsQueryOptions' diff --git a/examples/react/basic-react-query-file-based/vite.config.js b/examples/react/basic-react-query-file-based/vite.config.js index b819774577..ab615485ae 100644 --- a/examples/react/basic-react-query-file-based/vite.config.js +++ b/examples/react/basic-react-query-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ target: 'react', autoCodeSplitting: true }), react(), ], }) diff --git a/examples/react/basic-react-query/package.json b/examples/react/basic-react-query/package.json index 8cdbbd949c..9e4b8b2864 100644 --- a/examples/react/basic-react-query/package.json +++ b/examples/react/basic-react-query/package.json @@ -11,8 +11,8 @@ "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -25,6 +25,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/basic-ssr-file-based/package.json b/examples/react/basic-ssr-file-based/package.disabled.json similarity index 83% rename from examples/react/basic-ssr-file-based/package.json rename to examples/react/basic-ssr-file-based/package.disabled.json index 74062d8926..13e5720a64 100644 --- a/examples/react/basic-ssr-file-based/package.json +++ b/examples/react/basic-ssr-file-based/package.disabled.json @@ -11,10 +11,10 @@ "debug": "node --inspect-brk server" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.120.5", + "@tanstack/react-router-devtools": "^1.120.5", + "@tanstack/router-plugin": "^1.120.5", + "@tanstack/react-start": "^1.120.5", "get-port": "^7.1.0", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -32,7 +32,7 @@ "isbot": "^5.1.22", "node-fetch": "^3.3.2", "serve-static": "^1.16.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "@types/react": "^19.0.8", "@types/react-dom": "^19.0.1" } diff --git a/examples/react/basic-ssr-file-based/src/routeTree.gen.ts b/examples/react/basic-ssr-file-based/src/routeTree.gen.ts index 7092dee6de..4ff6d62320 100644 --- a/examples/react/basic-ssr-file-based/src/routeTree.gen.ts +++ b/examples/react/basic-ssr-file-based/src/routeTree.gen.ts @@ -10,40 +10,41 @@ // Import Routes +import type { FileRoutesByPath, CreateFileRoute } from '@tanstack/react-router' import { Route as rootRoute } from './routes/__root' -import { Route as ErrorImport } from './routes/error' -import { Route as PostsRouteImport } from './routes/posts/route' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts/index' -import { Route as PostsPostIdImport } from './routes/posts/$postId' +import { Route as ErrorRouteImport } from './routes/error' +import { Route as PostsRouteRouteImport } from './routes/posts/route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts/index' +import { Route as PostsPostIdRouteImport } from './routes/posts/$postId' // Create/Update Routes -const ErrorRoute = ErrorImport.update({ +const ErrorRoute = ErrorRouteImport.update({ id: '/error', path: '/error', getParentRoute: () => rootRoute, } as any) -const PostsRouteRoute = PostsRouteImport.update({ +const PostsRouteRoute = PostsRouteRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRouteRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRouteRoute, @@ -57,40 +58,88 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsRouteRouteImport parentRoute: typeof rootRoute } '/error': { id: '/error' path: '/error' fullPath: '/error' - preLoaderRoute: typeof ErrorImport + preLoaderRoute: typeof ErrorRouteImport parentRoute: typeof rootRoute } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/posts/route' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/error' { + const createFileRoute: CreateFileRoute< + '/error', + FileRoutesByPath['/error']['parentRoute'], + FileRoutesByPath['/error']['id'], + FileRoutesByPath['/error']['path'], + FileRoutesByPath['/error']['fullPath'] + > +} +declare module './routes/posts/$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/posts/index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} + // Create and export the route tree interface PostsRouteRouteChildren { @@ -156,6 +205,9 @@ export const routeTree = rootRoute ._addFileChildren(rootRouteChildren) ._addFileTypes() +// @ts-ignore +import type * as ServerTypes from '../.tanstack-start/server-routes/routeTree.gen.ts' + /* ROUTE_MANIFEST_START { "routes": { diff --git a/examples/react/basic-ssr-file-based/src/routes/error.tsx b/examples/react/basic-ssr-file-based/src/routes/error.tsx index 52d42f2a99..33412fe3da 100644 --- a/examples/react/basic-ssr-file-based/src/routes/error.tsx +++ b/examples/react/basic-ssr-file-based/src/routes/error.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -export const Route = createFileRoute('/error')({ +export const Route = createFileRoute({ component: ErrorComponent, loader: async () => { if (Math.random() > 0.5) throw new Error('Random error!') diff --git a/examples/react/basic-ssr-file-based/src/routes/index.tsx b/examples/react/basic-ssr-file-based/src/routes/index.tsx index eac7746031..b27dfd977a 100644 --- a/examples/react/basic-ssr-file-based/src/routes/index.tsx +++ b/examples/react/basic-ssr-file-based/src/routes/index.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: IndexComponent, }) diff --git a/examples/react/basic-ssr-file-based/src/routes/posts/$postId.tsx b/examples/react/basic-ssr-file-based/src/routes/posts/$postId.tsx index b045eb784f..4f474865dd 100644 --- a/examples/react/basic-ssr-file-based/src/routes/posts/$postId.tsx +++ b/examples/react/basic-ssr-file-based/src/routes/posts/$postId.tsx @@ -1,8 +1,7 @@ -import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' import type { PostType } from '../posts' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params }) => { console.info(`Fetching post with id ${params.postId}...`) diff --git a/examples/react/basic-ssr-file-based/src/routes/posts/index.tsx b/examples/react/basic-ssr-file-based/src/routes/posts/index.tsx index 5b5f08f95b..13529228bb 100644 --- a/examples/react/basic-ssr-file-based/src/routes/posts/index.tsx +++ b/examples/react/basic-ssr-file-based/src/routes/posts/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/examples/react/basic-ssr-file-based/src/routes/posts/route.tsx b/examples/react/basic-ssr-file-based/src/routes/posts/route.tsx index 3699478d0a..4900ccb437 100644 --- a/examples/react/basic-ssr-file-based/src/routes/posts/route.tsx +++ b/examples/react/basic-ssr-file-based/src/routes/posts/route.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' export type PostType = { id: string @@ -7,7 +7,7 @@ export type PostType = { body: string } -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: async () => { console.info('Fetching posts...') await new Promise((r) => diff --git a/examples/react/basic-ssr-file-based/vite.config.js b/examples/react/basic-ssr-file-based/vite.config.js index b819774577..ab615485ae 100644 --- a/examples/react/basic-ssr-file-based/vite.config.js +++ b/examples/react/basic-ssr-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ target: 'react', autoCodeSplitting: true }), react(), ], }) diff --git a/examples/react/basic-ssr-streaming-file-based/package.json b/examples/react/basic-ssr-streaming-file-based/package.disabled.json similarity index 84% rename from examples/react/basic-ssr-streaming-file-based/package.json rename to examples/react/basic-ssr-streaming-file-based/package.disabled.json index a29711ecc0..49ba54908c 100644 --- a/examples/react/basic-ssr-streaming-file-based/package.json +++ b/examples/react/basic-ssr-streaming-file-based/package.disabled.json @@ -11,10 +11,10 @@ "debug": "node --inspect-brk server" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.120.5", + "@tanstack/react-router-devtools": "^1.120.5", + "@tanstack/router-plugin": "^1.120.5", + "@tanstack/react-start": "^1.120.5", "get-port": "^7.1.0", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -33,7 +33,7 @@ "isbot": "^5.1.22", "node-fetch": "^3.3.2", "serve-static": "^1.16.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "@types/react": "^19.0.8", "@types/react-dom": "^19.0.1" } diff --git a/examples/react/basic-ssr-streaming-file-based/src/routeTree.gen.ts b/examples/react/basic-ssr-streaming-file-based/src/routeTree.gen.ts index 7092dee6de..4ff6d62320 100644 --- a/examples/react/basic-ssr-streaming-file-based/src/routeTree.gen.ts +++ b/examples/react/basic-ssr-streaming-file-based/src/routeTree.gen.ts @@ -10,40 +10,41 @@ // Import Routes +import type { FileRoutesByPath, CreateFileRoute } from '@tanstack/react-router' import { Route as rootRoute } from './routes/__root' -import { Route as ErrorImport } from './routes/error' -import { Route as PostsRouteImport } from './routes/posts/route' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts/index' -import { Route as PostsPostIdImport } from './routes/posts/$postId' +import { Route as ErrorRouteImport } from './routes/error' +import { Route as PostsRouteRouteImport } from './routes/posts/route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts/index' +import { Route as PostsPostIdRouteImport } from './routes/posts/$postId' // Create/Update Routes -const ErrorRoute = ErrorImport.update({ +const ErrorRoute = ErrorRouteImport.update({ id: '/error', path: '/error', getParentRoute: () => rootRoute, } as any) -const PostsRouteRoute = PostsRouteImport.update({ +const PostsRouteRoute = PostsRouteRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRouteRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRouteRoute, @@ -57,40 +58,88 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsRouteRouteImport parentRoute: typeof rootRoute } '/error': { id: '/error' path: '/error' fullPath: '/error' - preLoaderRoute: typeof ErrorImport + preLoaderRoute: typeof ErrorRouteImport parentRoute: typeof rootRoute } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/posts/route' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/error' { + const createFileRoute: CreateFileRoute< + '/error', + FileRoutesByPath['/error']['parentRoute'], + FileRoutesByPath['/error']['id'], + FileRoutesByPath['/error']['path'], + FileRoutesByPath['/error']['fullPath'] + > +} +declare module './routes/posts/$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/posts/index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} + // Create and export the route tree interface PostsRouteRouteChildren { @@ -156,6 +205,9 @@ export const routeTree = rootRoute ._addFileChildren(rootRouteChildren) ._addFileTypes() +// @ts-ignore +import type * as ServerTypes from '../.tanstack-start/server-routes/routeTree.gen.ts' + /* ROUTE_MANIFEST_START { "routes": { diff --git a/examples/react/basic-ssr-streaming-file-based/src/routes/error.tsx b/examples/react/basic-ssr-streaming-file-based/src/routes/error.tsx index 8ab6d2b52d..a8f14563d2 100644 --- a/examples/react/basic-ssr-streaming-file-based/src/routes/error.tsx +++ b/examples/react/basic-ssr-streaming-file-based/src/routes/error.tsx @@ -1,4 +1,4 @@ -import { Await, createFileRoute } from '@tanstack/react-router' +import { Await } from '@tanstack/react-router' import * as React from 'react' async function loadData() { @@ -7,7 +7,7 @@ async function loadData() { return 'Hello!' } -export const Route = createFileRoute('/error')({ +export const Route = createFileRoute({ component: ErrorComponent, loader: () => { if (Math.random() > 0.5) throw new Error('Random error!') diff --git a/examples/react/basic-ssr-streaming-file-based/src/routes/index.tsx b/examples/react/basic-ssr-streaming-file-based/src/routes/index.tsx index 50c2706a26..33f887a27b 100644 --- a/examples/react/basic-ssr-streaming-file-based/src/routes/index.tsx +++ b/examples/react/basic-ssr-streaming-file-based/src/routes/index.tsx @@ -1,7 +1,7 @@ -import { Await, createFileRoute } from '@tanstack/react-router' +import { Await } from '@tanstack/react-router' import * as React from 'react' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ loader: () => ({ date: new Date(), deferred: new Promise<{ date: Date }>((r) => diff --git a/examples/react/basic-ssr-streaming-file-based/src/routes/posts/$postId.tsx b/examples/react/basic-ssr-streaming-file-based/src/routes/posts/$postId.tsx index 0a3f603008..9466546c60 100644 --- a/examples/react/basic-ssr-streaming-file-based/src/routes/posts/$postId.tsx +++ b/examples/react/basic-ssr-streaming-file-based/src/routes/posts/$postId.tsx @@ -1,4 +1,4 @@ -import { Await, createFileRoute, notFound } from '@tanstack/react-router' +import { Await, notFound } from '@tanstack/react-router' import * as React from 'react' import type { PostType } from './route' @@ -32,7 +32,7 @@ async function fetchComments(postId: string) { ).then((r) => r.json() as Promise>) } -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => { const commentsPromise = fetchComments(postId) const post = await fetchPostById(postId) diff --git a/examples/react/basic-ssr-streaming-file-based/src/routes/posts/index.tsx b/examples/react/basic-ssr-streaming-file-based/src/routes/posts/index.tsx index 2aa298c265..a88aaa8f26 100644 --- a/examples/react/basic-ssr-streaming-file-based/src/routes/posts/index.tsx +++ b/examples/react/basic-ssr-streaming-file-based/src/routes/posts/index.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, wrapInSuspense: true, errorComponent: ({ error }) => { diff --git a/examples/react/basic-ssr-streaming-file-based/src/routes/posts/route.tsx b/examples/react/basic-ssr-streaming-file-based/src/routes/posts/route.tsx index ad2b0082ad..ceb14625f2 100644 --- a/examples/react/basic-ssr-streaming-file-based/src/routes/posts/route.tsx +++ b/examples/react/basic-ssr-streaming-file-based/src/routes/posts/route.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' export type PostType = { id: string @@ -7,7 +7,7 @@ export type PostType = { body: string } -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: async () => { console.info('Fetching posts...') await new Promise((r) => diff --git a/examples/react/basic-ssr-streaming-file-based/vite.config.js b/examples/react/basic-ssr-streaming-file-based/vite.config.js index b819774577..ab615485ae 100644 --- a/examples/react/basic-ssr-streaming-file-based/vite.config.js +++ b/examples/react/basic-ssr-streaming-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ target: 'react', autoCodeSplitting: true }), react(), ], }) diff --git a/examples/react/basic-virtual-file-based/package.json b/examples/react/basic-virtual-file-based/package.json index ff649aeac9..9a1057e796 100644 --- a/examples/react/basic-virtual-file-based/package.json +++ b/examples/react/basic-virtual-file-based/package.json @@ -9,10 +9,10 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", - "@tanstack/virtual-file-routes": "^1.115.0", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", + "@tanstack/virtual-file-routes": "^1.121.0-alpha.1", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -26,6 +26,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/basic-virtual-file-based/src/routeTree.gen.ts b/examples/react/basic-virtual-file-based/src/routeTree.gen.ts index 22a3dcf194..c6ef800c5a 100644 --- a/examples/react/basic-virtual-file-based/src/routeTree.gen.ts +++ b/examples/react/basic-virtual-file-based/src/routeTree.gen.ts @@ -9,103 +9,104 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { createFileRoute } from '@tanstack/react-router' +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-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' +import { Route as postsPostsRouteImport } from './routes/posts/posts' +import { Route as layoutFirstLayoutRouteImport } from './routes/layout/first-layout' +import { Route as homeRouteImport } from './routes/home' +import { Route as postsPostsDetailRouteImport } from './routes/posts/posts-detail' +import { Route as layoutSecondLayoutRouteImport } from './routes/layout/second-layout' +import { Route as postsPostsHomeRouteImport } from './routes/posts/posts-home' +import { Route as ClassicHelloRouteRouteImport } from './routes/file-based-subtree/hello/route' +import { Route as ClassicHelloIndexRouteImport } from './routes/file-based-subtree/hello/index' +import { Route as ClassicHelloWorldRouteImport } from './routes/file-based-subtree/hello/world' +import { Route as ClassicHelloUniverseRouteImport } from './routes/file-based-subtree/hello/universe' +import { Route as bRouteImport } from './routes/b' +import { Route as aRouteImport } from './routes/a' // Create Virtual Routes -const FirstSecondLayoutRouteWithoutFileImport = createFileRoute( +const FirstSecondLayoutRouteWithoutFileRouteImport = createFileRoute( '/_first/_second-layout/route-without-file', )() // Create/Update Routes -const postsPostsRoute = postsPostsImport.update({ +const postsPostsRoute = postsPostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const layoutFirstLayoutRoute = layoutFirstLayoutImport.update({ +const layoutFirstLayoutRoute = layoutFirstLayoutRouteImport.update({ id: '/_first', getParentRoute: () => rootRoute, } as any) -const homeRoute = homeImport.update({ +const homeRoute = homeRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const postsPostsDetailRoute = postsPostsDetailImport.update({ +const postsPostsDetailRoute = postsPostsDetailRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => postsPostsRoute, } as any) -const layoutSecondLayoutRoute = layoutSecondLayoutImport.update({ +const layoutSecondLayoutRoute = layoutSecondLayoutRouteImport.update({ id: '/_second-layout', getParentRoute: () => layoutFirstLayoutRoute, } as any) -const postsPostsHomeRoute = postsPostsHomeImport.update({ +const postsPostsHomeRoute = postsPostsHomeRouteImport.update({ id: '/', path: '/', getParentRoute: () => postsPostsRoute, } as any) -const ClassicHelloRouteRoute = ClassicHelloRouteImport.update({ +const ClassicHelloRouteRoute = ClassicHelloRouteRouteImport.update({ id: '/classic/hello', path: '/classic/hello', getParentRoute: () => rootRoute, } as any) -const ClassicHelloIndexRoute = ClassicHelloIndexImport.update({ +const ClassicHelloIndexRoute = ClassicHelloIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => ClassicHelloRouteRoute, } as any) -const ClassicHelloWorldRoute = ClassicHelloWorldImport.update({ +const ClassicHelloWorldRoute = ClassicHelloWorldRouteImport.update({ id: '/world', path: '/world', getParentRoute: () => ClassicHelloRouteRoute, } as any) -const ClassicHelloUniverseRoute = ClassicHelloUniverseImport.update({ +const ClassicHelloUniverseRoute = ClassicHelloUniverseRouteImport.update({ id: '/universe', path: '/universe', getParentRoute: () => ClassicHelloRouteRoute, } as any) const FirstSecondLayoutRouteWithoutFileRoute = - FirstSecondLayoutRouteWithoutFileImport.update({ + FirstSecondLayoutRouteWithoutFileRouteImport.update({ id: '/route-without-file', path: '/route-without-file', getParentRoute: () => layoutSecondLayoutRoute, } as any) -const bRoute = bImport.update({ +const bRoute = bRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => FirstSecondLayoutRouteWithoutFileRoute, } as any) -const aRoute = aImport.update({ +const aRoute = aRouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => FirstSecondLayoutRouteWithoutFileRoute, @@ -119,96 +120,208 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof homeImport + preLoaderRoute: typeof homeRouteImport parentRoute: typeof rootRoute } '/_first': { id: '/_first' path: '' fullPath: '' - preLoaderRoute: typeof layoutFirstLayoutImport + preLoaderRoute: typeof layoutFirstLayoutRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof postsPostsImport + preLoaderRoute: typeof postsPostsRouteImport parentRoute: typeof rootRoute } '/classic/hello': { id: '/classic/hello' path: '/classic/hello' fullPath: '/classic/hello' - preLoaderRoute: typeof ClassicHelloRouteImport + preLoaderRoute: typeof ClassicHelloRouteRouteImport parentRoute: typeof rootRoute } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof postsPostsHomeImport - parentRoute: typeof postsPostsImport + preLoaderRoute: typeof postsPostsHomeRouteImport + parentRoute: typeof postsPostsRouteImport } '/_first/_second-layout': { id: '/_first/_second-layout' path: '' fullPath: '' - preLoaderRoute: typeof layoutSecondLayoutImport - parentRoute: typeof layoutFirstLayoutImport + preLoaderRoute: typeof layoutSecondLayoutRouteImport + parentRoute: typeof layoutFirstLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof postsPostsDetailImport - parentRoute: typeof postsPostsImport + preLoaderRoute: typeof postsPostsDetailRouteImport + parentRoute: typeof postsPostsRouteImport } '/_first/_second-layout/route-without-file': { id: '/_first/_second-layout/route-without-file' path: '/route-without-file' fullPath: '/route-without-file' - preLoaderRoute: typeof FirstSecondLayoutRouteWithoutFileImport - parentRoute: typeof layoutSecondLayoutImport + preLoaderRoute: typeof FirstSecondLayoutRouteWithoutFileRouteImport + parentRoute: typeof layoutSecondLayoutRouteImport } '/classic/hello/universe': { id: '/classic/hello/universe' path: '/universe' fullPath: '/classic/hello/universe' - preLoaderRoute: typeof ClassicHelloUniverseImport - parentRoute: typeof ClassicHelloRouteImport + preLoaderRoute: typeof ClassicHelloUniverseRouteImport + parentRoute: typeof ClassicHelloRouteRouteImport } '/classic/hello/world': { id: '/classic/hello/world' path: '/world' fullPath: '/classic/hello/world' - preLoaderRoute: typeof ClassicHelloWorldImport - parentRoute: typeof ClassicHelloRouteImport + preLoaderRoute: typeof ClassicHelloWorldRouteImport + parentRoute: typeof ClassicHelloRouteRouteImport } '/classic/hello/': { id: '/classic/hello/' path: '/' fullPath: '/classic/hello/' - preLoaderRoute: typeof ClassicHelloIndexImport - parentRoute: typeof ClassicHelloRouteImport + preLoaderRoute: typeof ClassicHelloIndexRouteImport + parentRoute: typeof ClassicHelloRouteRouteImport } '/_first/_second-layout/route-without-file/layout-a': { id: '/_first/_second-layout/route-without-file/layout-a' path: '/layout-a' fullPath: '/route-without-file/layout-a' - preLoaderRoute: typeof aImport - parentRoute: typeof FirstSecondLayoutRouteWithoutFileImport + preLoaderRoute: typeof aRouteImport + parentRoute: typeof FirstSecondLayoutRouteWithoutFileRouteImport } '/_first/_second-layout/route-without-file/layout-b': { id: '/_first/_second-layout/route-without-file/layout-b' path: '/layout-b' fullPath: '/route-without-file/layout-b' - preLoaderRoute: typeof bImport - parentRoute: typeof FirstSecondLayoutRouteWithoutFileImport + preLoaderRoute: typeof bRouteImport + parentRoute: typeof FirstSecondLayoutRouteWithoutFileRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/home' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/layout/first-layout' { + const createFileRoute: CreateFileRoute< + '/_first', + FileRoutesByPath['/_first']['parentRoute'], + FileRoutesByPath['/_first']['id'], + FileRoutesByPath['/_first']['path'], + FileRoutesByPath['/_first']['fullPath'] + > +} +declare module './routes/posts/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/route' { + const createFileRoute: CreateFileRoute< + '/classic/hello', + FileRoutesByPath['/classic/hello']['parentRoute'], + FileRoutesByPath['/classic/hello']['id'], + FileRoutesByPath['/classic/hello']['path'], + FileRoutesByPath['/classic/hello']['fullPath'] + > +} +declare module './routes/posts/posts-home' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/layout/second-layout' { + const createFileRoute: CreateFileRoute< + '/_first/_second-layout', + FileRoutesByPath['/_first/_second-layout']['parentRoute'], + FileRoutesByPath['/_first/_second-layout']['id'], + FileRoutesByPath['/_first/_second-layout']['path'], + FileRoutesByPath['/_first/_second-layout']['fullPath'] + > +} +declare module './routes/posts/posts-detail' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} + +declare module './routes/file-based-subtree/hello/universe' { + const createFileRoute: CreateFileRoute< + '/classic/hello/universe', + FileRoutesByPath['/classic/hello/universe']['parentRoute'], + FileRoutesByPath['/classic/hello/universe']['id'], + FileRoutesByPath['/classic/hello/universe']['path'], + FileRoutesByPath['/classic/hello/universe']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/world' { + const createFileRoute: CreateFileRoute< + '/classic/hello/world', + FileRoutesByPath['/classic/hello/world']['parentRoute'], + FileRoutesByPath['/classic/hello/world']['id'], + FileRoutesByPath['/classic/hello/world']['path'], + FileRoutesByPath['/classic/hello/world']['fullPath'] + > +} +declare module './routes/file-based-subtree/hello/index' { + const createFileRoute: CreateFileRoute< + '/classic/hello/', + FileRoutesByPath['/classic/hello/']['parentRoute'], + FileRoutesByPath['/classic/hello/']['id'], + FileRoutesByPath['/classic/hello/']['path'], + FileRoutesByPath['/classic/hello/']['fullPath'] + > +} +declare module './routes/a' { + const createFileRoute: CreateFileRoute< + '/_first/_second-layout/route-without-file/layout-a', + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-a']['parentRoute'], + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-a']['id'], + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-a']['path'], + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-a']['fullPath'] + > +} +declare module './routes/b' { + const createFileRoute: CreateFileRoute< + '/_first/_second-layout/route-without-file/layout-b', + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-b']['parentRoute'], + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-b']['id'], + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-b']['path'], + FileRoutesByPath['/_first/_second-layout/route-without-file/layout-b']['fullPath'] + > +} + // Create and export the route tree interface FirstSecondLayoutRouteWithoutFileRouteChildren { diff --git a/examples/react/basic-virtual-file-based/src/routes/a.tsx b/examples/react/basic-virtual-file-based/src/routes/a.tsx index aa765e6891..a190b24202 100644 --- a/examples/react/basic-virtual-file-based/src/routes/a.tsx +++ b/examples/react/basic-virtual-file-based/src/routes/a.tsx @@ -1,8 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute( - '/_first/_second-layout/route-without-file/layout-a', -)({ +export const Route = createFileRoute({ component: LayoutAComponent, }) diff --git a/examples/react/basic-virtual-file-based/src/routes/b.tsx b/examples/react/basic-virtual-file-based/src/routes/b.tsx index 1a7fcaebdb..505f8f6fbf 100644 --- a/examples/react/basic-virtual-file-based/src/routes/b.tsx +++ b/examples/react/basic-virtual-file-based/src/routes/b.tsx @@ -1,8 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute( - '/_first/_second-layout/route-without-file/layout-b', -)({ +export const Route = createFileRoute({ component: LayoutBComponent, }) 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 index c7417e5eeb..f86335e291 100644 --- 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 @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/classic/hello/')({ +export const Route = createFileRoute({ 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 index 566efc8777..620dd2b76b 100644 --- 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 @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/classic/hello')({ +export const Route = createFileRoute({ component: () => (
Hello! 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 index e00c47d74b..20b07c41cc 100644 --- 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 @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/classic/hello/universe')({ +export const Route = createFileRoute({ 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 index 9783557342..4af11357a2 100644 --- 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 @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/classic/hello/world')({ +export const Route = createFileRoute({ 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 index eac82a9174..b23956ae17 100644 --- a/examples/react/basic-virtual-file-based/src/routes/home.tsx +++ b/examples/react/basic-virtual-file-based/src/routes/home.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: 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 index d39e206f2d..5c4a461d8d 100644 --- 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 @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_first')({ +export const Route = createFileRoute({ component: LayoutComponent, }) 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 index 2f56647492..478d9afbec 100644 --- 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 @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_first/_second-layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) 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 index 948d52d6d6..654f3cfd18 100644 --- 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 @@ -1,9 +1,9 @@ import * as React from 'react' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import { fetchPost } from '../../posts' import type { ErrorComponentProps } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost(postId), errorComponent: PostErrorComponent as any, notFoundComponent: () => { 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 index 056433ca0a..fdbe5865e5 100644 --- 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 @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) 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 index a2ab1ee388..f92c37f537 100644 --- a/examples/react/basic-virtual-file-based/src/routes/posts/posts.tsx +++ b/examples/react/basic-virtual-file-based/src/routes/posts/posts.tsx @@ -1,8 +1,8 @@ import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../../posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: fetchPosts, component: PostsComponent, }) diff --git a/examples/react/basic-virtual-file-based/vite.config.ts b/examples/react/basic-virtual-file-based/vite.config.ts index a04fbc2dcb..ea7fb55e88 100644 --- a/examples/react/basic-virtual-file-based/vite.config.ts +++ b/examples/react/basic-virtual-file-based/vite.config.ts @@ -1,13 +1,14 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'react', autoCodeSplitting: true, + verboseFileRoutes: false, virtualRouteConfig: './routes.ts', }), react(), diff --git a/examples/react/basic-virtual-inside-file-based/package.json b/examples/react/basic-virtual-inside-file-based/package.json index b8b045f74c..dbf01cdbbb 100644 --- a/examples/react/basic-virtual-inside-file-based/package.json +++ b/examples/react/basic-virtual-inside-file-based/package.json @@ -9,10 +9,10 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", - "@tanstack/virtual-file-routes": "^1.115.0", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", + "@tanstack/virtual-file-routes": "^1.121.0-alpha.1", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -26,6 +26,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } 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 index 79d98a78be..b9890b4077 100644 --- a/examples/react/basic-virtual-inside-file-based/src/routeTree.gen.ts +++ b/examples/react/basic-virtual-inside-file-based/src/routeTree.gen.ts @@ -8,75 +8,77 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-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' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as LayoutRouteImport } from './routes/_layout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as postsDetailsRouteImport } from './routes/posts/details' +import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2' +import { Route as postsHomeRouteImport } from './routes/posts/home' +import { Route as postsLetsGoIndexRouteImport } from './routes/posts/lets-go/index' +import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b' +import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' +import { Route as postsLetsGoDeeperHomeRouteImport } from './routes/posts/lets-go/deeper/home' // Create/Update Routes -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const LayoutRoute = LayoutImport.update({ +const LayoutRoute = LayoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const postsDetailsRoute = postsDetailsImport.update({ +const postsDetailsRoute = postsDetailsRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const LayoutLayout2Route = LayoutLayout2Import.update({ +const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) -const postsHomeRoute = postsHomeImport.update({ +const postsHomeRoute = postsHomeRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const postsLetsGoIndexRoute = postsLetsGoIndexImport.update({ +const postsLetsGoIndexRoute = postsLetsGoIndexRouteImport.update({ id: '/inception/', path: '/inception/', getParentRoute: () => PostsRoute, } as any) -const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBImport.update({ +const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({ id: '/layout-b', path: '/layout-b', getParentRoute: () => LayoutLayout2Route, } as any) -const LayoutLayout2LayoutARoute = LayoutLayout2LayoutAImport.update({ +const LayoutLayout2LayoutARoute = LayoutLayout2LayoutARouteImport.update({ id: '/layout-a', path: '/layout-a', getParentRoute: () => LayoutLayout2Route, } as any) -const postsLetsGoDeeperHomeRoute = postsLetsGoDeeperHomeImport.update({ +const postsLetsGoDeeperHomeRoute = postsLetsGoDeeperHomeRouteImport.update({ id: '/inception/deeper/', path: '/inception/deeper/', getParentRoute: () => PostsRoute, @@ -90,75 +92,168 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof postsHomeImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof postsHomeRouteImport + parentRoute: typeof PostsRouteImport } '/_layout/_layout-2': { id: '/_layout/_layout-2' path: '' fullPath: '' - preLoaderRoute: typeof LayoutLayout2Import - parentRoute: typeof LayoutImport + preLoaderRoute: typeof LayoutLayout2RouteImport + parentRoute: typeof LayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof postsDetailsImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof postsDetailsRouteImport + parentRoute: typeof PostsRouteImport } '/_layout/_layout-2/layout-a': { id: '/_layout/_layout-2/layout-a' path: '/layout-a' fullPath: '/layout-a' - preLoaderRoute: typeof LayoutLayout2LayoutAImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutARouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/_layout/_layout-2/layout-b': { id: '/_layout/_layout-2/layout-b' path: '/layout-b' fullPath: '/layout-b' - preLoaderRoute: typeof LayoutLayout2LayoutBImport - parentRoute: typeof LayoutLayout2Import + preLoaderRoute: typeof LayoutLayout2LayoutBRouteImport + parentRoute: typeof LayoutLayout2RouteImport } '/posts/inception/': { id: '/posts/inception/' path: '/inception' fullPath: '/posts/inception' - preLoaderRoute: typeof postsLetsGoIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof postsLetsGoIndexRouteImport + parentRoute: typeof PostsRouteImport } '/posts/inception/deeper/': { id: '/posts/inception/deeper/' path: '/inception/deeper' fullPath: '/posts/inception/deeper' - preLoaderRoute: typeof postsLetsGoDeeperHomeImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof postsLetsGoDeeperHomeRouteImport + parentRoute: typeof PostsRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_layout' { + const createFileRoute: CreateFileRoute< + '/_layout', + FileRoutesByPath['/_layout']['parentRoute'], + FileRoutesByPath['/_layout']['id'], + FileRoutesByPath['/_layout']['path'], + FileRoutesByPath['/_layout']['fullPath'] + > +} +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/posts/home' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/_layout/_layout-2' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2', + FileRoutesByPath['/_layout/_layout-2']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2']['id'], + FileRoutesByPath['/_layout/_layout-2']['path'], + FileRoutesByPath['/_layout/_layout-2']['fullPath'] + > +} +declare module './routes/posts/details' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-a' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-a', + FileRoutesByPath['/_layout/_layout-2/layout-a']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-a']['fullPath'] + > +} +declare module './routes/_layout/_layout-2/layout-b' { + const createFileRoute: CreateFileRoute< + '/_layout/_layout-2/layout-b', + FileRoutesByPath['/_layout/_layout-2/layout-b']['parentRoute'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['id'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['path'], + FileRoutesByPath['/_layout/_layout-2/layout-b']['fullPath'] + > +} +declare module './routes/posts/lets-go/index' { + const createFileRoute: CreateFileRoute< + '/posts/inception/', + FileRoutesByPath['/posts/inception/']['parentRoute'], + FileRoutesByPath['/posts/inception/']['id'], + FileRoutesByPath['/posts/inception/']['path'], + FileRoutesByPath['/posts/inception/']['fullPath'] + > +} +declare module './routes/posts/lets-go/deeper/home' { + const createFileRoute: CreateFileRoute< + '/posts/inception/deeper/', + FileRoutesByPath['/posts/inception/deeper/']['parentRoute'], + FileRoutesByPath['/posts/inception/deeper/']['id'], + FileRoutesByPath['/posts/inception/deeper/']['path'], + FileRoutesByPath['/posts/inception/deeper/']['fullPath'] + > +} + // Create and export the route tree interface LayoutLayout2RouteChildren { 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 index 02ddbb1cd9..5c4a461d8d 100644 --- a/examples/react/basic-virtual-inside-file-based/src/routes/_layout.tsx +++ b/examples/react/basic-virtual-inside-file-based/src/routes/_layout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) 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 index 3b7dbf2903..483b910862 100644 --- 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 @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout/_layout-2')({ +export const Route = createFileRoute({ component: LayoutComponent, }) 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 index 61e19b4d9f..a190b24202 100644 --- 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 @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ +export const Route = createFileRoute({ component: LayoutAComponent, }) 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 index cceed1fb9a..505f8f6fbf 100644 --- 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 @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ +export const Route = createFileRoute({ component: LayoutBComponent, }) 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 index eac82a9174..b23956ae17 100644 --- a/examples/react/basic-virtual-inside-file-based/src/routes/index.tsx +++ b/examples/react/basic-virtual-inside-file-based/src/routes/index.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: 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 index c7a09ed7f8..4469b2216a 100644 --- a/examples/react/basic-virtual-inside-file-based/src/routes/posts.tsx +++ b/examples/react/basic-virtual-inside-file-based/src/routes/posts.tsx @@ -1,8 +1,8 @@ import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: fetchPosts, component: PostsComponent, }) 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 index 6479bdf803..fc10978507 100644 --- 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 @@ -1,9 +1,9 @@ import * as React from 'react' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import { fetchPost } from '../../posts' import type { ErrorComponentProps } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost(postId), errorComponent: PostErrorComponent, notFoundComponent: () => { 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 index 056433ca0a..fdbe5865e5 100644 --- 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 @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) 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 index 11f7fa95ca..f8bc76644a 100644 --- 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 @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/inception/deeper/')({ +export const Route = createFileRoute({ 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 index 964ab3c900..1c7ea68931 100644 --- 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 @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/inception/')({ +export const Route = createFileRoute({ component: () =>
Hello /posts/inception/!
, }) diff --git a/examples/react/basic-virtual-inside-file-based/vite.config.ts b/examples/react/basic-virtual-inside-file-based/vite.config.ts index b819774577..3524a957da 100644 --- a/examples/react/basic-virtual-inside-file-based/vite.config.ts +++ b/examples/react/basic-virtual-inside-file-based/vite.config.ts @@ -1,11 +1,15 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ + target: 'react', + autoCodeSplitting: true, + verboseFileRoutes: false, + }), react(), ], }) diff --git a/examples/react/basic/package.json b/examples/react/basic/package.json index 2f2c75d4b0..e73765ad27 100644 --- a/examples/react/basic/package.json +++ b/examples/react/basic/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -23,6 +23,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/deferred-data/package.json b/examples/react/deferred-data/package.json index 07d7ca2b8c..7210b7dbdc 100644 --- a/examples/react/deferred-data/package.json +++ b/examples/react/deferred-data/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -24,6 +24,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/kitchen-sink-file-based/package.json b/examples/react/kitchen-sink-file-based/package.json index 6fbb0f6ae3..fbae548a37 100644 --- a/examples/react/kitchen-sink-file-based/package.json +++ b/examples/react/kitchen-sink-file-based/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "immer": "^10.1.1", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -26,6 +26,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/kitchen-sink-file-based/src/routeTree.gen.ts b/examples/react/kitchen-sink-file-based/src/routeTree.gen.ts index 4f3339865d..f3accfa48e 100644 --- a/examples/react/kitchen-sink-file-based/src/routeTree.gen.ts +++ b/examples/react/kitchen-sink-file-based/src/routeTree.gen.ts @@ -11,128 +11,127 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as LoginImport } from './routes/login' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as AuthImport } from './routes/_auth' -import { Route as DashboardRouteImport } from './routes/dashboard.route' -import { Route as IndexImport } from './routes/index' -import { Route as ExpensiveIndexImport } from './routes/expensive/index' -import { Route as DashboardIndexImport } from './routes/dashboard.index' -import { Route as PathlessLayoutRouteBImport } from './routes/_pathlessLayout.route-b' -import { Route as PathlessLayoutRouteAImport } from './routes/_pathlessLayout.route-a' -import { Route as AuthProfileImport } from './routes/_auth.profile' -import { Route as thisFolderIsNotInTheUrlRouteGroupImport } from './routes/(this-folder-is-not-in-the-url)/route-group' -import { Route as DashboardUsersRouteImport } from './routes/dashboard.users.route' -import { Route as DashboardInvoicesRouteImport } from './routes/dashboard.invoices.route' -import { Route as DashboardUsersIndexImport } from './routes/dashboard.users.index' -import { Route as DashboardInvoicesIndexImport } from './routes/dashboard.invoices.index' -import { Route as DashboardUsersUserImport } from './routes/dashboard.users.user' -import { Route as DashboardInvoicesInvoiceIdImport } from './routes/dashboard.invoices.$invoiceId' +import { Route as LoginRouteImport } from './routes/login' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as AuthRouteImport } from './routes/_auth' +import { Route as DashboardRouteRouteImport } from './routes/dashboard.route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as ExpensiveIndexRouteImport } from './routes/expensive/index' +import { Route as DashboardIndexRouteImport } from './routes/dashboard.index' +import { Route as PathlessLayoutRouteBRouteImport } from './routes/_pathlessLayout.route-b' +import { Route as PathlessLayoutRouteARouteImport } from './routes/_pathlessLayout.route-a' +import { Route as AuthProfileRouteImport } from './routes/_auth.profile' +import { Route as thisFolderIsNotInTheUrlRouteGroupRouteImport } from './routes/(this-folder-is-not-in-the-url)/route-group' +import { Route as DashboardUsersRouteRouteImport } from './routes/dashboard.users.route' +import { Route as DashboardInvoicesRouteRouteImport } from './routes/dashboard.invoices.route' +import { Route as DashboardUsersIndexRouteImport } from './routes/dashboard.users.index' +import { Route as DashboardInvoicesIndexRouteImport } from './routes/dashboard.invoices.index' +import { Route as DashboardUsersUserRouteImport } from './routes/dashboard.users.user' +import { Route as DashboardInvoicesInvoiceIdRouteImport } from './routes/dashboard.invoices.$invoiceId' // Create/Update Routes -const LoginRoute = LoginImport.update({ +const LoginRoute = LoginRouteImport.update({ id: '/login', path: '/login', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const AuthRoute = AuthImport.update({ +const AuthRoute = AuthRouteImport.update({ id: '/_auth', getParentRoute: () => rootRoute, } as any) -const DashboardRouteRoute = DashboardRouteImport.update({ +const DashboardRouteRoute = DashboardRouteRouteImport.update({ id: '/dashboard', path: '/dashboard', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const ExpensiveIndexRoute = ExpensiveIndexImport.update({ +const ExpensiveIndexRoute = ExpensiveIndexRouteImport.update({ id: '/expensive/', path: '/expensive/', getParentRoute: () => rootRoute, } as any) -const DashboardIndexRoute = DashboardIndexImport.update({ +const DashboardIndexRoute = DashboardIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => DashboardRouteRoute, } as any) -const PathlessLayoutRouteBRoute = PathlessLayoutRouteBImport.update({ +const PathlessLayoutRouteBRoute = PathlessLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutRoute, } as any) -const PathlessLayoutRouteARoute = PathlessLayoutRouteAImport.update({ +const PathlessLayoutRouteARoute = PathlessLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutRoute, } as any) -const AuthProfileRoute = AuthProfileImport.update({ +const AuthProfileRoute = AuthProfileRouteImport.update({ id: '/profile', path: '/profile', getParentRoute: () => AuthRoute, } as any) const thisFolderIsNotInTheUrlRouteGroupRoute = - thisFolderIsNotInTheUrlRouteGroupImport.update({ + thisFolderIsNotInTheUrlRouteGroupRouteImport.update({ id: '/(this-folder-is-not-in-the-url)/route-group', path: '/route-group', getParentRoute: () => rootRoute, } as any) -const DashboardUsersRouteRoute = DashboardUsersRouteImport.update({ +const DashboardUsersRouteRoute = DashboardUsersRouteRouteImport.update({ id: '/users', path: '/users', getParentRoute: () => DashboardRouteRoute, } as any) -const DashboardInvoicesRouteRoute = DashboardInvoicesRouteImport.update({ +const DashboardInvoicesRouteRoute = DashboardInvoicesRouteRouteImport.update({ id: '/invoices', path: '/invoices', getParentRoute: () => DashboardRouteRoute, } as any) -const DashboardUsersIndexRoute = DashboardUsersIndexImport.update({ +const DashboardUsersIndexRoute = DashboardUsersIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => DashboardUsersRouteRoute, } as any) -const DashboardInvoicesIndexRoute = DashboardInvoicesIndexImport.update({ +const DashboardInvoicesIndexRoute = DashboardInvoicesIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => DashboardInvoicesRouteRoute, } as any) -const DashboardUsersUserRoute = DashboardUsersUserImport.update({ +const DashboardUsersUserRoute = DashboardUsersUserRouteImport.update({ id: '/user', path: '/user', getParentRoute: () => DashboardUsersRouteRoute, } as any) -const DashboardInvoicesInvoiceIdRoute = DashboardInvoicesInvoiceIdImport.update( - { +const DashboardInvoicesInvoiceIdRoute = + DashboardInvoicesInvoiceIdRouteImport.update({ id: '/$invoiceId', path: '/$invoiceId', getParentRoute: () => DashboardInvoicesRouteRoute, - } as any, -) + } as any) // Populate the FileRoutesByPath interface @@ -142,120 +141,120 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/dashboard': { id: '/dashboard' path: '/dashboard' fullPath: '/dashboard' - preLoaderRoute: typeof DashboardRouteImport + preLoaderRoute: typeof DashboardRouteRouteImport parentRoute: typeof rootRoute } '/_auth': { id: '/_auth' path: '' fullPath: '' - preLoaderRoute: typeof AuthImport + preLoaderRoute: typeof AuthRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/login': { id: '/login' path: '/login' fullPath: '/login' - preLoaderRoute: typeof LoginImport + preLoaderRoute: typeof LoginRouteImport parentRoute: typeof rootRoute } '/dashboard/invoices': { id: '/dashboard/invoices' path: '/invoices' fullPath: '/dashboard/invoices' - preLoaderRoute: typeof DashboardInvoicesRouteImport - parentRoute: typeof DashboardRouteImport + preLoaderRoute: typeof DashboardInvoicesRouteRouteImport + parentRoute: typeof DashboardRouteRouteImport } '/dashboard/users': { id: '/dashboard/users' path: '/users' fullPath: '/dashboard/users' - preLoaderRoute: typeof DashboardUsersRouteImport - parentRoute: typeof DashboardRouteImport + preLoaderRoute: typeof DashboardUsersRouteRouteImport + parentRoute: typeof DashboardRouteRouteImport } '/(this-folder-is-not-in-the-url)/route-group': { id: '/(this-folder-is-not-in-the-url)/route-group' path: '/route-group' fullPath: '/route-group' - preLoaderRoute: typeof thisFolderIsNotInTheUrlRouteGroupImport + preLoaderRoute: typeof thisFolderIsNotInTheUrlRouteGroupRouteImport parentRoute: typeof rootRoute } '/_auth/profile': { id: '/_auth/profile' path: '/profile' fullPath: '/profile' - preLoaderRoute: typeof AuthProfileImport - parentRoute: typeof AuthImport + preLoaderRoute: typeof AuthProfileRouteImport + parentRoute: typeof AuthRouteImport } '/_pathlessLayout/route-a': { id: '/_pathlessLayout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutRouteAImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/_pathlessLayout/route-b': { id: '/_pathlessLayout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutRouteBImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/dashboard/': { id: '/dashboard/' path: '/' fullPath: '/dashboard/' - preLoaderRoute: typeof DashboardIndexImport - parentRoute: typeof DashboardRouteImport + preLoaderRoute: typeof DashboardIndexRouteImport + parentRoute: typeof DashboardRouteRouteImport } '/expensive/': { id: '/expensive/' path: '/expensive' fullPath: '/expensive' - preLoaderRoute: typeof ExpensiveIndexImport + preLoaderRoute: typeof ExpensiveIndexRouteImport parentRoute: typeof rootRoute } '/dashboard/invoices/$invoiceId': { id: '/dashboard/invoices/$invoiceId' path: '/$invoiceId' fullPath: '/dashboard/invoices/$invoiceId' - preLoaderRoute: typeof DashboardInvoicesInvoiceIdImport - parentRoute: typeof DashboardInvoicesRouteImport + preLoaderRoute: typeof DashboardInvoicesInvoiceIdRouteImport + parentRoute: typeof DashboardInvoicesRouteRouteImport } '/dashboard/users/user': { id: '/dashboard/users/user' path: '/user' fullPath: '/dashboard/users/user' - preLoaderRoute: typeof DashboardUsersUserImport - parentRoute: typeof DashboardUsersRouteImport + preLoaderRoute: typeof DashboardUsersUserRouteImport + parentRoute: typeof DashboardUsersRouteRouteImport } '/dashboard/invoices/': { id: '/dashboard/invoices/' path: '/' fullPath: '/dashboard/invoices/' - preLoaderRoute: typeof DashboardInvoicesIndexImport - parentRoute: typeof DashboardInvoicesRouteImport + preLoaderRoute: typeof DashboardInvoicesIndexRouteImport + parentRoute: typeof DashboardInvoicesRouteRouteImport } '/dashboard/users/': { id: '/dashboard/users/' path: '/' fullPath: '/dashboard/users/' - preLoaderRoute: typeof DashboardUsersIndexImport - parentRoute: typeof DashboardUsersRouteImport + preLoaderRoute: typeof DashboardUsersIndexRouteImport + parentRoute: typeof DashboardUsersRouteRouteImport } } } diff --git a/examples/react/kitchen-sink-file-based/src/routes/(this-folder-is-not-in-the-url)/route-group.tsx b/examples/react/kitchen-sink-file-based/src/routes/(this-folder-is-not-in-the-url)/route-group.tsx index 4541afc8d0..5083ff1803 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/(this-folder-is-not-in-the-url)/route-group.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/(this-folder-is-not-in-the-url)/route-group.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute( '/(this-folder-is-not-in-the-url)/route-group', diff --git a/examples/react/kitchen-sink-file-based/src/routes/_auth.profile.tsx b/examples/react/kitchen-sink-file-based/src/routes/_auth.profile.tsx index fa63df98b0..5fb32c03cf 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/_auth.profile.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/_auth.profile.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/_auth/profile')({ component: ProfileComponent, diff --git a/examples/react/kitchen-sink-file-based/src/routes/_auth.tsx b/examples/react/kitchen-sink-file-based/src/routes/_auth.tsx index f4f3876f26..19bbb2b33b 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/_auth.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/_auth.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' import { auth } from '../utils/auth' export const Route = createFileRoute('/_auth')({ diff --git a/examples/react/kitchen-sink-file-based/src/routes/_pathlessLayout.route-a.tsx b/examples/react/kitchen-sink-file-based/src/routes/_pathlessLayout.route-a.tsx index ce791bcf2f..61167164f7 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/_pathlessLayout.route-a.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/_pathlessLayout.route-a.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/_pathlessLayout/route-a')({ component: LayoutAComponent, diff --git a/examples/react/kitchen-sink-file-based/src/routes/_pathlessLayout.route-b.tsx b/examples/react/kitchen-sink-file-based/src/routes/_pathlessLayout.route-b.tsx index aa3010287d..ed4fbcf142 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/_pathlessLayout.route-b.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/_pathlessLayout.route-b.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/_pathlessLayout/route-b')({ component: LayoutBComponent, diff --git a/examples/react/kitchen-sink-file-based/src/routes/_pathlessLayout.tsx b/examples/react/kitchen-sink-file-based/src/routes/_pathlessLayout.tsx index 4884d30343..b9afe4d9e7 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/_pathlessLayout.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/_pathlessLayout.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_pathlessLayout')({ component: PathlessLayoutComponent, diff --git a/examples/react/kitchen-sink-file-based/src/routes/dashboard.index.tsx b/examples/react/kitchen-sink-file-based/src/routes/dashboard.index.tsx index 22fb1c83c6..1666ad41ec 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/dashboard.index.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/dashboard.index.tsx @@ -1,5 +1,6 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' + import { fetchInvoices } from '../utils/mockTodos' export const Route = createFileRoute('/dashboard/')({ diff --git a/examples/react/kitchen-sink-file-based/src/routes/dashboard.invoices.$invoiceId.tsx b/examples/react/kitchen-sink-file-based/src/routes/dashboard.invoices.$invoiceId.tsx index d615c89a2c..d7938e72c5 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/dashboard.invoices.$invoiceId.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/dashboard.invoices.$invoiceId.tsx @@ -1,10 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { - Link, - createFileRoute, - useNavigate, - useRouter, -} from '@tanstack/react-router' +import { Link, useNavigate, useRouter } from '@tanstack/react-router' import { z } from 'zod' import { InvoiceFields } from '../components/InvoiceFields' import { useMutation } from '../hooks/useMutation' diff --git a/examples/react/kitchen-sink-file-based/src/routes/dashboard.invoices.index.tsx b/examples/react/kitchen-sink-file-based/src/routes/dashboard.invoices.index.tsx index 4df164a96e..845308e983 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/dashboard.invoices.index.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/dashboard.invoices.index.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { createFileRoute, useRouter } from '@tanstack/react-router' +import { useRouter } from '@tanstack/react-router' import { InvoiceFields } from '../components/InvoiceFields' import { Spinner } from '../components/Spinner' import { useMutation } from '../hooks/useMutation' diff --git a/examples/react/kitchen-sink-file-based/src/routes/dashboard.invoices.route.tsx b/examples/react/kitchen-sink-file-based/src/routes/dashboard.invoices.route.tsx index e1a123946d..d3192d300f 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/dashboard.invoices.route.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/dashboard.invoices.route.tsx @@ -1,10 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { - Link, - MatchRoute, - Outlet, - createFileRoute, -} from '@tanstack/react-router' +import { Link, MatchRoute, Outlet } from '@tanstack/react-router' import { Spinner } from '../components/Spinner' import { fetchInvoices } from '../utils/mockTodos' diff --git a/examples/react/kitchen-sink-file-based/src/routes/dashboard.route.tsx b/examples/react/kitchen-sink-file-based/src/routes/dashboard.route.tsx index b718b59a2d..5e053e164f 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/dashboard.route.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/dashboard.route.tsx @@ -1,10 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { - Link, - Outlet, - createFileRoute, - linkOptions, -} from '@tanstack/react-router' +import { Link, Outlet, linkOptions } from '@tanstack/react-router' export const Route = createFileRoute('/dashboard')({ component: DashboardComponent, diff --git a/examples/react/kitchen-sink-file-based/src/routes/dashboard.users.index.tsx b/examples/react/kitchen-sink-file-based/src/routes/dashboard.users.index.tsx index 7ad9771152..8b9e85b6bd 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/dashboard.users.index.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/dashboard.users.index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/dashboard/users/')({ component: UsersIndexComponent, diff --git a/examples/react/kitchen-sink-file-based/src/routes/dashboard.users.route.tsx b/examples/react/kitchen-sink-file-based/src/routes/dashboard.users.route.tsx index 0d8886872f..287f4ff0ec 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/dashboard.users.route.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/dashboard.users.route.tsx @@ -1,9 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' import { Link, MatchRoute, Outlet, - createFileRoute, retainSearchParams, useNavigate, } from '@tanstack/react-router' diff --git a/examples/react/kitchen-sink-file-based/src/routes/dashboard.users.user.tsx b/examples/react/kitchen-sink-file-based/src/routes/dashboard.users.user.tsx index fb8d1cc880..6d26dfe83f 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/dashboard.users.user.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/dashboard.users.user.tsx @@ -1,5 +1,6 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' + import { z } from 'zod' import { fetchUserById } from '../utils/mockTodos' diff --git a/examples/react/kitchen-sink-file-based/src/routes/index.tsx b/examples/react/kitchen-sink-file-based/src/routes/index.tsx index a99ada182b..d1ed6b5141 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/index.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/index.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' export const Route = createFileRoute('/')({ component: IndexComponent, diff --git a/examples/react/kitchen-sink-file-based/src/routes/login.tsx b/examples/react/kitchen-sink-file-based/src/routes/login.tsx index 42c01d793f..d4574d1461 100644 --- a/examples/react/kitchen-sink-file-based/src/routes/login.tsx +++ b/examples/react/kitchen-sink-file-based/src/routes/login.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { createFileRoute, useRouter } from '@tanstack/react-router' +import { useRouter } from '@tanstack/react-router' import { z } from 'zod' export const Route = createFileRoute('/login')({ diff --git a/examples/react/kitchen-sink-file-based/vite.config.js b/examples/react/kitchen-sink-file-based/vite.config.js index b819774577..ab615485ae 100644 --- a/examples/react/kitchen-sink-file-based/vite.config.js +++ b/examples/react/kitchen-sink-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ target: 'react', autoCodeSplitting: true }), react(), ], }) 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 01c44d2c42..a7e356dc9a 100644 --- a/examples/react/kitchen-sink-react-query-file-based/package.json +++ b/examples/react/kitchen-sink-react-query-file-based/package.json @@ -11,9 +11,9 @@ "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "immer": "^10.1.1", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -28,6 +28,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routeTree.gen.ts b/examples/react/kitchen-sink-react-query-file-based/src/routeTree.gen.ts index 0ba6d5e9a5..2795fea650 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routeTree.gen.ts +++ b/examples/react/kitchen-sink-react-query-file-based/src/routeTree.gen.ts @@ -11,127 +11,126 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as LoginImport } from './routes/login' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as AuthImport } from './routes/_auth' -import { Route as DashboardRouteImport } from './routes/dashboard.route' -import { Route as IndexImport } from './routes/index' -import { Route as ExpensiveIndexImport } from './routes/expensive/index' -import { Route as DashboardIndexImport } from './routes/dashboard.index' -import { Route as FooBarImport } from './routes/foo/bar' -import { Route as PathlessLayoutRouteBImport } from './routes/_pathlessLayout.route-b' -import { Route as PathlessLayoutRouteAImport } from './routes/_pathlessLayout.route-a' -import { Route as AuthProfileImport } from './routes/_auth.profile' -import { Route as DashboardUsersRouteImport } from './routes/dashboard.users.route' -import { Route as DashboardInvoicesRouteImport } from './routes/dashboard.invoices.route' -import { Route as DashboardUsersIndexImport } from './routes/dashboard.users.index' -import { Route as DashboardInvoicesIndexImport } from './routes/dashboard.invoices.index' -import { Route as DashboardUsersUserImport } from './routes/dashboard.users.user' -import { Route as DashboardInvoicesInvoiceIdImport } from './routes/dashboard.invoices.$invoiceId' +import { Route as LoginRouteImport } from './routes/login' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as AuthRouteImport } from './routes/_auth' +import { Route as DashboardRouteRouteImport } from './routes/dashboard.route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as ExpensiveIndexRouteImport } from './routes/expensive/index' +import { Route as DashboardIndexRouteImport } from './routes/dashboard.index' +import { Route as FooBarRouteImport } from './routes/foo/bar' +import { Route as PathlessLayoutRouteBRouteImport } from './routes/_pathlessLayout.route-b' +import { Route as PathlessLayoutRouteARouteImport } from './routes/_pathlessLayout.route-a' +import { Route as AuthProfileRouteImport } from './routes/_auth.profile' +import { Route as DashboardUsersRouteRouteImport } from './routes/dashboard.users.route' +import { Route as DashboardInvoicesRouteRouteImport } from './routes/dashboard.invoices.route' +import { Route as DashboardUsersIndexRouteImport } from './routes/dashboard.users.index' +import { Route as DashboardInvoicesIndexRouteImport } from './routes/dashboard.invoices.index' +import { Route as DashboardUsersUserRouteImport } from './routes/dashboard.users.user' +import { Route as DashboardInvoicesInvoiceIdRouteImport } from './routes/dashboard.invoices.$invoiceId' // Create/Update Routes -const LoginRoute = LoginImport.update({ +const LoginRoute = LoginRouteImport.update({ id: '/login', path: '/login', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const AuthRoute = AuthImport.update({ +const AuthRoute = AuthRouteImport.update({ id: '/_auth', getParentRoute: () => rootRoute, } as any) -const DashboardRouteRoute = DashboardRouteImport.update({ +const DashboardRouteRoute = DashboardRouteRouteImport.update({ id: '/dashboard', path: '/dashboard', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const ExpensiveIndexRoute = ExpensiveIndexImport.update({ +const ExpensiveIndexRoute = ExpensiveIndexRouteImport.update({ id: '/expensive/', path: '/expensive/', getParentRoute: () => rootRoute, } as any) -const DashboardIndexRoute = DashboardIndexImport.update({ +const DashboardIndexRoute = DashboardIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => DashboardRouteRoute, } as any) -const FooBarRoute = FooBarImport.update({ +const FooBarRoute = FooBarRouteImport.update({ id: '/foo/bar', path: '/foo/bar', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRouteBRoute = PathlessLayoutRouteBImport.update({ +const PathlessLayoutRouteBRoute = PathlessLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutRoute, } as any) -const PathlessLayoutRouteARoute = PathlessLayoutRouteAImport.update({ +const PathlessLayoutRouteARoute = PathlessLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutRoute, } as any) -const AuthProfileRoute = AuthProfileImport.update({ +const AuthProfileRoute = AuthProfileRouteImport.update({ id: '/profile', path: '/profile', getParentRoute: () => AuthRoute, } as any) -const DashboardUsersRouteRoute = DashboardUsersRouteImport.update({ +const DashboardUsersRouteRoute = DashboardUsersRouteRouteImport.update({ id: '/users', path: '/users', getParentRoute: () => DashboardRouteRoute, } as any) -const DashboardInvoicesRouteRoute = DashboardInvoicesRouteImport.update({ +const DashboardInvoicesRouteRoute = DashboardInvoicesRouteRouteImport.update({ id: '/invoices', path: '/invoices', getParentRoute: () => DashboardRouteRoute, } as any) -const DashboardUsersIndexRoute = DashboardUsersIndexImport.update({ +const DashboardUsersIndexRoute = DashboardUsersIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => DashboardUsersRouteRoute, } as any) -const DashboardInvoicesIndexRoute = DashboardInvoicesIndexImport.update({ +const DashboardInvoicesIndexRoute = DashboardInvoicesIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => DashboardInvoicesRouteRoute, } as any) -const DashboardUsersUserRoute = DashboardUsersUserImport.update({ +const DashboardUsersUserRoute = DashboardUsersUserRouteImport.update({ id: '/user', path: '/user', getParentRoute: () => DashboardUsersRouteRoute, } as any) -const DashboardInvoicesInvoiceIdRoute = DashboardInvoicesInvoiceIdImport.update( - { +const DashboardInvoicesInvoiceIdRoute = + DashboardInvoicesInvoiceIdRouteImport.update({ id: '/$invoiceId', path: '/$invoiceId', getParentRoute: () => DashboardInvoicesRouteRoute, - } as any, -) + } as any) // Populate the FileRoutesByPath interface @@ -141,120 +140,120 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/dashboard': { id: '/dashboard' path: '/dashboard' fullPath: '/dashboard' - preLoaderRoute: typeof DashboardRouteImport + preLoaderRoute: typeof DashboardRouteRouteImport parentRoute: typeof rootRoute } '/_auth': { id: '/_auth' path: '' fullPath: '' - preLoaderRoute: typeof AuthImport + preLoaderRoute: typeof AuthRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/login': { id: '/login' path: '/login' fullPath: '/login' - preLoaderRoute: typeof LoginImport + preLoaderRoute: typeof LoginRouteImport parentRoute: typeof rootRoute } '/dashboard/invoices': { id: '/dashboard/invoices' path: '/invoices' fullPath: '/dashboard/invoices' - preLoaderRoute: typeof DashboardInvoicesRouteImport - parentRoute: typeof DashboardRouteImport + preLoaderRoute: typeof DashboardInvoicesRouteRouteImport + parentRoute: typeof DashboardRouteRouteImport } '/dashboard/users': { id: '/dashboard/users' path: '/users' fullPath: '/dashboard/users' - preLoaderRoute: typeof DashboardUsersRouteImport - parentRoute: typeof DashboardRouteImport + preLoaderRoute: typeof DashboardUsersRouteRouteImport + parentRoute: typeof DashboardRouteRouteImport } '/_auth/profile': { id: '/_auth/profile' path: '/profile' fullPath: '/profile' - preLoaderRoute: typeof AuthProfileImport - parentRoute: typeof AuthImport + preLoaderRoute: typeof AuthProfileRouteImport + parentRoute: typeof AuthRouteImport } '/_pathlessLayout/route-a': { id: '/_pathlessLayout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutRouteAImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/_pathlessLayout/route-b': { id: '/_pathlessLayout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutRouteBImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/foo/bar': { id: '/foo/bar' path: '/foo/bar' fullPath: '/foo/bar' - preLoaderRoute: typeof FooBarImport + preLoaderRoute: typeof FooBarRouteImport parentRoute: typeof rootRoute } '/dashboard/': { id: '/dashboard/' path: '/' fullPath: '/dashboard/' - preLoaderRoute: typeof DashboardIndexImport - parentRoute: typeof DashboardRouteImport + preLoaderRoute: typeof DashboardIndexRouteImport + parentRoute: typeof DashboardRouteRouteImport } '/expensive/': { id: '/expensive/' path: '/expensive' fullPath: '/expensive' - preLoaderRoute: typeof ExpensiveIndexImport + preLoaderRoute: typeof ExpensiveIndexRouteImport parentRoute: typeof rootRoute } '/dashboard/invoices/$invoiceId': { id: '/dashboard/invoices/$invoiceId' path: '/$invoiceId' fullPath: '/dashboard/invoices/$invoiceId' - preLoaderRoute: typeof DashboardInvoicesInvoiceIdImport - parentRoute: typeof DashboardInvoicesRouteImport + preLoaderRoute: typeof DashboardInvoicesInvoiceIdRouteImport + parentRoute: typeof DashboardInvoicesRouteRouteImport } '/dashboard/users/user': { id: '/dashboard/users/user' path: '/user' fullPath: '/dashboard/users/user' - preLoaderRoute: typeof DashboardUsersUserImport - parentRoute: typeof DashboardUsersRouteImport + preLoaderRoute: typeof DashboardUsersUserRouteImport + parentRoute: typeof DashboardUsersRouteRouteImport } '/dashboard/invoices/': { id: '/dashboard/invoices/' path: '/' fullPath: '/dashboard/invoices/' - preLoaderRoute: typeof DashboardInvoicesIndexImport - parentRoute: typeof DashboardInvoicesRouteImport + preLoaderRoute: typeof DashboardInvoicesIndexRouteImport + parentRoute: typeof DashboardInvoicesRouteRouteImport } '/dashboard/users/': { id: '/dashboard/users/' path: '/' fullPath: '/dashboard/users/' - preLoaderRoute: typeof DashboardUsersIndexImport - parentRoute: typeof DashboardUsersRouteImport + preLoaderRoute: typeof DashboardUsersIndexRouteImport + parentRoute: typeof DashboardUsersRouteRouteImport } } } diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/_auth.profile.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/_auth.profile.tsx index fa63df98b0..5fb32c03cf 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/_auth.profile.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/_auth.profile.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/_auth/profile')({ component: ProfileComponent, diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/_auth.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/_auth.tsx index 30fdcf9f28..ed046d2046 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/_auth.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/_auth.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' import { auth } from '../utils/auth' export const Route = createFileRoute('/_auth')({ diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/_pathlessLayout.route-a.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/_pathlessLayout.route-a.tsx index ce791bcf2f..61167164f7 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/_pathlessLayout.route-a.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/_pathlessLayout.route-a.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/_pathlessLayout/route-a')({ component: LayoutAComponent, diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/_pathlessLayout.route-b.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/_pathlessLayout.route-b.tsx index aa3010287d..ed4fbcf142 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/_pathlessLayout.route-b.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/_pathlessLayout.route-b.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/_pathlessLayout/route-b')({ component: LayoutBComponent, diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/_pathlessLayout.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/_pathlessLayout.tsx index 1f13b66ee8..88dccf6e6f 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/_pathlessLayout.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/_pathlessLayout.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/_pathlessLayout')({ component: LayoutComponent, diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.index.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.index.tsx index 86fdaf1172..80bfdadb79 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.index.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.index.tsx @@ -1,5 +1,6 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' + import { useSuspenseQuery } from '@tanstack/react-query' import { invoicesQueryOptions } from '../utils/queryOptions' diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.invoices.$invoiceId.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.invoices.$invoiceId.tsx index 5a8a3c5308..94bcda4130 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.invoices.$invoiceId.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.invoices.$invoiceId.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, createFileRoute, useNavigate } from '@tanstack/react-router' +import { Link, useNavigate } from '@tanstack/react-router' import { useSuspenseQuery } from '@tanstack/react-query' import { z } from 'zod' import { InvoiceFields } from '../components/InvoiceFields' diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.invoices.index.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.invoices.index.tsx index 5537b15bb6..87288b034a 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.invoices.index.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.invoices.index.tsx @@ -1,5 +1,6 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' + import { InvoiceFields } from '../components/InvoiceFields' import { Spinner } from '../components/Spinner' import { useCreateInvoiceMutation } from '../utils/queryOptions' diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.invoices.route.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.invoices.route.tsx index 4c613cb7a7..54a03c9af4 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.invoices.route.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.invoices.route.tsx @@ -1,10 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { - Link, - MatchRoute, - Outlet, - createFileRoute, -} from '@tanstack/react-router' +import { Link, MatchRoute, Outlet } from '@tanstack/react-router' import { useSuspenseQuery } from '@tanstack/react-query' import { Spinner } from '../components/Spinner' import { invoicesQueryOptions } from '../utils/queryOptions' diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.route.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.route.tsx index fc6ac0701e..dd28d4d8be 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.route.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.route.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/dashboard')({ component: DashboardComponent, diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.users.index.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.users.index.tsx index 7ad9771152..8b9e85b6bd 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.users.index.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.users.index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/dashboard/users/')({ component: UsersIndexComponent, diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.users.route.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.users.route.tsx index e7b2eb2316..d18c515975 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.users.route.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.users.route.tsx @@ -1,10 +1,10 @@ +import { createFileRoute } from '@tanstack/react-router' /* eslint-disable @typescript-eslint/no-unnecessary-condition */ import * as React from 'react' import { Link, MatchRoute, Outlet, - createFileRoute, retainSearchParams, useNavigate, } from '@tanstack/react-router' diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.users.user.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.users.user.tsx index 0dece3c32f..e820f946f9 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.users.user.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/dashboard.users.user.tsx @@ -1,5 +1,6 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' + import { useSuspenseQuery } from '@tanstack/react-query' import { z } from 'zod' import { userQueryOptions } from '../utils/queryOptions' diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/index.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/index.tsx index a99ada182b..d1ed6b5141 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/index.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/index.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' export const Route = createFileRoute('/')({ component: IndexComponent, diff --git a/examples/react/kitchen-sink-react-query-file-based/src/routes/login.tsx b/examples/react/kitchen-sink-react-query-file-based/src/routes/login.tsx index bcc606ac33..03f439d65d 100644 --- a/examples/react/kitchen-sink-react-query-file-based/src/routes/login.tsx +++ b/examples/react/kitchen-sink-react-query-file-based/src/routes/login.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { createFileRoute, useRouter } from '@tanstack/react-router' +import { useRouter } from '@tanstack/react-router' import { z } from 'zod' export const Route = createFileRoute('/login')({ diff --git a/examples/react/kitchen-sink-react-query-file-based/vite.config.js b/examples/react/kitchen-sink-react-query-file-based/vite.config.js index b819774577..ab615485ae 100644 --- a/examples/react/kitchen-sink-react-query-file-based/vite.config.js +++ b/examples/react/kitchen-sink-react-query-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ target: 'react', autoCodeSplitting: true }), react(), ], }) diff --git a/examples/react/kitchen-sink-react-query/package.json b/examples/react/kitchen-sink-react-query/package.json index 24629dc4d7..34a718e4cc 100644 --- a/examples/react/kitchen-sink-react-query/package.json +++ b/examples/react/kitchen-sink-react-query/package.json @@ -11,8 +11,8 @@ "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "immer": "^10.1.1", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -27,6 +27,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/kitchen-sink/package.json b/examples/react/kitchen-sink/package.json index fcda245ccc..11852f182b 100644 --- a/examples/react/kitchen-sink/package.json +++ b/examples/react/kitchen-sink/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "immer": "^10.1.1", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -25,6 +25,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/kitchen-sink/src/main.tsx b/examples/react/kitchen-sink/src/main.tsx index 6c0c347284..3465637ce0 100644 --- a/examples/react/kitchen-sink/src/main.tsx +++ b/examples/react/kitchen-sink/src/main.tsx @@ -68,7 +68,7 @@ function RootComponent() { ['/route-a', 'Pathless Layout A'], ['/route-b', 'Pathless Layout B'], ['/profile', 'Profile'], - ['/login', 'Login'], + ...(auth.status === 'loggedOut' ? [['/login', 'Login']] : []), ] as const ).map(([to, label]) => { return ( @@ -642,6 +642,7 @@ const authPathlessLayoutRoute = createRoute({ beforeLoad: ({ context, location }) => { // If the user is logged out, redirect them to the login page if (context.auth.status === 'loggedOut') { + console.log(location) throw redirect({ to: loginRoute.to, search: { @@ -674,6 +675,15 @@ function ProfileComponent() {
Username:{username}
+
) } @@ -714,7 +724,10 @@ function LoginComponent() { Logged in as {auth.username}
diff --git a/examples/react/large-file-based/package.json b/examples/react/large-file-based/package.json index b028ce0f14..05c6f9eecd 100644 --- a/examples/react/large-file-based/package.json +++ b/examples/react/large-file-based/package.json @@ -12,9 +12,9 @@ }, "dependencies": { "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -28,6 +28,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/large-file-based/src/routeTree.gen.ts b/examples/react/large-file-based/src/routeTree.gen.ts index e4f3a85ab1..414c09c1e9 100644 --- a/examples/react/large-file-based/src/routeTree.gen.ts +++ b/examples/react/large-file-based/src/routeTree.gen.ts @@ -11,60 +11,60 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as RelativeImport } from './routes/relative' -import { Route as LinkPropsImport } from './routes/linkProps' -import { Route as AbsoluteImport } from './routes/absolute' -import { Route as SearchRouteImport } from './routes/search/route' -import { Route as ParamsRouteImport } from './routes/params/route' -import { Route as IndexImport } from './routes/index' -import { Route as SearchSearchPlaceholderImport } from './routes/search/searchPlaceholder' -import { Route as ParamsParamsPlaceholderImport } from './routes/params/$paramsPlaceholder' +import { Route as RelativeRouteImport } from './routes/relative' +import { Route as LinkPropsRouteImport } from './routes/linkProps' +import { Route as AbsoluteRouteImport } from './routes/absolute' +import { Route as SearchRouteRouteImport } from './routes/search/route' +import { Route as ParamsRouteRouteImport } from './routes/params/route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as SearchSearchPlaceholderRouteImport } from './routes/search/searchPlaceholder' +import { Route as ParamsParamsPlaceholderRouteImport } from './routes/params/$paramsPlaceholder' // Create/Update Routes -const RelativeRoute = RelativeImport.update({ +const RelativeRoute = RelativeRouteImport.update({ id: '/relative', path: '/relative', getParentRoute: () => rootRoute, } as any) -const LinkPropsRoute = LinkPropsImport.update({ +const LinkPropsRoute = LinkPropsRouteImport.update({ id: '/linkProps', path: '/linkProps', getParentRoute: () => rootRoute, } as any) -const AbsoluteRoute = AbsoluteImport.update({ +const AbsoluteRoute = AbsoluteRouteImport.update({ id: '/absolute', path: '/absolute', getParentRoute: () => rootRoute, } as any) -const SearchRouteRoute = SearchRouteImport.update({ +const SearchRouteRoute = SearchRouteRouteImport.update({ id: '/search', path: '/search', getParentRoute: () => rootRoute, } as any) -const ParamsRouteRoute = ParamsRouteImport.update({ +const ParamsRouteRoute = ParamsRouteRouteImport.update({ id: '/params', path: '/params', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const SearchSearchPlaceholderRoute = SearchSearchPlaceholderImport.update({ +const SearchSearchPlaceholderRoute = SearchSearchPlaceholderRouteImport.update({ id: '/searchPlaceholder', path: '/searchPlaceholder', getParentRoute: () => SearchRouteRoute, } as any) -const ParamsParamsPlaceholderRoute = ParamsParamsPlaceholderImport.update({ +const ParamsParamsPlaceholderRoute = ParamsParamsPlaceholderRouteImport.update({ id: '/$paramsPlaceholder', path: '/$paramsPlaceholder', getParentRoute: () => ParamsRouteRoute, @@ -78,57 +78,57 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/params': { id: '/params' path: '/params' fullPath: '/params' - preLoaderRoute: typeof ParamsRouteImport + preLoaderRoute: typeof ParamsRouteRouteImport parentRoute: typeof rootRoute } '/search': { id: '/search' path: '/search' fullPath: '/search' - preLoaderRoute: typeof SearchRouteImport + preLoaderRoute: typeof SearchRouteRouteImport parentRoute: typeof rootRoute } '/absolute': { id: '/absolute' path: '/absolute' fullPath: '/absolute' - preLoaderRoute: typeof AbsoluteImport + preLoaderRoute: typeof AbsoluteRouteImport parentRoute: typeof rootRoute } '/linkProps': { id: '/linkProps' path: '/linkProps' fullPath: '/linkProps' - preLoaderRoute: typeof LinkPropsImport + preLoaderRoute: typeof LinkPropsRouteImport parentRoute: typeof rootRoute } '/relative': { id: '/relative' path: '/relative' fullPath: '/relative' - preLoaderRoute: typeof RelativeImport + preLoaderRoute: typeof RelativeRouteImport parentRoute: typeof rootRoute } '/params/$paramsPlaceholder': { id: '/params/$paramsPlaceholder' path: '/$paramsPlaceholder' fullPath: '/params/$paramsPlaceholder' - preLoaderRoute: typeof ParamsParamsPlaceholderImport - parentRoute: typeof ParamsRouteImport + preLoaderRoute: typeof ParamsParamsPlaceholderRouteImport + parentRoute: typeof ParamsRouteRouteImport } '/search/searchPlaceholder': { id: '/search/searchPlaceholder' path: '/searchPlaceholder' fullPath: '/search/searchPlaceholder' - preLoaderRoute: typeof SearchSearchPlaceholderImport - parentRoute: typeof SearchRouteImport + preLoaderRoute: typeof SearchSearchPlaceholderRouteImport + parentRoute: typeof SearchRouteRouteImport } } } diff --git a/examples/react/large-file-based/src/routes/absolute.tsx b/examples/react/large-file-based/src/routes/absolute.tsx index ba1f875050..0dc5578842 100644 --- a/examples/react/large-file-based/src/routes/absolute.tsx +++ b/examples/react/large-file-based/src/routes/absolute.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' export const Route = createFileRoute('/absolute')({ component: AbsoluteComponent, diff --git a/examples/react/large-file-based/src/routes/index.tsx b/examples/react/large-file-based/src/routes/index.tsx index eac82a9174..0a5b7572ba 100644 --- a/examples/react/large-file-based/src/routes/index.tsx +++ b/examples/react/large-file-based/src/routes/index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/')({ component: Home, diff --git a/examples/react/large-file-based/src/routes/linkProps.tsx b/examples/react/large-file-based/src/routes/linkProps.tsx index 2811bcd5a8..d520cf0f96 100644 --- a/examples/react/large-file-based/src/routes/linkProps.tsx +++ b/examples/react/large-file-based/src/routes/linkProps.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, createFileRoute, linkOptions } from '@tanstack/react-router' +import { Link, linkOptions } from '@tanstack/react-router' export const Route = createFileRoute('/linkProps')({ component: LinkPropsPage, diff --git a/examples/react/large-file-based/src/routes/params/$paramsPlaceholder.tsx b/examples/react/large-file-based/src/routes/params/$paramsPlaceholder.tsx index 35f85eab9b..1442464a1c 100644 --- a/examples/react/large-file-based/src/routes/params/$paramsPlaceholder.tsx +++ b/examples/react/large-file-based/src/routes/params/$paramsPlaceholder.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { z } from 'zod' import { queryOptions } from '@tanstack/react-query' diff --git a/examples/react/large-file-based/src/routes/params/route.tsx b/examples/react/large-file-based/src/routes/params/route.tsx index 32f2b82024..0e29ec1e1e 100644 --- a/examples/react/large-file-based/src/routes/params/route.tsx +++ b/examples/react/large-file-based/src/routes/params/route.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/params')({ component: () =>
Hello /params!
, diff --git a/examples/react/large-file-based/src/routes/relative.tsx b/examples/react/large-file-based/src/routes/relative.tsx index 6f6e581efd..b2e8c7a10a 100644 --- a/examples/react/large-file-based/src/routes/relative.tsx +++ b/examples/react/large-file-based/src/routes/relative.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' export const Route = createFileRoute('/relative')({ component: RelativeComponent, diff --git a/examples/react/large-file-based/src/routes/search/route.tsx b/examples/react/large-file-based/src/routes/search/route.tsx index 364daefb12..33447e4c80 100644 --- a/examples/react/large-file-based/src/routes/search/route.tsx +++ b/examples/react/large-file-based/src/routes/search/route.tsx @@ -1,5 +1,6 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' + import { z } from 'zod' const search = z.object({ diff --git a/examples/react/large-file-based/src/routes/search/searchPlaceholder.tsx b/examples/react/large-file-based/src/routes/search/searchPlaceholder.tsx index 60372e8b98..8938899d13 100644 --- a/examples/react/large-file-based/src/routes/search/searchPlaceholder.tsx +++ b/examples/react/large-file-based/src/routes/search/searchPlaceholder.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { z } from 'zod' import { queryOptions } from '@tanstack/react-query' diff --git a/examples/react/large-file-based/vite.config.js b/examples/react/large-file-based/vite.config.js index b819774577..ab615485ae 100644 --- a/examples/react/large-file-based/vite.config.js +++ b/examples/react/large-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ target: 'react', autoCodeSplitting: true }), react(), ], }) diff --git a/examples/react/location-masking/package.json b/examples/react/location-masking/package.json index 76974a7fd6..49505885d8 100644 --- a/examples/react/location-masking/package.json +++ b/examples/react/location-masking/package.json @@ -11,8 +11,8 @@ "dependencies": { "@radix-ui/react-dialog": "^1.1.6", "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -25,6 +25,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/navigation-blocking/package.json b/examples/react/navigation-blocking/package.json index a02bbd11c7..eda61f2fb0 100644 --- a/examples/react/navigation-blocking/package.json +++ b/examples/react/navigation-blocking/package.json @@ -10,8 +10,8 @@ }, "dependencies": { "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -24,6 +24,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/quickstart-esbuild-file-based/esbuild.config.js b/examples/react/quickstart-esbuild-file-based/esbuild.config.js index 7edf067879..fb7950d1fa 100644 --- a/examples/react/quickstart-esbuild-file-based/esbuild.config.js +++ b/examples/react/quickstart-esbuild-file-based/esbuild.config.js @@ -1,4 +1,4 @@ -import { TanStackRouterEsbuild } from '@tanstack/router-plugin/esbuild' +import { tanstackRouter } from '@tanstack/router-plugin/esbuild' export default { jsx: 'transform', @@ -7,7 +7,5 @@ export default { bundle: true, format: 'esm', target: ['esnext'], - plugins: [ - TanStackRouterEsbuild({ target: 'react', autoCodeSplitting: true }), - ], + plugins: [tanstackRouter({ target: 'react', autoCodeSplitting: true })], } diff --git a/examples/react/quickstart-esbuild-file-based/package.json b/examples/react/quickstart-esbuild-file-based/package.json index a70374a87d..e8c111dc57 100644 --- a/examples/react/quickstart-esbuild-file-based/package.json +++ b/examples/react/quickstart-esbuild-file-based/package.json @@ -9,9 +9,9 @@ "start": "dev" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/quickstart-file-based/package.json b/examples/react/quickstart-file-based/package.json index f5ee2a99ee..b73ee47307 100644 --- a/examples/react/quickstart-file-based/package.json +++ b/examples/react/quickstart-file-based/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -25,6 +25,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/quickstart-file-based/src/routeTree.gen.ts b/examples/react/quickstart-file-based/src/routeTree.gen.ts index 48c183c8da..e758a6c2fe 100644 --- a/examples/react/quickstart-file-based/src/routeTree.gen.ts +++ b/examples/react/quickstart-file-based/src/routeTree.gen.ts @@ -11,18 +11,18 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as AboutImport } from './routes/about' -import { Route as IndexImport } from './routes/index' +import { Route as AboutRouteImport } from './routes/about' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const AboutRoute = AboutImport.update({ +const AboutRoute = AboutRouteImport.update({ id: '/about', path: '/about', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -36,14 +36,14 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/about': { id: '/about' path: '/about' fullPath: '/about' - preLoaderRoute: typeof AboutImport + preLoaderRoute: typeof AboutRouteImport parentRoute: typeof rootRoute } } diff --git a/examples/react/quickstart-file-based/src/routes/about.tsx b/examples/react/quickstart-file-based/src/routes/about.tsx index 492e6b85c2..02394cba28 100644 --- a/examples/react/quickstart-file-based/src/routes/about.tsx +++ b/examples/react/quickstart-file-based/src/routes/about.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/about')({ component: AboutComponent, diff --git a/examples/react/quickstart-file-based/src/routes/index.tsx b/examples/react/quickstart-file-based/src/routes/index.tsx index c4588fb2c9..978c498f1b 100644 --- a/examples/react/quickstart-file-based/src/routes/index.tsx +++ b/examples/react/quickstart-file-based/src/routes/index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/')({ component: HomeComponent, diff --git a/examples/react/quickstart-file-based/vite.config.js b/examples/react/quickstart-file-based/vite.config.js index b819774577..ab615485ae 100644 --- a/examples/react/quickstart-file-based/vite.config.js +++ b/examples/react/quickstart-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ target: 'react', autoCodeSplitting: true }), react(), ], }) diff --git a/examples/react/quickstart-rspack-file-based/package.json b/examples/react/quickstart-rspack-file-based/package.json index 950bfd7b4f..12d6553320 100644 --- a/examples/react/quickstart-rspack-file-based/package.json +++ b/examples/react/quickstart-rspack-file-based/package.json @@ -8,8 +8,8 @@ "preview": "rsbuild preview" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "postcss": "^8.5.1", @@ -19,7 +19,7 @@ "devDependencies": { "@rsbuild/core": "1.2.4", "@rsbuild/plugin-react": "1.1.0", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "typescript": "^5.6.2" diff --git a/examples/react/quickstart-rspack-file-based/rsbuild.config.ts b/examples/react/quickstart-rspack-file-based/rsbuild.config.ts index f9df4a1f45..faeba3dd9d 100644 --- a/examples/react/quickstart-rspack-file-based/rsbuild.config.ts +++ b/examples/react/quickstart-rspack-file-based/rsbuild.config.ts @@ -1,14 +1,12 @@ import { defineConfig } from '@rsbuild/core' import { pluginReact } from '@rsbuild/plugin-react' -import { TanStackRouterRspack } from '@tanstack/router-plugin/rspack' +import { tanstackRouter } from '@tanstack/router-plugin/rspack' export default defineConfig({ plugins: [pluginReact()], tools: { rspack: { - plugins: [ - TanStackRouterRspack({ target: 'react', autoCodeSplitting: true }), - ], + plugins: [tanstackRouter({ target: 'react', autoCodeSplitting: true })], }, }, }) diff --git a/examples/react/quickstart-rspack-file-based/src/routeTree.gen.ts b/examples/react/quickstart-rspack-file-based/src/routeTree.gen.ts index 48c183c8da..e758a6c2fe 100644 --- a/examples/react/quickstart-rspack-file-based/src/routeTree.gen.ts +++ b/examples/react/quickstart-rspack-file-based/src/routeTree.gen.ts @@ -11,18 +11,18 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as AboutImport } from './routes/about' -import { Route as IndexImport } from './routes/index' +import { Route as AboutRouteImport } from './routes/about' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const AboutRoute = AboutImport.update({ +const AboutRoute = AboutRouteImport.update({ id: '/about', path: '/about', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -36,14 +36,14 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/about': { id: '/about' path: '/about' fullPath: '/about' - preLoaderRoute: typeof AboutImport + preLoaderRoute: typeof AboutRouteImport parentRoute: typeof rootRoute } } diff --git a/examples/react/quickstart-rspack-file-based/src/routes/about.tsx b/examples/react/quickstart-rspack-file-based/src/routes/about.tsx index 492e6b85c2..02394cba28 100644 --- a/examples/react/quickstart-rspack-file-based/src/routes/about.tsx +++ b/examples/react/quickstart-rspack-file-based/src/routes/about.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/about')({ component: AboutComponent, diff --git a/examples/react/quickstart-rspack-file-based/src/routes/index.tsx b/examples/react/quickstart-rspack-file-based/src/routes/index.tsx index c4588fb2c9..978c498f1b 100644 --- a/examples/react/quickstart-rspack-file-based/src/routes/index.tsx +++ b/examples/react/quickstart-rspack-file-based/src/routes/index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/')({ component: HomeComponent, diff --git a/examples/react/quickstart-webpack-file-based/package.json b/examples/react/quickstart-webpack-file-based/package.json index 6dec44454f..f78e449fab 100644 --- a/examples/react/quickstart-webpack-file-based/package.json +++ b/examples/react/quickstart-webpack-file-based/package.json @@ -7,14 +7,14 @@ "build": "webpack build && tsc --noEmit" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0" }, "devDependencies": { "@swc/core": "^1.10.15", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "html-webpack-plugin": "^5.6.3", diff --git a/examples/react/quickstart-webpack-file-based/src/routeTree.gen.ts b/examples/react/quickstart-webpack-file-based/src/routeTree.gen.ts index 48c183c8da..e758a6c2fe 100644 --- a/examples/react/quickstart-webpack-file-based/src/routeTree.gen.ts +++ b/examples/react/quickstart-webpack-file-based/src/routeTree.gen.ts @@ -11,18 +11,18 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as AboutImport } from './routes/about' -import { Route as IndexImport } from './routes/index' +import { Route as AboutRouteImport } from './routes/about' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const AboutRoute = AboutImport.update({ +const AboutRoute = AboutRouteImport.update({ id: '/about', path: '/about', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -36,14 +36,14 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/about': { id: '/about' path: '/about' fullPath: '/about' - preLoaderRoute: typeof AboutImport + preLoaderRoute: typeof AboutRouteImport parentRoute: typeof rootRoute } } diff --git a/examples/react/quickstart-webpack-file-based/src/routes/about.tsx b/examples/react/quickstart-webpack-file-based/src/routes/about.tsx index 0d58b8cb0b..be940040b3 100644 --- a/examples/react/quickstart-webpack-file-based/src/routes/about.tsx +++ b/examples/react/quickstart-webpack-file-based/src/routes/about.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/about')({ component: AboutComponent, }) diff --git a/examples/react/quickstart-webpack-file-based/src/routes/index.tsx b/examples/react/quickstart-webpack-file-based/src/routes/index.tsx index c6b6b31c01..67fb33a03e 100644 --- a/examples/react/quickstart-webpack-file-based/src/routes/index.tsx +++ b/examples/react/quickstart-webpack-file-based/src/routes/index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/react-router' - export const Route = createFileRoute('/')({ component: HomeComponent, }) diff --git a/examples/react/quickstart-webpack-file-based/webpack.config.js b/examples/react/quickstart-webpack-file-based/webpack.config.js index 3ffe6281bd..d83e2bea10 100644 --- a/examples/react/quickstart-webpack-file-based/webpack.config.js +++ b/examples/react/quickstart-webpack-file-based/webpack.config.js @@ -1,7 +1,7 @@ import path from 'path' import { fileURLToPath } from 'url' import HtmlWebpackPlugin from 'html-webpack-plugin' -import { TanStackRouterWebpack } from '@tanstack/router-plugin/webpack' +import { tanstackRouter } from '@tanstack/router-plugin/webpack' const __dirname = fileURLToPath(new URL('.', import.meta.url)) @@ -23,7 +23,7 @@ export default ({ WEBPACK_SERVE }) => ({ template: path.resolve(__dirname, './public/index.html'), filename: 'index.html', }), - TanStackRouterWebpack({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ target: 'react', autoCodeSplitting: true }), ], module: { rules: [ diff --git a/examples/react/quickstart/package.json b/examples/react/quickstart/package.json index 68ee7d2a5d..fe145d93c0 100644 --- a/examples/react/quickstart/package.json +++ b/examples/react/quickstart/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "postcss": "^8.5.1", @@ -22,6 +22,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/router-monorepo-react-query/package.json b/examples/react/router-monorepo-react-query/package.json index d63d9c1272..ce390184f4 100644 --- a/examples/react/router-monorepo-react-query/package.json +++ b/examples/react/router-monorepo-react-query/package.json @@ -12,9 +12,9 @@ "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1" @@ -25,7 +25,7 @@ "@types/react-dom": "^19.0.3", "typescript": "^5.7.2", "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-dts": "^4.5.0" }, "keywords": [], diff --git a/examples/react/router-monorepo-react-query/packages/app/package.json b/examples/react/router-monorepo-react-query/packages/app/package.json index f108f10e39..9ad56dbae2 100644 --- a/examples/react/router-monorepo-react-query/packages/app/package.json +++ b/examples/react/router-monorepo-react-query/packages/app/package.json @@ -20,11 +20,11 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "postcss": "^8.5.1", "autoprefixer": "^10.4.20", "tailwindcss": "^3.4.17", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-dts": "^4.5.0" }, "nx": { diff --git a/examples/react/router-monorepo-react-query/packages/post-feature/package.json b/examples/react/router-monorepo-react-query/packages/post-feature/package.json index 8fd1b7da4f..ef4700d04f 100644 --- a/examples/react/router-monorepo-react-query/packages/post-feature/package.json +++ b/examples/react/router-monorepo-react-query/packages/post-feature/package.json @@ -19,7 +19,7 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-dts": "^4.5.0" } } diff --git a/examples/react/router-monorepo-react-query/packages/post-query/package.json b/examples/react/router-monorepo-react-query/packages/post-query/package.json index 1ea8a36e06..6f856efc89 100644 --- a/examples/react/router-monorepo-react-query/packages/post-query/package.json +++ b/examples/react/router-monorepo-react-query/packages/post-query/package.json @@ -15,6 +15,6 @@ "devDependencies": { "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/router-monorepo-react-query/packages/router/package.json b/examples/react/router-monorepo-react-query/packages/router/package.json index 87e0b53e46..411d7d396b 100644 --- a/examples/react/router-monorepo-react-query/packages/router/package.json +++ b/examples/react/router-monorepo-react-query/packages/router/package.json @@ -8,10 +8,10 @@ "main": "./dist/index.js", "types": "./dist/index.d.ts", "dependencies": { - "@tanstack/history": "^1.115.0", + "@tanstack/history": "^1.121.0-alpha.1", "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "@router-mono-react-query/post-query": "workspace:*", "redaxios": "^0.5.1", "zod": "^3.24.2", @@ -23,7 +23,7 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-dts": "^4.5.0" } } diff --git a/examples/react/router-monorepo-react-query/packages/router/src/routeTree.gen.ts b/examples/react/router-monorepo-react-query/packages/router/src/routeTree.gen.ts index 708707e98c..166cab84ad 100644 --- a/examples/react/router-monorepo-react-query/packages/router/src/routeTree.gen.ts +++ b/examples/react/router-monorepo-react-query/packages/router/src/routeTree.gen.ts @@ -11,18 +11,18 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PostIdImport } from './routes/$postId' -import { Route as IndexImport } from './routes/index' +import { Route as PostIdRouteImport } from './routes/$postId' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const PostIdRoute = PostIdImport.update({ +const PostIdRoute = PostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -36,14 +36,14 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/$postId': { id: '/$postId' path: '/$postId' fullPath: '/$postId' - preLoaderRoute: typeof PostIdImport + preLoaderRoute: typeof PostIdRouteImport parentRoute: typeof rootRoute } } diff --git a/examples/react/router-monorepo-react-query/packages/router/vite.config.ts b/examples/react/router-monorepo-react-query/packages/router/vite.config.ts index 7b846b67b0..b471bd3f58 100644 --- a/examples/react/router-monorepo-react-query/packages/router/vite.config.ts +++ b/examples/react/router-monorepo-react-query/packages/router/vite.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from 'vite' import dts from 'vite-plugin-dts' import * as path from 'node:path' import { fileURLToPath } from 'node:url' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' import react from '@vitejs/plugin-react' const __filename = fileURLToPath(import.meta.url) @@ -17,7 +17,7 @@ export default defineConfig({ tsconfigPath: path.join(__dirname, 'tsconfig.json'), }), react(), - TanStackRouterVite(), + tanstackRouter(), ], build: { outDir: './dist', diff --git a/examples/react/router-monorepo-simple-lazy/package.json b/examples/react/router-monorepo-simple-lazy/package.json index 8805fcadee..b7668b2185 100644 --- a/examples/react/router-monorepo-simple-lazy/package.json +++ b/examples/react/router-monorepo-simple-lazy/package.json @@ -8,9 +8,9 @@ "dev": "pnpm router build && pnpm post-feature build && pnpm app dev" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1" @@ -21,7 +21,7 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-dts": "^4.5.0" }, "keywords": [], diff --git a/examples/react/router-monorepo-simple-lazy/packages/app/package.json b/examples/react/router-monorepo-simple-lazy/packages/app/package.json index 6e8e6a773b..cf58cd6adf 100644 --- a/examples/react/router-monorepo-simple-lazy/packages/app/package.json +++ b/examples/react/router-monorepo-simple-lazy/packages/app/package.json @@ -19,11 +19,11 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "postcss": "^8.5.1", "autoprefixer": "^10.4.20", "tailwindcss": "^3.4.17", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-dts": "^4.5.0" }, "nx": { diff --git a/examples/react/router-monorepo-simple-lazy/packages/post-feature/package.json b/examples/react/router-monorepo-simple-lazy/packages/post-feature/package.json index 9efcefe894..324c49737a 100644 --- a/examples/react/router-monorepo-simple-lazy/packages/post-feature/package.json +++ b/examples/react/router-monorepo-simple-lazy/packages/post-feature/package.json @@ -26,7 +26,7 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-dts": "^4.5.0" } } diff --git a/examples/react/router-monorepo-simple-lazy/packages/router/package.json b/examples/react/router-monorepo-simple-lazy/packages/router/package.json index 4ab5a93131..66eeae2383 100644 --- a/examples/react/router-monorepo-simple-lazy/packages/router/package.json +++ b/examples/react/router-monorepo-simple-lazy/packages/router/package.json @@ -8,9 +8,9 @@ "main": "./dist/index.js", "types": "./dist/index.d.ts", "dependencies": { - "@tanstack/history": "^1.115.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/history": "^1.121.0-alpha.1", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "redaxios": "^0.5.1", "zod": "^3.24.2", "react": "^19.0.0", @@ -21,7 +21,7 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-dts": "^4.5.0" } } diff --git a/examples/react/router-monorepo-simple-lazy/packages/router/src/routeTree.gen.ts b/examples/react/router-monorepo-simple-lazy/packages/router/src/routeTree.gen.ts index 708707e98c..166cab84ad 100644 --- a/examples/react/router-monorepo-simple-lazy/packages/router/src/routeTree.gen.ts +++ b/examples/react/router-monorepo-simple-lazy/packages/router/src/routeTree.gen.ts @@ -11,18 +11,18 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PostIdImport } from './routes/$postId' -import { Route as IndexImport } from './routes/index' +import { Route as PostIdRouteImport } from './routes/$postId' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const PostIdRoute = PostIdImport.update({ +const PostIdRoute = PostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -36,14 +36,14 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/$postId': { id: '/$postId' path: '/$postId' fullPath: '/$postId' - preLoaderRoute: typeof PostIdImport + preLoaderRoute: typeof PostIdRouteImport parentRoute: typeof rootRoute } } diff --git a/examples/react/router-monorepo-simple-lazy/packages/router/vite.config.ts b/examples/react/router-monorepo-simple-lazy/packages/router/vite.config.ts index d71c28ac2d..21aa5e70f4 100644 --- a/examples/react/router-monorepo-simple-lazy/packages/router/vite.config.ts +++ b/examples/react/router-monorepo-simple-lazy/packages/router/vite.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from 'vite' import dts from 'vite-plugin-dts' import * as path from 'node:path' import { fileURLToPath } from 'node:url' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' import react from '@vitejs/plugin-react' const __filename = fileURLToPath(import.meta.url) @@ -15,7 +15,7 @@ export default defineConfig({ tsconfigPath: path.join(__dirname, 'tsconfig.json'), }), react(), - TanStackRouterVite(), + tanstackRouter(), ], build: { outDir: './dist', diff --git a/examples/react/router-monorepo-simple/package.json b/examples/react/router-monorepo-simple/package.json index 35e73aefb1..1d8fc320e1 100644 --- a/examples/react/router-monorepo-simple/package.json +++ b/examples/react/router-monorepo-simple/package.json @@ -8,9 +8,9 @@ "dev": "pnpm router build && pnpm post-feature build && pnpm app dev" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1" @@ -21,7 +21,7 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-dts": "^4.5.0" }, "keywords": [], diff --git a/examples/react/router-monorepo-simple/packages/app/package.json b/examples/react/router-monorepo-simple/packages/app/package.json index 3b1f2e4cb1..dfc0cc4081 100644 --- a/examples/react/router-monorepo-simple/packages/app/package.json +++ b/examples/react/router-monorepo-simple/packages/app/package.json @@ -19,8 +19,8 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "@tanstack/react-router-devtools": "^1.120.3", - "vite": "^6.1.0", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "vite": "^6.3.5", "postcss": "^8.5.1", "autoprefixer": "^10.4.20", "tailwindcss": "^3.4.17", diff --git a/examples/react/router-monorepo-simple/packages/post-feature/package.json b/examples/react/router-monorepo-simple/packages/post-feature/package.json index fec8618c23..2a5ff9288e 100644 --- a/examples/react/router-monorepo-simple/packages/post-feature/package.json +++ b/examples/react/router-monorepo-simple/packages/post-feature/package.json @@ -17,7 +17,7 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-dts": "^4.5.0" } } diff --git a/examples/react/router-monorepo-simple/packages/router/package.json b/examples/react/router-monorepo-simple/packages/router/package.json index 8f110580a1..f7f253a0a6 100644 --- a/examples/react/router-monorepo-simple/packages/router/package.json +++ b/examples/react/router-monorepo-simple/packages/router/package.json @@ -8,9 +8,9 @@ "main": "./dist/index.js", "types": "./dist/index.d.ts", "dependencies": { - "@tanstack/history": "^1.115.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/history": "^1.121.0-alpha.1", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "redaxios": "^0.5.1", "zod": "^3.24.2", "react": "^19.0.0", @@ -21,7 +21,7 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-dts": "^4.5.0" } } diff --git a/examples/react/router-monorepo-simple/packages/router/src/routeTree.gen.ts b/examples/react/router-monorepo-simple/packages/router/src/routeTree.gen.ts index 708707e98c..166cab84ad 100644 --- a/examples/react/router-monorepo-simple/packages/router/src/routeTree.gen.ts +++ b/examples/react/router-monorepo-simple/packages/router/src/routeTree.gen.ts @@ -11,18 +11,18 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PostIdImport } from './routes/$postId' -import { Route as IndexImport } from './routes/index' +import { Route as PostIdRouteImport } from './routes/$postId' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const PostIdRoute = PostIdImport.update({ +const PostIdRoute = PostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -36,14 +36,14 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/$postId': { id: '/$postId' path: '/$postId' fullPath: '/$postId' - preLoaderRoute: typeof PostIdImport + preLoaderRoute: typeof PostIdRouteImport parentRoute: typeof rootRoute } } diff --git a/examples/react/router-monorepo-simple/packages/router/vite.config.ts b/examples/react/router-monorepo-simple/packages/router/vite.config.ts index d71c28ac2d..21aa5e70f4 100644 --- a/examples/react/router-monorepo-simple/packages/router/vite.config.ts +++ b/examples/react/router-monorepo-simple/packages/router/vite.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from 'vite' import dts from 'vite-plugin-dts' import * as path from 'node:path' import { fileURLToPath } from 'node:url' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' import react from '@vitejs/plugin-react' const __filename = fileURLToPath(import.meta.url) @@ -15,7 +15,7 @@ export default defineConfig({ tsconfigPath: path.join(__dirname, 'tsconfig.json'), }), react(), - TanStackRouterVite(), + tanstackRouter(), ], build: { outDir: './dist', diff --git a/examples/react/scroll-restoration/package.json b/examples/react/scroll-restoration/package.json index 8e07cf2589..f10caa054d 100644 --- a/examples/react/scroll-restoration/package.json +++ b/examples/react/scroll-restoration/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", "@tanstack/react-virtual": "^3.13.0", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "postcss": "^8.5.1", @@ -23,6 +23,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/search-validator-adapters/package.json b/examples/react/search-validator-adapters/package.json index af25aedde5..ebdfc391cb 100644 --- a/examples/react/search-validator-adapters/package.json +++ b/examples/react/search-validator-adapters/package.json @@ -10,13 +10,13 @@ "test:unit": "vitest" }, "dependencies": { - "@tanstack/arktype-adapter": "^1.120.3", + "@tanstack/arktype-adapter": "^1.121.0-alpha.11", "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", - "@tanstack/valibot-adapter": "^1.120.3", - "@tanstack/zod-adapter": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", + "@tanstack/valibot-adapter": "^1.121.0-alpha.11", + "@tanstack/zod-adapter": "^1.121.0-alpha.11", "arktype": "^2.1.7", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -33,6 +33,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/search-validator-adapters/src/routeTree.gen.ts b/examples/react/search-validator-adapters/src/routeTree.gen.ts index 4e8d04aa89..a90eb1dfcd 100644 --- a/examples/react/search-validator-adapters/src/routeTree.gen.ts +++ b/examples/react/search-validator-adapters/src/routeTree.gen.ts @@ -8,35 +8,37 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' -import { Route as UsersZodIndexImport } from './routes/users/zod.index' -import { Route as UsersValibotIndexImport } from './routes/users/valibot.index' -import { Route as UsersArktypeIndexImport } from './routes/users/arktype.index' +import { Route as IndexRouteImport } from './routes/index' +import { Route as UsersZodIndexRouteImport } from './routes/users/zod.index' +import { Route as UsersValibotIndexRouteImport } from './routes/users/valibot.index' +import { Route as UsersArktypeIndexRouteImport } from './routes/users/arktype.index' // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const UsersZodIndexRoute = UsersZodIndexImport.update({ +const UsersZodIndexRoute = UsersZodIndexRouteImport.update({ id: '/users/zod/', path: '/users/zod/', getParentRoute: () => rootRoute, } as any) -const UsersValibotIndexRoute = UsersValibotIndexImport.update({ +const UsersValibotIndexRoute = UsersValibotIndexRouteImport.update({ id: '/users/valibot/', path: '/users/valibot/', getParentRoute: () => rootRoute, } as any) -const UsersArktypeIndexRoute = UsersArktypeIndexImport.update({ +const UsersArktypeIndexRoute = UsersArktypeIndexRouteImport.update({ id: '/users/arktype/', path: '/users/arktype/', getParentRoute: () => rootRoute, @@ -50,33 +52,72 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/users/arktype/': { id: '/users/arktype/' path: '/users/arktype' fullPath: '/users/arktype' - preLoaderRoute: typeof UsersArktypeIndexImport + preLoaderRoute: typeof UsersArktypeIndexRouteImport parentRoute: typeof rootRoute } '/users/valibot/': { id: '/users/valibot/' path: '/users/valibot' fullPath: '/users/valibot' - preLoaderRoute: typeof UsersValibotIndexImport + preLoaderRoute: typeof UsersValibotIndexRouteImport parentRoute: typeof rootRoute } '/users/zod/': { id: '/users/zod/' path: '/users/zod' fullPath: '/users/zod' - preLoaderRoute: typeof UsersZodIndexImport + preLoaderRoute: typeof UsersZodIndexRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/users/arktype.index' { + const createFileRoute: CreateFileRoute< + '/users/arktype/', + FileRoutesByPath['/users/arktype/']['parentRoute'], + FileRoutesByPath['/users/arktype/']['id'], + FileRoutesByPath['/users/arktype/']['path'], + FileRoutesByPath['/users/arktype/']['fullPath'] + > +} +declare module './routes/users/valibot.index' { + const createFileRoute: CreateFileRoute< + '/users/valibot/', + FileRoutesByPath['/users/valibot/']['parentRoute'], + FileRoutesByPath['/users/valibot/']['id'], + FileRoutesByPath['/users/valibot/']['path'], + FileRoutesByPath['/users/valibot/']['fullPath'] + > +} +declare module './routes/users/zod.index' { + const createFileRoute: CreateFileRoute< + '/users/zod/', + FileRoutesByPath['/users/zod/']['parentRoute'], + FileRoutesByPath['/users/zod/']['id'], + FileRoutesByPath['/users/zod/']['path'], + FileRoutesByPath['/users/zod/']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/examples/react/search-validator-adapters/src/routes/index.tsx b/examples/react/search-validator-adapters/src/routes/index.tsx index c00341b613..e279d9c1e0 100644 --- a/examples/react/search-validator-adapters/src/routes/index.tsx +++ b/examples/react/search-validator-adapters/src/routes/index.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' + import { Header } from '../components/Header' import { Content } from '../components/Content' @@ -12,6 +12,6 @@ export const Index: React.FunctionComponent = () => { ) } -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Index, }) diff --git a/examples/react/search-validator-adapters/src/routes/users/arktype.index.tsx b/examples/react/search-validator-adapters/src/routes/users/arktype.index.tsx index 3595f1ef01..38af594c85 100644 --- a/examples/react/search-validator-adapters/src/routes/users/arktype.index.tsx +++ b/examples/react/search-validator-adapters/src/routes/users/arktype.index.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { createFileRoute, useNavigate } from '@tanstack/react-router' +import { useNavigate } from '@tanstack/react-router' import { type } from 'arktype' import { Header } from '../../components/Header' import { Users, usersQueryOptions } from '../../components/Users' @@ -32,7 +32,7 @@ const search = type({ search: 'string = ""', }) -export const Route = createFileRoute('/users/arktype/')({ +export const Route = createFileRoute({ validateSearch: search, loaderDeps: (opt) => ({ search: opt.search }), loader: (opt) => { diff --git a/examples/react/search-validator-adapters/src/routes/users/valibot.index.tsx b/examples/react/search-validator-adapters/src/routes/users/valibot.index.tsx index 33ff6623f0..1a8bc7dd18 100644 --- a/examples/react/search-validator-adapters/src/routes/users/valibot.index.tsx +++ b/examples/react/search-validator-adapters/src/routes/users/valibot.index.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { createFileRoute, useNavigate } from '@tanstack/react-router' +import { useNavigate } from '@tanstack/react-router' import * as v from 'valibot' import { Header } from '../../components/Header' import { Users, usersQueryOptions } from '../../components/Users' @@ -26,7 +26,7 @@ const Valibot = () => { ) } -export const Route = createFileRoute('/users/valibot/')({ +export const Route = createFileRoute({ validateSearch: v.object({ search: v.fallback(v.optional(v.string(), ''), ''), }), diff --git a/examples/react/search-validator-adapters/src/routes/users/zod.index.tsx b/examples/react/search-validator-adapters/src/routes/users/zod.index.tsx index 7a94b04d54..8f095d156f 100644 --- a/examples/react/search-validator-adapters/src/routes/users/zod.index.tsx +++ b/examples/react/search-validator-adapters/src/routes/users/zod.index.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { createFileRoute, useNavigate } from '@tanstack/react-router' +import { useNavigate } from '@tanstack/react-router' import { fallback, zodValidator } from '@tanstack/zod-adapter' import { z } from 'zod' import { Header } from '../../components/Header' @@ -29,7 +29,7 @@ const Zod = () => { ) } -export const Route = createFileRoute('/users/zod/')({ +export const Route = createFileRoute({ validateSearch: zodValidator( z.object({ search: fallback(z.string().optional(), undefined), diff --git a/examples/react/search-validator-adapters/vite.config.ts b/examples/react/search-validator-adapters/vite.config.ts index 8cf11338ed..a14d94a148 100644 --- a/examples/react/search-validator-adapters/vite.config.ts +++ b/examples/react/search-validator-adapters/vite.config.ts @@ -1,6 +1,6 @@ import { defineConfig } from 'vitest/config' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' import packageJson from './package.json' export default defineConfig({ @@ -12,7 +12,11 @@ export default defineConfig({ typecheck: { enabled: true }, }, plugins: [ - TanStackRouterVite({ target: 'react', autoCodeSplitting: true }), + tanstackRouter({ + target: 'react', + autoCodeSplitting: true, + verboseFileRoutes: false, + }), react(), ], }) diff --git a/examples/react/start-bare/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-bare/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/examples/react/start-bare/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-bare/app.config.ts b/examples/react/start-bare/app.config.ts deleted file mode 100644 index 775bee171b..0000000000 --- a/examples/react/start-bare/app.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - tailwindcss(), - ], - }, -}) diff --git a/examples/react/start-bare/package.json b/examples/react/start-bare/package.json index c87ecebfde..f1dab67729 100644 --- a/examples/react/start-bare/package.json +++ b/examples/react/start-bare/package.json @@ -4,17 +4,16 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/examples/react/start-bare/src/api.ts b/examples/react/start-bare/src/api.ts deleted file mode 100644 index 8b9fef1667..0000000000 --- a/examples/react/start-bare/src/api.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { - createStartAPIHandler, - defaultAPIFileRouteHandler, -} from '@tanstack/react-start/api' - -export default createStartAPIHandler(defaultAPIFileRouteHandler) diff --git a/examples/react/start-bare/src/client.tsx b/examples/react/start-bare/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-bare/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-bare/src/routeTree.gen.ts b/examples/react/start-bare/src/routeTree.gen.ts index 48c183c8da..3f5c19883b 100644 --- a/examples/react/start-bare/src/routeTree.gen.ts +++ b/examples/react/start-bare/src/routeTree.gen.ts @@ -8,21 +8,23 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as AboutImport } from './routes/about' -import { Route as IndexImport } from './routes/index' +import { Route as AboutRouteImport } from './routes/about' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const AboutRoute = AboutImport.update({ +const AboutRoute = AboutRouteImport.update({ id: '/about', path: '/about', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -36,19 +38,40 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/about': { id: '/about' path: '/about' fullPath: '/about' - preLoaderRoute: typeof AboutImport + preLoaderRoute: typeof AboutRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/about' { + const createFileRoute: CreateFileRoute< + '/about', + FileRoutesByPath['/about']['parentRoute'], + FileRoutesByPath['/about']['id'], + FileRoutesByPath['/about']['path'], + FileRoutesByPath['/about']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/examples/react/start-bare/src/routes/about.tsx b/examples/react/start-bare/src/routes/about.tsx index ca401c33c7..f0d5d234a0 100644 --- a/examples/react/start-bare/src/routes/about.tsx +++ b/examples/react/start-bare/src/routes/about.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/about')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/examples/react/start-bare/src/routes/index.tsx b/examples/react/start-bare/src/routes/index.tsx index e9de615dc9..bd87c0bf42 100644 --- a/examples/react/start-bare/src/routes/index.tsx +++ b/examples/react/start-bare/src/routes/index.tsx @@ -1,6 +1,5 @@ -import { createFileRoute } from '@tanstack/react-router' import Counter from '~/components/Counter' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/examples/react/start-bare/src/ssr.tsx b/examples/react/start-bare/src/ssr.tsx deleted file mode 100644 index 65a580f25e..0000000000 --- a/examples/react/start-bare/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-bare/src/tanstack-start.d.ts b/examples/react/start-bare/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-bare/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-bare/vite.config.ts b/examples/react/start-bare/vite.config.ts new file mode 100644 index 0000000000..1f5fd1961a --- /dev/null +++ b/examples/react/start-bare/vite.config.ts @@ -0,0 +1,15 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/examples/react/start-basic-auth/.gitignore b/examples/react/start-basic-auth/.gitignore index b15fed94e2..2818549158 100644 --- a/examples/react/start-basic-auth/.gitignore +++ b/examples/react/start-basic-auth/.gitignore @@ -7,14 +7,10 @@ yarn.lock .cache .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/start-basic-auth/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-basic-auth/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/examples/react/start-basic-auth/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-basic-auth/app.config.ts b/examples/react/start-basic-auth/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/examples/react/start-basic-auth/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/examples/react/start-basic-auth/package.json b/examples/react/start-basic-auth/package.json index 554777cc4e..33aa4d3678 100644 --- a/examples/react/start-basic-auth/package.json +++ b/examples/react/start-basic-auth/package.json @@ -4,22 +4,21 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start", + "dev": "vite dev", + "build": "vite build", + "start": "vite start", "prisma-generate": "prisma generate" }, "dependencies": { "@prisma/client": "5.22.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "prisma": "^5.22.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/react/start-basic-auth/src/client.tsx b/examples/react/start-basic-auth/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-basic-auth/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-basic-auth/src/routeTree.gen.ts b/examples/react/start-basic-auth/src/routeTree.gen.ts index 8c5a37a7e8..c7cab2e4d5 100644 --- a/examples/react/start-basic-auth/src/routeTree.gen.ts +++ b/examples/react/start-basic-auth/src/routeTree.gen.ts @@ -8,62 +8,64 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as SignupImport } from './routes/signup' -import { Route as LogoutImport } from './routes/logout' -import { Route as LoginImport } from './routes/login' -import { Route as AuthedImport } from './routes/_authed' -import { Route as IndexImport } from './routes/index' -import { Route as AuthedPostsRouteImport } from './routes/_authed/posts.route' -import { Route as AuthedPostsIndexImport } from './routes/_authed/posts.index' -import { Route as AuthedPostsPostIdImport } from './routes/_authed/posts.$postId' +import { Route as SignupRouteImport } from './routes/signup' +import { Route as LogoutRouteImport } from './routes/logout' +import { Route as LoginRouteImport } from './routes/login' +import { Route as AuthedRouteImport } from './routes/_authed' +import { Route as IndexRouteImport } from './routes/index' +import { Route as AuthedPostsRouteRouteImport } from './routes/_authed/posts.route' +import { Route as AuthedPostsIndexRouteImport } from './routes/_authed/posts.index' +import { Route as AuthedPostsPostIdRouteImport } from './routes/_authed/posts.$postId' // Create/Update Routes -const SignupRoute = SignupImport.update({ +const SignupRoute = SignupRouteImport.update({ id: '/signup', path: '/signup', getParentRoute: () => rootRoute, } as any) -const LogoutRoute = LogoutImport.update({ +const LogoutRoute = LogoutRouteImport.update({ id: '/logout', path: '/logout', getParentRoute: () => rootRoute, } as any) -const LoginRoute = LoginImport.update({ +const LoginRoute = LoginRouteImport.update({ id: '/login', path: '/login', getParentRoute: () => rootRoute, } as any) -const AuthedRoute = AuthedImport.update({ +const AuthedRoute = AuthedRouteImport.update({ id: '/_authed', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const AuthedPostsRouteRoute = AuthedPostsRouteImport.update({ +const AuthedPostsRouteRoute = AuthedPostsRouteRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => AuthedRoute, } as any) -const AuthedPostsIndexRoute = AuthedPostsIndexImport.update({ +const AuthedPostsIndexRoute = AuthedPostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => AuthedPostsRouteRoute, } as any) -const AuthedPostsPostIdRoute = AuthedPostsPostIdImport.update({ +const AuthedPostsPostIdRoute = AuthedPostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => AuthedPostsRouteRoute, @@ -77,61 +79,136 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_authed': { id: '/_authed' path: '' fullPath: '' - preLoaderRoute: typeof AuthedImport + preLoaderRoute: typeof AuthedRouteImport parentRoute: typeof rootRoute } '/login': { id: '/login' path: '/login' fullPath: '/login' - preLoaderRoute: typeof LoginImport + preLoaderRoute: typeof LoginRouteImport parentRoute: typeof rootRoute } '/logout': { id: '/logout' path: '/logout' fullPath: '/logout' - preLoaderRoute: typeof LogoutImport + preLoaderRoute: typeof LogoutRouteImport parentRoute: typeof rootRoute } '/signup': { id: '/signup' path: '/signup' fullPath: '/signup' - preLoaderRoute: typeof SignupImport + preLoaderRoute: typeof SignupRouteImport parentRoute: typeof rootRoute } '/_authed/posts': { id: '/_authed/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof AuthedPostsRouteImport - parentRoute: typeof AuthedImport + preLoaderRoute: typeof AuthedPostsRouteRouteImport + parentRoute: typeof AuthedRouteImport } '/_authed/posts/$postId': { id: '/_authed/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof AuthedPostsPostIdImport - parentRoute: typeof AuthedPostsRouteImport + preLoaderRoute: typeof AuthedPostsPostIdRouteImport + parentRoute: typeof AuthedPostsRouteRouteImport } '/_authed/posts/': { id: '/_authed/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof AuthedPostsIndexImport - parentRoute: typeof AuthedPostsRouteImport + preLoaderRoute: typeof AuthedPostsIndexRouteImport + parentRoute: typeof AuthedPostsRouteRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_authed' { + const createFileRoute: CreateFileRoute< + '/_authed', + FileRoutesByPath['/_authed']['parentRoute'], + FileRoutesByPath['/_authed']['id'], + FileRoutesByPath['/_authed']['path'], + FileRoutesByPath['/_authed']['fullPath'] + > +} +declare module './routes/login' { + const createFileRoute: CreateFileRoute< + '/login', + FileRoutesByPath['/login']['parentRoute'], + FileRoutesByPath['/login']['id'], + FileRoutesByPath['/login']['path'], + FileRoutesByPath['/login']['fullPath'] + > +} +declare module './routes/logout' { + const createFileRoute: CreateFileRoute< + '/logout', + FileRoutesByPath['/logout']['parentRoute'], + FileRoutesByPath['/logout']['id'], + FileRoutesByPath['/logout']['path'], + FileRoutesByPath['/logout']['fullPath'] + > +} +declare module './routes/signup' { + const createFileRoute: CreateFileRoute< + '/signup', + FileRoutesByPath['/signup']['parentRoute'], + FileRoutesByPath['/signup']['id'], + FileRoutesByPath['/signup']['path'], + FileRoutesByPath['/signup']['fullPath'] + > +} +declare module './routes/_authed/posts.route' { + const createFileRoute: CreateFileRoute< + '/_authed/posts', + FileRoutesByPath['/_authed/posts']['parentRoute'], + FileRoutesByPath['/_authed/posts']['id'], + FileRoutesByPath['/_authed/posts']['path'], + FileRoutesByPath['/_authed/posts']['fullPath'] + > +} +declare module './routes/_authed/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/_authed/posts/$postId', + FileRoutesByPath['/_authed/posts/$postId']['parentRoute'], + FileRoutesByPath['/_authed/posts/$postId']['id'], + FileRoutesByPath['/_authed/posts/$postId']['path'], + FileRoutesByPath['/_authed/posts/$postId']['fullPath'] + > +} +declare module './routes/_authed/posts.index' { + const createFileRoute: CreateFileRoute< + '/_authed/posts/', + FileRoutesByPath['/_authed/posts/']['parentRoute'], + FileRoutesByPath['/_authed/posts/']['id'], + FileRoutesByPath['/_authed/posts/']['path'], + FileRoutesByPath['/_authed/posts/']['fullPath'] + > +} + // Create and export the route tree interface AuthedPostsRouteRouteChildren { diff --git a/examples/react/start-basic-auth/src/routes/_authed.tsx b/examples/react/start-basic-auth/src/routes/_authed.tsx index 3944e590f9..f1049611a4 100644 --- a/examples/react/start-basic-auth/src/routes/_authed.tsx +++ b/examples/react/start-basic-auth/src/routes/_authed.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import { hashPassword, prismaClient } from '~/utils/prisma' import { Login } from '~/components/Login' @@ -42,7 +41,7 @@ export const loginFn = createServerFn({ method: 'POST' }) }) }) -export const Route = createFileRoute('/_authed')({ +export const Route = createFileRoute({ beforeLoad: ({ context }) => { if (!context.user) { throw new Error('Not authenticated') diff --git a/examples/react/start-basic-auth/src/routes/_authed/posts.$postId.tsx b/examples/react/start-basic-auth/src/routes/_authed/posts.$postId.tsx index 039271bb89..c6c36f3ea4 100644 --- a/examples/react/start-basic-auth/src/routes/_authed/posts.$postId.tsx +++ b/examples/react/start-basic-auth/src/routes/_authed/posts.$postId.tsx @@ -1,9 +1,9 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import type { ErrorComponentProps } from '@tanstack/react-router' import { NotFound } from '~/components/NotFound.js' import { fetchPost } from '~/utils/posts.js' -export const Route = createFileRoute('/_authed/posts/$postId')({ +export const Route = createFileRoute({ loader: ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, diff --git a/examples/react/start-basic-auth/src/routes/_authed/posts.index.tsx b/examples/react/start-basic-auth/src/routes/_authed/posts.index.tsx index ea9e667e54..13529228bb 100644 --- a/examples/react/start-basic-auth/src/routes/_authed/posts.index.tsx +++ b/examples/react/start-basic-auth/src/routes/_authed/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_authed/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/examples/react/start-basic-auth/src/routes/_authed/posts.route.tsx b/examples/react/start-basic-auth/src/routes/_authed/posts.route.tsx index 86c8ef4138..f9b50197cf 100644 --- a/examples/react/start-basic-auth/src/routes/_authed/posts.route.tsx +++ b/examples/react/start-basic-auth/src/routes/_authed/posts.route.tsx @@ -1,7 +1,7 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '~/utils/posts.js' -export const Route = createFileRoute('/_authed/posts')({ +export const Route = createFileRoute({ loader: () => fetchPosts(), component: PostsComponent, }) diff --git a/examples/react/start-basic-auth/src/routes/index.tsx b/examples/react/start-basic-auth/src/routes/index.tsx index 09a907cb18..f6c5b98b02 100644 --- a/examples/react/start-basic-auth/src/routes/index.tsx +++ b/examples/react/start-basic-auth/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/examples/react/start-basic-auth/src/routes/login.tsx b/examples/react/start-basic-auth/src/routes/login.tsx index 03ced20832..269ca5e816 100644 --- a/examples/react/start-basic-auth/src/routes/login.tsx +++ b/examples/react/start-basic-auth/src/routes/login.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import { Login } from '~/components/Login' -export const Route = createFileRoute('/login')({ +export const Route = createFileRoute({ component: LoginComp, }) diff --git a/examples/react/start-basic-auth/src/routes/logout.tsx b/examples/react/start-basic-auth/src/routes/logout.tsx index d072c25008..a7023a1793 100644 --- a/examples/react/start-basic-auth/src/routes/logout.tsx +++ b/examples/react/start-basic-auth/src/routes/logout.tsx @@ -1,4 +1,4 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import { useAppSession } from '~/utils/session' @@ -12,7 +12,7 @@ const logoutFn = createServerFn().handler(async () => { }) }) -export const Route = createFileRoute('/logout')({ +export const Route = createFileRoute({ preload: false, loader: () => logoutFn(), }) diff --git a/examples/react/start-basic-auth/src/routes/signup.tsx b/examples/react/start-basic-auth/src/routes/signup.tsx index 8f052d3629..a8dbef283b 100644 --- a/examples/react/start-basic-auth/src/routes/signup.tsx +++ b/examples/react/start-basic-auth/src/routes/signup.tsx @@ -1,4 +1,4 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' import { createServerFn, useServerFn } from '@tanstack/react-start' import { hashPassword, prismaClient } from '~/utils/prisma' import { useMutation } from '~/hooks/useMutation' @@ -62,7 +62,7 @@ export const signupFn = createServerFn({ method: 'POST' }) }) }) -export const Route = createFileRoute('/signup')({ +export const Route = createFileRoute({ component: SignupComp, }) diff --git a/examples/react/start-basic-auth/src/ssr.tsx b/examples/react/start-basic-auth/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-basic-auth/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-basic-auth/src/tanstack-start.d.ts b/examples/react/start-basic-auth/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-basic-auth/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-basic-auth/vite.config.ts b/examples/react/start-basic-auth/vite.config.ts new file mode 100644 index 0000000000..1f5fd1961a --- /dev/null +++ b/examples/react/start-basic-auth/vite.config.ts @@ -0,0 +1,15 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/examples/react/start-basic-react-query/.gitignore b/examples/react/start-basic-react-query/.gitignore index be342025da..ca63f49885 100644 --- a/examples/react/start-basic-react-query/.gitignore +++ b/examples/react/start-basic-react-query/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/start-basic-react-query/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-basic-react-query/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/examples/react/start-basic-react-query/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-basic-react-query/app.config.ts b/examples/react/start-basic-react-query/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/examples/react/start-basic-react-query/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/examples/react/start-basic-react-query/package.json b/examples/react/start-basic-react-query/package.json index 9c27d1a42d..b470e17a35 100644 --- a/examples/react/start-basic-react-query/package.json +++ b/examples/react/start-basic-react-query/package.json @@ -4,22 +4,21 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-with-query": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-with-query": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/react/start-basic-react-query/src/client.tsx b/examples/react/start-basic-react-query/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-basic-react-query/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-basic-react-query/src/routeTree.gen.ts b/examples/react/start-basic-react-query/src/routeTree.gen.ts index 4dca20ee9c..3c6af11ae1 100644 --- a/examples/react/start-basic-react-query/src/routeTree.gen.ts +++ b/examples/react/start-basic-react-query/src/routeTree.gen.ts @@ -8,107 +8,108 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as RedirectImport } from './routes/redirect' -import { Route as DeferredImport } from './routes/deferred' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as UsersRouteImport } from './routes/users.route' -import { Route as PostsRouteImport } from './routes/posts.route' -import { Route as IndexImport } from './routes/index' -import { Route as UsersIndexImport } from './routes/users.index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as UsersUserIdImport } from './routes/users.$userId' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as PathlessLayoutNestedLayoutImport } from './routes/_pathlessLayout/_nested-layout' -import { Route as PostsPostIdDeepImport } from './routes/posts_.$postId.deep' -import { Route as PathlessLayoutNestedLayoutRouteBImport } from './routes/_pathlessLayout/_nested-layout/route-b' -import { Route as PathlessLayoutNestedLayoutRouteAImport } from './routes/_pathlessLayout/_nested-layout/route-a' +import { Route as RedirectRouteImport } from './routes/redirect' +import { Route as DeferredRouteImport } from './routes/deferred' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as UsersRouteRouteImport } from './routes/users.route' +import { Route as PostsRouteRouteImport } from './routes/posts.route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as UsersIndexRouteImport } from './routes/users.index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as UsersUserIdRouteImport } from './routes/users.$userId' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts_.$postId.deep' +import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' +import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' // Create/Update Routes -const RedirectRoute = RedirectImport.update({ +const RedirectRoute = RedirectRouteImport.update({ id: '/redirect', path: '/redirect', getParentRoute: () => rootRoute, } as any) -const DeferredRoute = DeferredImport.update({ +const DeferredRoute = DeferredRouteImport.update({ id: '/deferred', path: '/deferred', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const UsersRouteRoute = UsersRouteImport.update({ +const UsersRouteRoute = UsersRouteRouteImport.update({ id: '/users', path: '/users', getParentRoute: () => rootRoute, } as any) -const PostsRouteRoute = PostsRouteImport.update({ +const PostsRouteRoute = PostsRouteRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const UsersIndexRoute = UsersIndexImport.update({ +const UsersIndexRoute = UsersIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => UsersRouteRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRouteRoute, } as any) -const UsersUserIdRoute = UsersUserIdImport.update({ +const UsersUserIdRoute = UsersUserIdRouteImport.update({ id: '/$userId', path: '/$userId', getParentRoute: () => UsersRouteRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRouteRoute, } as any) -const PathlessLayoutNestedLayoutRoute = PathlessLayoutNestedLayoutImport.update( - { +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ id: '/_nested-layout', getParentRoute: () => PathlessLayoutRoute, - } as any, -) + } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/posts_/$postId/deep', path: '/posts/$postId/deep', getParentRoute: () => rootRoute, } as any) const PathlessLayoutNestedLayoutRouteBRoute = - PathlessLayoutNestedLayoutRouteBImport.update({ + PathlessLayoutNestedLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutNestedLayoutRoute, } as any) const PathlessLayoutNestedLayoutRouteARoute = - PathlessLayoutNestedLayoutRouteAImport.update({ + PathlessLayoutNestedLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutNestedLayoutRoute, @@ -122,103 +123,232 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsRouteRouteImport parentRoute: typeof rootRoute } '/users': { id: '/users' path: '/users' fullPath: '/users' - preLoaderRoute: typeof UsersRouteImport + preLoaderRoute: typeof UsersRouteRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/deferred': { id: '/deferred' path: '/deferred' fullPath: '/deferred' - preLoaderRoute: typeof DeferredImport + preLoaderRoute: typeof DeferredRouteImport parentRoute: typeof rootRoute } '/redirect': { id: '/redirect' path: '/redirect' fullPath: '/redirect' - preLoaderRoute: typeof RedirectImport + preLoaderRoute: typeof RedirectRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout/_nested-layout': { id: '/_pathlessLayout/_nested-layout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutNestedLayoutImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteRouteImport } '/users/$userId': { id: '/users/$userId' path: '/$userId' fullPath: '/users/$userId' - preLoaderRoute: typeof UsersUserIdImport - parentRoute: typeof UsersRouteImport + preLoaderRoute: typeof UsersUserIdRouteImport + parentRoute: typeof UsersRouteRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteRouteImport } '/users/': { id: '/users/' path: '/' fullPath: '/users/' - preLoaderRoute: typeof UsersIndexImport - parentRoute: typeof UsersRouteImport + preLoaderRoute: typeof UsersIndexRouteImport + parentRoute: typeof UsersRouteRouteImport } '/_pathlessLayout/_nested-layout/route-a': { id: '/_pathlessLayout/_nested-layout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteAImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/_pathlessLayout/_nested-layout/route-b': { id: '/_pathlessLayout/_nested-layout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/posts_/$postId/deep': { id: '/posts_/$postId/deep' path: '/posts/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport + preLoaderRoute: typeof PostsPostIdDeepRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/posts.route' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/users.route' { + const createFileRoute: CreateFileRoute< + '/users', + FileRoutesByPath['/users']['parentRoute'], + FileRoutesByPath['/users']['id'], + FileRoutesByPath['/users']['path'], + FileRoutesByPath['/users']['fullPath'] + > +} +declare module './routes/_pathlessLayout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout', + FileRoutesByPath['/_pathlessLayout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout']['id'], + FileRoutesByPath['/_pathlessLayout']['path'], + FileRoutesByPath['/_pathlessLayout']['fullPath'] + > +} +declare module './routes/deferred' { + const createFileRoute: CreateFileRoute< + '/deferred', + FileRoutesByPath['/deferred']['parentRoute'], + FileRoutesByPath['/deferred']['id'], + FileRoutesByPath['/deferred']['path'], + FileRoutesByPath['/deferred']['fullPath'] + > +} +declare module './routes/redirect' { + const createFileRoute: CreateFileRoute< + '/redirect', + FileRoutesByPath['/redirect']['parentRoute'], + FileRoutesByPath['/redirect']['id'], + FileRoutesByPath['/redirect']['path'], + FileRoutesByPath['/redirect']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout', + FileRoutesByPath['/_pathlessLayout/_nested-layout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/users.$userId' { + const createFileRoute: CreateFileRoute< + '/users/$userId', + FileRoutesByPath['/users/$userId']['parentRoute'], + FileRoutesByPath['/users/$userId']['id'], + FileRoutesByPath['/users/$userId']['path'], + FileRoutesByPath['/users/$userId']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/users.index' { + const createFileRoute: CreateFileRoute< + '/users/', + FileRoutesByPath['/users/']['parentRoute'], + FileRoutesByPath['/users/']['id'], + FileRoutesByPath['/users/']['path'], + FileRoutesByPath['/users/']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-a' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-a', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-b' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-b', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['fullPath'] + > +} +declare module './routes/posts_.$postId.deep' { + const createFileRoute: CreateFileRoute< + '/posts_/$postId/deep', + FileRoutesByPath['/posts_/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > +} + // Create and export the route tree interface PostsRouteRouteChildren { diff --git a/examples/react/start-basic-react-query/src/routes/_pathlessLayout.tsx b/examples/react/start-basic-react-query/src/routes/_pathlessLayout.tsx index 3353841595..209e478e44 100644 --- a/examples/react/start-basic-react-query/src/routes/_pathlessLayout.tsx +++ b/examples/react/start-basic-react-query/src/routes/_pathlessLayout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout')({ +export const Route = createFileRoute({ component: PathlessLayoutComponent, }) diff --git a/examples/react/start-basic-react-query/src/routes/_pathlessLayout/_nested-layout.tsx b/examples/react/start-basic-react-query/src/routes/_pathlessLayout/_nested-layout.tsx index 0dcb1270ad..97f5dc3ea3 100644 --- a/examples/react/start-basic-react-query/src/routes/_pathlessLayout/_nested-layout.tsx +++ b/examples/react/start-basic-react-query/src/routes/_pathlessLayout/_nested-layout.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({ +export const Route = createFileRoute({ component: PathlessLayoutComponent, }) diff --git a/examples/react/start-basic-react-query/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/examples/react/start-basic-react-query/src/routes/_pathlessLayout/_nested-layout/route-a.tsx index 426a8fe486..a0bd5240b7 100644 --- a/examples/react/start-basic-react-query/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +++ b/examples/react/start-basic-react-query/src/routes/_pathlessLayout/_nested-layout/route-a.tsx @@ -1,10 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')( - { - component: LayoutAComponent, - }, -) +export const Route = createFileRoute({ + component: LayoutAComponent, +}) function LayoutAComponent() { return
I'm A!
diff --git a/examples/react/start-basic-react-query/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/examples/react/start-basic-react-query/src/routes/_pathlessLayout/_nested-layout/route-b.tsx index 20facf2daf..2864ec1f28 100644 --- a/examples/react/start-basic-react-query/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +++ b/examples/react/start-basic-react-query/src/routes/_pathlessLayout/_nested-layout/route-b.tsx @@ -1,10 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')( - { - component: LayoutBComponent, - }, -) +export const Route = createFileRoute({ + component: LayoutBComponent, +}) function LayoutBComponent() { return
I'm B!
diff --git a/examples/react/start-basic-react-query/src/routes/deferred.tsx b/examples/react/start-basic-react-query/src/routes/deferred.tsx index 666ae26e49..16a9f72593 100644 --- a/examples/react/start-basic-react-query/src/routes/deferred.tsx +++ b/examples/react/start-basic-react-query/src/routes/deferred.tsx @@ -1,5 +1,5 @@ import { queryOptions, useSuspenseQuery } from '@tanstack/react-query' -import { createFileRoute } from '@tanstack/react-router' +import {} from '@tanstack/react-router' import { Suspense, useState } from 'react' const deferredQueryOptions = () => @@ -15,7 +15,7 @@ const deferredQueryOptions = () => }, }) -export const Route = createFileRoute('/deferred')({ +export const Route = createFileRoute({ loader: ({ context }) => { // Kick off loading as early as possible! context.queryClient.prefetchQuery(deferredQueryOptions()) diff --git a/examples/react/start-basic-react-query/src/routes/index.tsx b/examples/react/start-basic-react-query/src/routes/index.tsx index 09a907cb18..f6c5b98b02 100644 --- a/examples/react/start-basic-react-query/src/routes/index.tsx +++ b/examples/react/start-basic-react-query/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/examples/react/start-basic-react-query/src/routes/posts.$postId.tsx b/examples/react/start-basic-react-query/src/routes/posts.$postId.tsx index 542a12a9f6..e8098c4a2f 100644 --- a/examples/react/start-basic-react-query/src/routes/posts.$postId.tsx +++ b/examples/react/start-basic-react-query/src/routes/posts.$postId.tsx @@ -1,10 +1,10 @@ -import { ErrorComponent, Link, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent, Link } from '@tanstack/react-router' import { useSuspenseQuery } from '@tanstack/react-query' import { postQueryOptions } from '../utils/posts' import type { ErrorComponentProps } from '@tanstack/react-router' import { NotFound } from '~/components/NotFound' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId }, context }) => { const data = await context.queryClient.ensureQueryData( postQueryOptions(postId), @@ -42,7 +42,7 @@ function PostComponent() { postId: postQuery.data.id, }} activeProps={{ className: 'text-black font-bold' }} - className="block py-1 text-blue-800 hover:text-blue-600" + className="inline-block py-1 text-blue-800 hover:text-blue-600" > Deep View diff --git a/examples/react/start-basic-react-query/src/routes/posts.index.tsx b/examples/react/start-basic-react-query/src/routes/posts.index.tsx index 5b5f08f95b..13529228bb 100644 --- a/examples/react/start-basic-react-query/src/routes/posts.index.tsx +++ b/examples/react/start-basic-react-query/src/routes/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/examples/react/start-basic-react-query/src/routes/posts.route.tsx b/examples/react/start-basic-react-query/src/routes/posts.route.tsx index b545663be2..4fbfb471c1 100644 --- a/examples/react/start-basic-react-query/src/routes/posts.route.tsx +++ b/examples/react/start-basic-react-query/src/routes/posts.route.tsx @@ -1,8 +1,8 @@ import { useSuspenseQuery } from '@tanstack/react-query' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { postsQueryOptions } from '../utils/posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: async ({ context }) => { await context.queryClient.ensureQueryData(postsQueryOptions()) }, diff --git a/examples/react/start-basic-react-query/src/routes/posts_.$postId.deep.tsx b/examples/react/start-basic-react-query/src/routes/posts_.$postId.deep.tsx index 33f6475a55..4d91776273 100644 --- a/examples/react/start-basic-react-query/src/routes/posts_.$postId.deep.tsx +++ b/examples/react/start-basic-react-query/src/routes/posts_.$postId.deep.tsx @@ -1,9 +1,9 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { useSuspenseQuery } from '@tanstack/react-query' import { postQueryOptions } from '../utils/posts' import { PostErrorComponent } from './posts.$postId' -export const Route = createFileRoute('/posts_/$postId/deep')({ +export const Route = createFileRoute({ loader: async ({ params: { postId }, context }) => { const data = await context.queryClient.ensureQueryData( postQueryOptions(postId), diff --git a/examples/react/start-basic-react-query/src/routes/redirect.tsx b/examples/react/start-basic-react-query/src/routes/redirect.tsx index c9286de13d..68a98d5683 100644 --- a/examples/react/start-basic-react-query/src/routes/redirect.tsx +++ b/examples/react/start-basic-react-query/src/routes/redirect.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect')({ +export const Route = createFileRoute({ beforeLoad: async () => { throw redirect({ to: '/posts', diff --git a/examples/react/start-basic-react-query/src/routes/users.$userId.tsx b/examples/react/start-basic-react-query/src/routes/users.$userId.tsx index 0750a01568..176be186e0 100644 --- a/examples/react/start-basic-react-query/src/routes/users.$userId.tsx +++ b/examples/react/start-basic-react-query/src/routes/users.$userId.tsx @@ -1,10 +1,10 @@ import { useSuspenseQuery } from '@tanstack/react-query' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import type { ErrorComponentProps } from '@tanstack/react-router' import { NotFound } from '~/components/NotFound' import { userQueryOptions } from '~/utils/users' -export const Route = createFileRoute('/users/$userId')({ +export const Route = createFileRoute({ loader: async ({ context, params: { userId } }) => { await context.queryClient.ensureQueryData(userQueryOptions(userId)) }, diff --git a/examples/react/start-basic-react-query/src/routes/users.index.tsx b/examples/react/start-basic-react-query/src/routes/users.index.tsx index b6b0ee67fb..662e8b6c68 100644 --- a/examples/react/start-basic-react-query/src/routes/users.index.tsx +++ b/examples/react/start-basic-react-query/src/routes/users.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/users/')({ +export const Route = createFileRoute({ component: UsersIndexComponent, }) diff --git a/examples/react/start-basic-react-query/src/routes/users.route.tsx b/examples/react/start-basic-react-query/src/routes/users.route.tsx index 2f3c72cb7b..80ce468130 100644 --- a/examples/react/start-basic-react-query/src/routes/users.route.tsx +++ b/examples/react/start-basic-react-query/src/routes/users.route.tsx @@ -1,8 +1,8 @@ import { useSuspenseQuery } from '@tanstack/react-query' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { usersQueryOptions } from '../utils/users' -export const Route = createFileRoute('/users')({ +export const Route = createFileRoute({ loader: async ({ context }) => { await context.queryClient.ensureQueryData(usersQueryOptions()) }, diff --git a/examples/react/start-basic-react-query/src/ssr.tsx b/examples/react/start-basic-react-query/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-basic-react-query/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-basic-react-query/src/tanstack-start.d.ts b/examples/react/start-basic-react-query/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-basic-react-query/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-basic-react-query/vite.config.ts b/examples/react/start-basic-react-query/vite.config.ts new file mode 100644 index 0000000000..1f5fd1961a --- /dev/null +++ b/examples/react/start-basic-react-query/vite.config.ts @@ -0,0 +1,15 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/examples/react/start-basic-rsc/.gitignore b/examples/react/start-basic-rsc/.gitignore index d3387e00cd..3c8e6870b3 100644 --- a/examples/react/start-basic-rsc/.gitignore +++ b/examples/react/start-basic-rsc/.gitignore @@ -7,12 +7,8 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin diff --git a/examples/react/start-basic-rsc/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-basic-rsc/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/examples/react/start-basic-rsc/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-basic-rsc/app.config.ts b/examples/react/start-basic-rsc/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/examples/react/start-basic-rsc/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/examples/react/start-basic-rsc/package.json b/examples/react/start-basic-rsc/package.json index e526759a5b..4cf291797f 100644 --- a/examples/react/start-basic-rsc/package.json +++ b/examples/react/start-basic-rsc/package.json @@ -4,20 +4,19 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { "@babel/plugin-syntax-typescript": "^7.25.9", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@types/react": "^19.0.8", diff --git a/examples/react/start-basic-rsc/src/client.tsx b/examples/react/start-basic-rsc/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-basic-rsc/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-basic-rsc/src/routeTree.gen.ts b/examples/react/start-basic-rsc/src/routeTree.gen.ts index 1465b03fd1..d59964eeca 100644 --- a/examples/react/start-basic-rsc/src/routeTree.gen.ts +++ b/examples/react/start-basic-rsc/src/routeTree.gen.ts @@ -8,72 +8,73 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PostsImport } from './routes/posts' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as PathlessLayoutNestedLayoutImport } from './routes/_pathlessLayout/_nested-layout' -import { Route as PostsPostIdDeepImport } from './routes/posts_.$postId.deep' -import { Route as PathlessLayoutNestedLayoutRouteBImport } from './routes/_pathlessLayout/_nested-layout/route-b' -import { Route as PathlessLayoutNestedLayoutRouteAImport } from './routes/_pathlessLayout/_nested-layout/route-a' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts_.$postId.deep' +import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' +import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' // Create/Update Routes -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const PathlessLayoutNestedLayoutRoute = PathlessLayoutNestedLayoutImport.update( - { +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ id: '/_nested-layout', getParentRoute: () => PathlessLayoutRoute, - } as any, -) + } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/posts_/$postId/deep', path: '/posts/$postId/deep', getParentRoute: () => rootRoute, } as any) const PathlessLayoutNestedLayoutRouteBRoute = - PathlessLayoutNestedLayoutRouteBImport.update({ + PathlessLayoutNestedLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutNestedLayoutRoute, } as any) const PathlessLayoutNestedLayoutRouteARoute = - PathlessLayoutNestedLayoutRouteAImport.update({ + PathlessLayoutNestedLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutNestedLayoutRoute, @@ -87,68 +88,152 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout/_nested-layout': { id: '/_pathlessLayout/_nested-layout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutNestedLayoutImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/_pathlessLayout/_nested-layout/route-a': { id: '/_pathlessLayout/_nested-layout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteAImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/_pathlessLayout/_nested-layout/route-b': { id: '/_pathlessLayout/_nested-layout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/posts_/$postId/deep': { id: '/posts_/$postId/deep' path: '/posts/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport + preLoaderRoute: typeof PostsPostIdDeepRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_pathlessLayout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout', + FileRoutesByPath['/_pathlessLayout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout']['id'], + FileRoutesByPath['/_pathlessLayout']['path'], + FileRoutesByPath['/_pathlessLayout']['fullPath'] + > +} +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout', + FileRoutesByPath['/_pathlessLayout/_nested-layout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-a' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-a', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-b' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-b', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['fullPath'] + > +} +declare module './routes/posts_.$postId.deep' { + const createFileRoute: CreateFileRoute< + '/posts_/$postId/deep', + FileRoutesByPath['/posts_/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > +} + // Create and export the route tree interface PathlessLayoutNestedLayoutRouteChildren { diff --git a/examples/react/start-basic-rsc/src/routes/_pathlessLayout.tsx b/examples/react/start-basic-rsc/src/routes/_pathlessLayout.tsx index c3b12442b8..5c4a461d8d 100644 --- a/examples/react/start-basic-rsc/src/routes/_pathlessLayout.tsx +++ b/examples/react/start-basic-rsc/src/routes/_pathlessLayout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/examples/react/start-basic-rsc/src/routes/_pathlessLayout/_nested-layout.tsx b/examples/react/start-basic-rsc/src/routes/_pathlessLayout/_nested-layout.tsx index c5bcffd5a4..abd82a2bf6 100644 --- a/examples/react/start-basic-rsc/src/routes/_pathlessLayout/_nested-layout.tsx +++ b/examples/react/start-basic-rsc/src/routes/_pathlessLayout/_nested-layout.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/examples/react/start-basic-rsc/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/examples/react/start-basic-rsc/src/routes/_pathlessLayout/_nested-layout/route-a.tsx index 426a8fe486..a0bd5240b7 100644 --- a/examples/react/start-basic-rsc/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +++ b/examples/react/start-basic-rsc/src/routes/_pathlessLayout/_nested-layout/route-a.tsx @@ -1,10 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')( - { - component: LayoutAComponent, - }, -) +export const Route = createFileRoute({ + component: LayoutAComponent, +}) function LayoutAComponent() { return
I'm A!
diff --git a/examples/react/start-basic-rsc/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/examples/react/start-basic-rsc/src/routes/_pathlessLayout/_nested-layout/route-b.tsx index 20facf2daf..2864ec1f28 100644 --- a/examples/react/start-basic-rsc/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +++ b/examples/react/start-basic-rsc/src/routes/_pathlessLayout/_nested-layout/route-b.tsx @@ -1,10 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')( - { - component: LayoutBComponent, - }, -) +export const Route = createFileRoute({ + component: LayoutBComponent, +}) function LayoutBComponent() { return
I'm B!
diff --git a/examples/react/start-basic-rsc/src/routes/index.tsx b/examples/react/start-basic-rsc/src/routes/index.tsx index b7b6138529..a693dcbf14 100644 --- a/examples/react/start-basic-rsc/src/routes/index.tsx +++ b/examples/react/start-basic-rsc/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/examples/react/start-basic-rsc/src/routes/posts.$postId.tsx b/examples/react/start-basic-rsc/src/routes/posts.$postId.tsx index 5404a690a0..736bb2499d 100644 --- a/examples/react/start-basic-rsc/src/routes/posts.$postId.tsx +++ b/examples/react/start-basic-rsc/src/routes/posts.$postId.tsx @@ -1,4 +1,4 @@ -import { ErrorComponent, Link, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent, Link } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import { fetchPost } from '../utils/posts' import type { ErrorComponentProps } from '@tanstack/react-router' @@ -27,7 +27,7 @@ const renderPost = createServerFn({ method: 'GET' }) ) }) -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => renderPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, diff --git a/examples/react/start-basic-rsc/src/routes/posts.index.tsx b/examples/react/start-basic-rsc/src/routes/posts.index.tsx index 5b5f08f95b..13529228bb 100644 --- a/examples/react/start-basic-rsc/src/routes/posts.index.tsx +++ b/examples/react/start-basic-rsc/src/routes/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/examples/react/start-basic-rsc/src/routes/posts.tsx b/examples/react/start-basic-rsc/src/routes/posts.tsx index a3ef2a2e20..131cec4b9b 100644 --- a/examples/react/start-basic-rsc/src/routes/posts.tsx +++ b/examples/react/start-basic-rsc/src/routes/posts.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' import { createServerFn, renderRsc } from '@tanstack/react-start' import { renderPosts } from '~/utils/renderPosts' @@ -6,7 +5,7 @@ export const serverRenderPosts = createServerFn({ method: 'GET' }).handler( renderPosts, ) -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: async () => serverRenderPosts(), component: PostsComponent, }) diff --git a/examples/react/start-basic-rsc/src/routes/posts_.$postId.deep.tsx b/examples/react/start-basic-rsc/src/routes/posts_.$postId.deep.tsx index 13d368cf9c..bf2edef3c9 100644 --- a/examples/react/start-basic-rsc/src/routes/posts_.$postId.deep.tsx +++ b/examples/react/start-basic-rsc/src/routes/posts_.$postId.deep.tsx @@ -1,8 +1,8 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { fetchPost } from '../utils/posts' import { PostErrorComponent } from './posts.$postId' -export const Route = createFileRoute('/posts_/$postId/deep')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost(postId), errorComponent: PostErrorComponent, component: PostDeepComponent, diff --git a/examples/react/start-basic-rsc/src/ssr.tsx b/examples/react/start-basic-rsc/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-basic-rsc/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-basic-rsc/src/tanstack-start.d.ts b/examples/react/start-basic-rsc/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-basic-rsc/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-basic-rsc/vite.config.ts b/examples/react/start-basic-rsc/vite.config.ts new file mode 100644 index 0000000000..1f5fd1961a --- /dev/null +++ b/examples/react/start-basic-rsc/vite.config.ts @@ -0,0 +1,15 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/examples/react/start-basic-static/.gitignore b/examples/react/start-basic-static/.gitignore index be342025da..ca63f49885 100644 --- a/examples/react/start-basic-static/.gitignore +++ b/examples/react/start-basic-static/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/start-basic-static/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-basic-static/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/examples/react/start-basic-static/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-basic-static/app.config.ts b/examples/react/start-basic-static/app.config.ts deleted file mode 100644 index e6854562f8..0000000000 --- a/examples/react/start-basic-static/app.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, - server: { - preset: 'netlify', - prerender: { - routes: ['/'], - crawlLinks: true, - }, - }, -}) diff --git a/examples/react/start-basic-static/package.json b/examples/react/start-basic-static/package.json index 5481062895..53930db1c5 100644 --- a/examples/react/start-basic-static/package.json +++ b/examples/react/start-basic-static/package.json @@ -4,19 +4,18 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.5.5", - "vinxi": "0.5.1" + "tailwind-merge": "^2.5.5" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/react/start-basic-static/src/client.tsx b/examples/react/start-basic-static/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-basic-static/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-basic-static/src/routeTree.gen.ts b/examples/react/start-basic-static/src/routeTree.gen.ts index 762ce1516f..a3ca3d53c4 100644 --- a/examples/react/start-basic-static/src/routeTree.gen.ts +++ b/examples/react/start-basic-static/src/routeTree.gen.ts @@ -8,107 +8,108 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as UsersImport } from './routes/users' -import { Route as RedirectImport } from './routes/redirect' -import { Route as PostsImport } from './routes/posts' -import { Route as DeferredImport } from './routes/deferred' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as IndexImport } from './routes/index' -import { Route as UsersIndexImport } from './routes/users.index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as UsersUserIdImport } from './routes/users.$userId' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as PathlessLayoutNestedLayoutImport } from './routes/_pathlessLayout/_nested-layout' -import { Route as PostsPostIdDeepImport } from './routes/posts_.$postId.deep' -import { Route as PathlessLayoutNestedLayoutRouteBImport } from './routes/_pathlessLayout/_nested-layout/route-b' -import { Route as PathlessLayoutNestedLayoutRouteAImport } from './routes/_pathlessLayout/_nested-layout/route-a' +import { Route as UsersRouteImport } from './routes/users' +import { Route as RedirectRouteImport } from './routes/redirect' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as DeferredRouteImport } from './routes/deferred' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as UsersIndexRouteImport } from './routes/users.index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as UsersUserIdRouteImport } from './routes/users.$userId' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts_.$postId.deep' +import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' +import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' // Create/Update Routes -const UsersRoute = UsersImport.update({ +const UsersRoute = UsersRouteImport.update({ id: '/users', path: '/users', getParentRoute: () => rootRoute, } as any) -const RedirectRoute = RedirectImport.update({ +const RedirectRoute = RedirectRouteImport.update({ id: '/redirect', path: '/redirect', getParentRoute: () => rootRoute, } as any) -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const DeferredRoute = DeferredImport.update({ +const DeferredRoute = DeferredRouteImport.update({ id: '/deferred', path: '/deferred', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const UsersIndexRoute = UsersIndexImport.update({ +const UsersIndexRoute = UsersIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => UsersRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const UsersUserIdRoute = UsersUserIdImport.update({ +const UsersUserIdRoute = UsersUserIdRouteImport.update({ id: '/$userId', path: '/$userId', getParentRoute: () => UsersRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const PathlessLayoutNestedLayoutRoute = PathlessLayoutNestedLayoutImport.update( - { +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ id: '/_nested-layout', getParentRoute: () => PathlessLayoutRoute, - } as any, -) + } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/posts_/$postId/deep', path: '/posts/$postId/deep', getParentRoute: () => rootRoute, } as any) const PathlessLayoutNestedLayoutRouteBRoute = - PathlessLayoutNestedLayoutRouteBImport.update({ + PathlessLayoutNestedLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutNestedLayoutRoute, } as any) const PathlessLayoutNestedLayoutRouteARoute = - PathlessLayoutNestedLayoutRouteAImport.update({ + PathlessLayoutNestedLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutNestedLayoutRoute, @@ -122,103 +123,232 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/deferred': { id: '/deferred' path: '/deferred' fullPath: '/deferred' - preLoaderRoute: typeof DeferredImport + preLoaderRoute: typeof DeferredRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/redirect': { id: '/redirect' path: '/redirect' fullPath: '/redirect' - preLoaderRoute: typeof RedirectImport + preLoaderRoute: typeof RedirectRouteImport parentRoute: typeof rootRoute } '/users': { id: '/users' path: '/users' fullPath: '/users' - preLoaderRoute: typeof UsersImport + preLoaderRoute: typeof UsersRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout/_nested-layout': { id: '/_pathlessLayout/_nested-layout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutNestedLayoutImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/users/$userId': { id: '/users/$userId' path: '/$userId' fullPath: '/users/$userId' - preLoaderRoute: typeof UsersUserIdImport - parentRoute: typeof UsersImport + preLoaderRoute: typeof UsersUserIdRouteImport + parentRoute: typeof UsersRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/users/': { id: '/users/' path: '/' fullPath: '/users/' - preLoaderRoute: typeof UsersIndexImport - parentRoute: typeof UsersImport + preLoaderRoute: typeof UsersIndexRouteImport + parentRoute: typeof UsersRouteImport } '/_pathlessLayout/_nested-layout/route-a': { id: '/_pathlessLayout/_nested-layout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteAImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/_pathlessLayout/_nested-layout/route-b': { id: '/_pathlessLayout/_nested-layout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/posts_/$postId/deep': { id: '/posts_/$postId/deep' path: '/posts/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport + preLoaderRoute: typeof PostsPostIdDeepRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_pathlessLayout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout', + FileRoutesByPath['/_pathlessLayout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout']['id'], + FileRoutesByPath['/_pathlessLayout']['path'], + FileRoutesByPath['/_pathlessLayout']['fullPath'] + > +} +declare module './routes/deferred' { + const createFileRoute: CreateFileRoute< + '/deferred', + FileRoutesByPath['/deferred']['parentRoute'], + FileRoutesByPath['/deferred']['id'], + FileRoutesByPath['/deferred']['path'], + FileRoutesByPath['/deferred']['fullPath'] + > +} +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/redirect' { + const createFileRoute: CreateFileRoute< + '/redirect', + FileRoutesByPath['/redirect']['parentRoute'], + FileRoutesByPath['/redirect']['id'], + FileRoutesByPath['/redirect']['path'], + FileRoutesByPath['/redirect']['fullPath'] + > +} +declare module './routes/users' { + const createFileRoute: CreateFileRoute< + '/users', + FileRoutesByPath['/users']['parentRoute'], + FileRoutesByPath['/users']['id'], + FileRoutesByPath['/users']['path'], + FileRoutesByPath['/users']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout', + FileRoutesByPath['/_pathlessLayout/_nested-layout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/users.$userId' { + const createFileRoute: CreateFileRoute< + '/users/$userId', + FileRoutesByPath['/users/$userId']['parentRoute'], + FileRoutesByPath['/users/$userId']['id'], + FileRoutesByPath['/users/$userId']['path'], + FileRoutesByPath['/users/$userId']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/users.index' { + const createFileRoute: CreateFileRoute< + '/users/', + FileRoutesByPath['/users/']['parentRoute'], + FileRoutesByPath['/users/']['id'], + FileRoutesByPath['/users/']['path'], + FileRoutesByPath['/users/']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-a' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-a', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-b' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-b', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['fullPath'] + > +} +declare module './routes/posts_.$postId.deep' { + const createFileRoute: CreateFileRoute< + '/posts_/$postId/deep', + FileRoutesByPath['/posts_/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > +} + // Create and export the route tree interface PathlessLayoutNestedLayoutRouteChildren { diff --git a/examples/react/start-basic-static/src/routes/__root.tsx b/examples/react/start-basic-static/src/routes/__root.tsx index 70140f2306..7bd99ed901 100644 --- a/examples/react/start-basic-static/src/routes/__root.tsx +++ b/examples/react/start-basic-static/src/routes/__root.tsx @@ -53,9 +53,9 @@ export const Route = createRootRoute({ }), errorComponent: (props) => { return ( - + - + ) }, notFoundComponent: () => , @@ -64,13 +64,13 @@ export const Route = createRootRoute({ function RootComponent() { return ( - + - + ) } -function RootDocument({ children }: { children: React.ReactNode }) { +function RootLayout({ children }: { children: React.ReactNode }) { return ( diff --git a/examples/react/start-basic-static/src/routes/_pathlessLayout.tsx b/examples/react/start-basic-static/src/routes/_pathlessLayout.tsx index 29d3477145..ed5b364c94 100644 --- a/examples/react/start-basic-static/src/routes/_pathlessLayout.tsx +++ b/examples/react/start-basic-static/src/routes/_pathlessLayout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout')({ +export const Route = createFileRoute({ component: PathlessLayoutComponent, }) diff --git a/examples/react/start-basic-static/src/routes/_pathlessLayout/_nested-layout.tsx b/examples/react/start-basic-static/src/routes/_pathlessLayout/_nested-layout.tsx index 9a48b73a46..1e1400f5a7 100644 --- a/examples/react/start-basic-static/src/routes/_pathlessLayout/_nested-layout.tsx +++ b/examples/react/start-basic-static/src/routes/_pathlessLayout/_nested-layout.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/examples/react/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/examples/react/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-a.tsx index 426a8fe486..a0bd5240b7 100644 --- a/examples/react/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +++ b/examples/react/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-a.tsx @@ -1,10 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')( - { - component: LayoutAComponent, - }, -) +export const Route = createFileRoute({ + component: LayoutAComponent, +}) function LayoutAComponent() { return
I'm A!
diff --git a/examples/react/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/examples/react/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-b.tsx index 20facf2daf..2864ec1f28 100644 --- a/examples/react/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +++ b/examples/react/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-b.tsx @@ -1,10 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')( - { - component: LayoutBComponent, - }, -) +export const Route = createFileRoute({ + component: LayoutBComponent, +}) function LayoutBComponent() { return
I'm B!
diff --git a/examples/react/start-basic-static/src/routes/deferred.tsx b/examples/react/start-basic-static/src/routes/deferred.tsx index e59a871e7b..f99f2236fb 100644 --- a/examples/react/start-basic-static/src/routes/deferred.tsx +++ b/examples/react/start-basic-static/src/routes/deferred.tsx @@ -1,4 +1,4 @@ -import { Await, createFileRoute } from '@tanstack/react-router' +import { Await } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import { Suspense, useState } from 'react' @@ -15,7 +15,7 @@ const slowServerFn = createServerFn({ method: 'GET', type: 'static' }) return { name, randomNumber: Math.floor(Math.random() * 100) } }) -export const Route = createFileRoute('/deferred')({ +export const Route = createFileRoute({ loader: async () => { return { deferredStuff: new Promise((r) => diff --git a/examples/react/start-basic-static/src/routes/index.tsx b/examples/react/start-basic-static/src/routes/index.tsx index 09a907cb18..f6c5b98b02 100644 --- a/examples/react/start-basic-static/src/routes/index.tsx +++ b/examples/react/start-basic-static/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/examples/react/start-basic-static/src/routes/posts.$postId.tsx b/examples/react/start-basic-static/src/routes/posts.$postId.tsx index 0d4d2de8eb..821c8b5fa9 100644 --- a/examples/react/start-basic-static/src/routes/posts.$postId.tsx +++ b/examples/react/start-basic-static/src/routes/posts.$postId.tsx @@ -1,9 +1,9 @@ -import { ErrorComponent, Link, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent, Link } from '@tanstack/react-router' import { fetchPost } from '../utils/posts' import type { ErrorComponentProps } from '@tanstack/react-router' import { NotFound } from '~/components/NotFound' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, @@ -29,7 +29,7 @@ function PostComponent() { postId: post.id, }} activeProps={{ className: 'text-black font-bold' }} - className="block py-1 text-blue-800 hover:text-blue-600" + className="inline-block py-1 text-blue-800 hover:text-blue-600" > Deep View diff --git a/examples/react/start-basic-static/src/routes/posts.index.tsx b/examples/react/start-basic-static/src/routes/posts.index.tsx index 5b5f08f95b..13529228bb 100644 --- a/examples/react/start-basic-static/src/routes/posts.index.tsx +++ b/examples/react/start-basic-static/src/routes/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/examples/react/start-basic-static/src/routes/posts.tsx b/examples/react/start-basic-static/src/routes/posts.tsx index ae49032459..5bcd320911 100644 --- a/examples/react/start-basic-static/src/routes/posts.tsx +++ b/examples/react/start-basic-static/src/routes/posts.tsx @@ -1,7 +1,7 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../utils/posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: async () => fetchPosts(), component: PostsComponent, }) diff --git a/examples/react/start-basic-static/src/routes/posts_.$postId.deep.tsx b/examples/react/start-basic-static/src/routes/posts_.$postId.deep.tsx index a82d2e3211..a26a03b7b8 100644 --- a/examples/react/start-basic-static/src/routes/posts_.$postId.deep.tsx +++ b/examples/react/start-basic-static/src/routes/posts_.$postId.deep.tsx @@ -1,8 +1,8 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { fetchPost } from '../utils/posts' import { PostErrorComponent } from './posts.$postId' -export const Route = createFileRoute('/posts_/$postId/deep')({ +export const Route = createFileRoute({ loader: ({ params: { postId } }) => fetchPost({ data: postId, diff --git a/examples/react/start-basic-static/src/routes/redirect.tsx b/examples/react/start-basic-static/src/routes/redirect.tsx index c9286de13d..68a98d5683 100644 --- a/examples/react/start-basic-static/src/routes/redirect.tsx +++ b/examples/react/start-basic-static/src/routes/redirect.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect')({ +export const Route = createFileRoute({ beforeLoad: async () => { throw redirect({ to: '/posts', diff --git a/examples/react/start-basic-static/src/routes/users.$userId.tsx b/examples/react/start-basic-static/src/routes/users.$userId.tsx index d166885e29..b7066bd00d 100644 --- a/examples/react/start-basic-static/src/routes/users.$userId.tsx +++ b/examples/react/start-basic-static/src/routes/users.$userId.tsx @@ -1,4 +1,4 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import axios from 'redaxios' import { createServerFn } from '@tanstack/react-start' import type { ErrorComponentProps } from '@tanstack/react-router' @@ -20,7 +20,7 @@ const fetchUser = createServerFn({ method: 'GET', type: 'static' }) }) }) -export const Route = createFileRoute('/users/$userId')({ +export const Route = createFileRoute({ loader: ({ params: { userId } }) => fetchUser({ data: userId }), errorComponent: UserErrorComponent, component: UserComponent, diff --git a/examples/react/start-basic-static/src/routes/users.index.tsx b/examples/react/start-basic-static/src/routes/users.index.tsx index b6b0ee67fb..662e8b6c68 100644 --- a/examples/react/start-basic-static/src/routes/users.index.tsx +++ b/examples/react/start-basic-static/src/routes/users.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/users/')({ +export const Route = createFileRoute({ component: UsersIndexComponent, }) diff --git a/examples/react/start-basic-static/src/routes/users.tsx b/examples/react/start-basic-static/src/routes/users.tsx index 95eeacaf63..8799830d36 100644 --- a/examples/react/start-basic-static/src/routes/users.tsx +++ b/examples/react/start-basic-static/src/routes/users.tsx @@ -1,4 +1,4 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import axios from 'redaxios' import { createServerFn } from '@tanstack/react-start' import type { User } from '../utils/users' @@ -16,7 +16,7 @@ const fetchUsers = createServerFn({ method: 'GET', type: 'static' }).handler( }, ) -export const Route = createFileRoute('/users')({ +export const Route = createFileRoute({ loader: async () => fetchUsers(), component: UsersComponent, }) diff --git a/examples/react/start-basic-static/src/ssr.tsx b/examples/react/start-basic-static/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-basic-static/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-basic-static/src/tanstack-start.d.ts b/examples/react/start-basic-static/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-basic-static/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-basic-static/src/utils/loggingMiddleware.tsx b/examples/react/start-basic-static/src/utils/loggingMiddleware.tsx index e64b1516da..80ef49b306 100644 --- a/examples/react/start-basic-static/src/utils/loggingMiddleware.tsx +++ b/examples/react/start-basic-static/src/utils/loggingMiddleware.tsx @@ -1,8 +1,8 @@ import { createMiddleware } from '@tanstack/react-start' -export const logMiddleware = createMiddleware() +export const logMiddleware = createMiddleware({ type: 'function' }) .middleware([ - createMiddleware() + createMiddleware({ type: 'function' }) .client(async (ctx) => { const clientTime = new Date() diff --git a/examples/react/start-basic-static/vite.config.ts b/examples/react/start-basic-static/vite.config.ts new file mode 100644 index 0000000000..303ac171c9 --- /dev/null +++ b/examples/react/start-basic-static/vite.config.ts @@ -0,0 +1,25 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart({ + spa: { + enabled: true, + prerender: { + crawlLinks: true, + }, + }, + sitemap: { + host: 'https://localhost:3000', + }, + }), + ], +}) diff --git a/examples/react/start-basic/.gitignore b/examples/react/start-basic/.gitignore index be342025da..0bb5a583db 100644 --- a/examples/react/start-basic/.gitignore +++ b/examples/react/start-basic/.gitignore @@ -7,16 +7,14 @@ yarn.lock .env .vercel .output -.vinxi - +.nitro /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ /blob-report/ /playwright/.cache/ +.tanstack-start/build \ No newline at end of file diff --git a/examples/react/start-basic/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-basic/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..7972e1ecfd --- /dev/null +++ b/examples/react/start-basic/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,187 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +import { ServerRoute as CustomScriptDotjsRouteImport } from './../../src/routes/customScript[.]js' +import { ServerRoute as ApiUsersRouteImport } from './../../src/routes/api/users' +import { ServerRoute as ApiUsersUserIdRouteImport } from './../../src/routes/api/users.$userId' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +const CustomScriptDotjsRoute = CustomScriptDotjsRouteImport.update({ + id: '/customScript.js', + path: '/customScript.js', + getParentRoute: () => rootRoute, +} as any) + +const ApiUsersRoute = ApiUsersRouteImport.update({ + id: '/api/users', + path: '/api/users', + getParentRoute: () => rootRoute, +} as any) + +const ApiUsersUserIdRoute = ApiUsersUserIdRouteImport.update({ + id: '/$userId', + path: '/$userId', + getParentRoute: () => ApiUsersRoute, +} as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath { + '/customScript.js': { + id: '/customScript.js' + path: '/customScript.js' + fullPath: '/customScript.js' + preLoaderRoute: typeof CustomScriptDotjsRouteImport + parentRoute: typeof rootRoute + } + '/api/users': { + id: '/api/users' + path: '/api/users' + fullPath: '/api/users' + preLoaderRoute: typeof ApiUsersRouteImport + parentRoute: typeof rootRoute + } + '/api/users/$userId': { + id: '/api/users/$userId' + path: '/$userId' + fullPath: '/api/users/$userId' + preLoaderRoute: typeof ApiUsersUserIdRouteImport + parentRoute: typeof ApiUsersRouteImport + } + } +} + +// Add type-safety to the createFileRoute function across the route tree + +declare module './../../src/routes/customScript[.]js' { + const createServerFileRoute: CreateServerFileRoute< + FileRoutesByPath['/customScript.js']['parentRoute'], + FileRoutesByPath['/customScript.js']['id'], + FileRoutesByPath['/customScript.js']['path'], + FileRoutesByPath['/customScript.js']['fullPath'], + unknown + > +} +declare module './../../src/routes/api/users' { + const createServerFileRoute: CreateServerFileRoute< + FileRoutesByPath['/api/users']['parentRoute'], + FileRoutesByPath['/api/users']['id'], + FileRoutesByPath['/api/users']['path'], + FileRoutesByPath['/api/users']['fullPath'], + ApiUsersRouteChildren + > +} +declare module './../../src/routes/api/users.$userId' { + const createServerFileRoute: CreateServerFileRoute< + FileRoutesByPath['/api/users/$userId']['parentRoute'], + FileRoutesByPath['/api/users/$userId']['id'], + FileRoutesByPath['/api/users/$userId']['path'], + FileRoutesByPath['/api/users/$userId']['fullPath'], + unknown + > +} + +// Create and export the route tree + +interface ApiUsersRouteChildren { + ApiUsersUserIdRoute: typeof ApiUsersUserIdRoute +} + +const ApiUsersRouteChildren: ApiUsersRouteChildren = { + ApiUsersUserIdRoute: ApiUsersUserIdRoute, +} + +const ApiUsersRouteWithChildren = ApiUsersRoute._addFileChildren( + ApiUsersRouteChildren, +) + +export interface FileRoutesByFullPath { + '/customScript.js': typeof CustomScriptDotjsRoute + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$userId': typeof ApiUsersUserIdRoute +} + +export interface FileRoutesByTo { + '/customScript.js': typeof CustomScriptDotjsRoute + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$userId': typeof ApiUsersUserIdRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/customScript.js': typeof CustomScriptDotjsRoute + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$userId': typeof ApiUsersUserIdRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/customScript.js' | '/api/users' | '/api/users/$userId' + fileRoutesByTo: FileRoutesByTo + to: '/customScript.js' | '/api/users' | '/api/users/$userId' + id: '__root__' | '/customScript.js' | '/api/users' | '/api/users/$userId' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + CustomScriptDotjsRoute: typeof CustomScriptDotjsRoute + ApiUsersRoute: typeof ApiUsersRouteWithChildren +} + +const rootRouteChildren: RootRouteChildren = { + CustomScriptDotjsRoute: CustomScriptDotjsRoute, + ApiUsersRoute: ApiUsersRouteWithChildren, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/customScript.js", + "/api/users" + ] + }, + "/customScript.js": { + "filePath": "customScript[.]js.ts" + }, + "/api/users": { + "filePath": "api/users.ts", + "children": [ + "/api/users/$userId" + ] + }, + "/api/users/$userId": { + "filePath": "api/users.$userId.ts", + "parent": "/api/users" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-basic/app.config.ts b/examples/react/start-basic/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/examples/react/start-basic/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/examples/react/start-basic/package.json b/examples/react/start-basic/package.json index b7475e12c3..f1764eae34 100644 --- a/examples/react/start-basic/package.json +++ b/examples/react/start-basic/package.json @@ -4,18 +4,19 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "node .output/server/index.mjs" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "vite": "^6.3.5", + "zod": "^3.24.2" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/react/start-basic/src/api.ts b/examples/react/start-basic/src/api.ts deleted file mode 100644 index 8b9fef1667..0000000000 --- a/examples/react/start-basic/src/api.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { - createStartAPIHandler, - defaultAPIFileRouteHandler, -} from '@tanstack/react-start/api' - -export default createStartAPIHandler(defaultAPIFileRouteHandler) diff --git a/examples/react/start-basic/src/client.tsx b/examples/react/start-basic/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-basic/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-basic/src/global-middleware.ts b/examples/react/start-basic/src/global-middleware.ts deleted file mode 100644 index c7e7af599f..0000000000 --- a/examples/react/start-basic/src/global-middleware.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { registerGlobalMiddleware } from '@tanstack/react-start' -import { logMiddleware } from './utils/loggingMiddleware' - -registerGlobalMiddleware({ - middleware: [logMiddleware], -}) diff --git a/examples/react/start-basic/src/routeTree.gen.ts b/examples/react/start-basic/src/routeTree.gen.ts index 4dca20ee9c..a3ca3d53c4 100644 --- a/examples/react/start-basic/src/routeTree.gen.ts +++ b/examples/react/start-basic/src/routeTree.gen.ts @@ -8,107 +8,108 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as RedirectImport } from './routes/redirect' -import { Route as DeferredImport } from './routes/deferred' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as UsersRouteImport } from './routes/users.route' -import { Route as PostsRouteImport } from './routes/posts.route' -import { Route as IndexImport } from './routes/index' -import { Route as UsersIndexImport } from './routes/users.index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as UsersUserIdImport } from './routes/users.$userId' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as PathlessLayoutNestedLayoutImport } from './routes/_pathlessLayout/_nested-layout' -import { Route as PostsPostIdDeepImport } from './routes/posts_.$postId.deep' -import { Route as PathlessLayoutNestedLayoutRouteBImport } from './routes/_pathlessLayout/_nested-layout/route-b' -import { Route as PathlessLayoutNestedLayoutRouteAImport } from './routes/_pathlessLayout/_nested-layout/route-a' +import { Route as UsersRouteImport } from './routes/users' +import { Route as RedirectRouteImport } from './routes/redirect' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as DeferredRouteImport } from './routes/deferred' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as UsersIndexRouteImport } from './routes/users.index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as UsersUserIdRouteImport } from './routes/users.$userId' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts_.$postId.deep' +import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' +import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' // Create/Update Routes -const RedirectRoute = RedirectImport.update({ - id: '/redirect', - path: '/redirect', +const UsersRoute = UsersRouteImport.update({ + id: '/users', + path: '/users', getParentRoute: () => rootRoute, } as any) -const DeferredRoute = DeferredImport.update({ - id: '/deferred', - path: '/deferred', +const RedirectRoute = RedirectRouteImport.update({ + id: '/redirect', + path: '/redirect', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRoute = PathlessLayoutImport.update({ - id: '/_pathlessLayout', +const PostsRoute = PostsRouteImport.update({ + id: '/posts', + path: '/posts', getParentRoute: () => rootRoute, } as any) -const UsersRouteRoute = UsersRouteImport.update({ - id: '/users', - path: '/users', +const DeferredRoute = DeferredRouteImport.update({ + id: '/deferred', + path: '/deferred', getParentRoute: () => rootRoute, } as any) -const PostsRouteRoute = PostsRouteImport.update({ - id: '/posts', - path: '/posts', +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ + id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const UsersIndexRoute = UsersIndexImport.update({ +const UsersIndexRoute = UsersIndexRouteImport.update({ id: '/', path: '/', - getParentRoute: () => UsersRouteRoute, + getParentRoute: () => UsersRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', - getParentRoute: () => PostsRouteRoute, + getParentRoute: () => PostsRoute, } as any) -const UsersUserIdRoute = UsersUserIdImport.update({ +const UsersUserIdRoute = UsersUserIdRouteImport.update({ id: '/$userId', path: '/$userId', - getParentRoute: () => UsersRouteRoute, + getParentRoute: () => UsersRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', - getParentRoute: () => PostsRouteRoute, + getParentRoute: () => PostsRoute, } as any) -const PathlessLayoutNestedLayoutRoute = PathlessLayoutNestedLayoutImport.update( - { +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ id: '/_nested-layout', getParentRoute: () => PathlessLayoutRoute, - } as any, -) + } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/posts_/$postId/deep', path: '/posts/$postId/deep', getParentRoute: () => rootRoute, } as any) const PathlessLayoutNestedLayoutRouteBRoute = - PathlessLayoutNestedLayoutRouteBImport.update({ + PathlessLayoutNestedLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutNestedLayoutRoute, } as any) const PathlessLayoutNestedLayoutRouteARoute = - PathlessLayoutNestedLayoutRouteAImport.update({ + PathlessLayoutNestedLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutNestedLayoutRoute, @@ -122,132 +123,233 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport - parentRoute: typeof rootRoute - } - '/posts': { - id: '/posts' - path: '/posts' - fullPath: '/posts' - preLoaderRoute: typeof PostsRouteImport - parentRoute: typeof rootRoute - } - '/users': { - id: '/users' - path: '/users' - fullPath: '/users' - preLoaderRoute: typeof UsersRouteImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/deferred': { id: '/deferred' path: '/deferred' fullPath: '/deferred' - preLoaderRoute: typeof DeferredImport + preLoaderRoute: typeof DeferredRouteImport + parentRoute: typeof rootRoute + } + '/posts': { + id: '/posts' + path: '/posts' + fullPath: '/posts' + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/redirect': { id: '/redirect' path: '/redirect' fullPath: '/redirect' - preLoaderRoute: typeof RedirectImport + preLoaderRoute: typeof RedirectRouteImport + parentRoute: typeof rootRoute + } + '/users': { + id: '/users' + path: '/users' + fullPath: '/users' + preLoaderRoute: typeof UsersRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout/_nested-layout': { id: '/_pathlessLayout/_nested-layout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutNestedLayoutImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport + preLoaderRoute: typeof PostsPostIdRouteImport parentRoute: typeof PostsRouteImport } '/users/$userId': { id: '/users/$userId' path: '/$userId' fullPath: '/users/$userId' - preLoaderRoute: typeof UsersUserIdImport + preLoaderRoute: typeof UsersUserIdRouteImport parentRoute: typeof UsersRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport + preLoaderRoute: typeof PostsIndexRouteImport parentRoute: typeof PostsRouteImport } '/users/': { id: '/users/' path: '/' fullPath: '/users/' - preLoaderRoute: typeof UsersIndexImport + preLoaderRoute: typeof UsersIndexRouteImport parentRoute: typeof UsersRouteImport } '/_pathlessLayout/_nested-layout/route-a': { id: '/_pathlessLayout/_nested-layout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteAImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/_pathlessLayout/_nested-layout/route-b': { id: '/_pathlessLayout/_nested-layout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/posts_/$postId/deep': { id: '/posts_/$postId/deep' path: '/posts/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport + preLoaderRoute: typeof PostsPostIdDeepRouteImport parentRoute: typeof rootRoute } } } -// Create and export the route tree +// Add type-safety to the createFileRoute function across the route tree -interface PostsRouteRouteChildren { - PostsPostIdRoute: typeof PostsPostIdRoute - PostsIndexRoute: typeof PostsIndexRoute +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > } - -const PostsRouteRouteChildren: PostsRouteRouteChildren = { - PostsPostIdRoute: PostsPostIdRoute, - PostsIndexRoute: PostsIndexRoute, +declare module './routes/_pathlessLayout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout', + FileRoutesByPath['/_pathlessLayout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout']['id'], + FileRoutesByPath['/_pathlessLayout']['path'], + FileRoutesByPath['/_pathlessLayout']['fullPath'] + > } - -const PostsRouteRouteWithChildren = PostsRouteRoute._addFileChildren( - PostsRouteRouteChildren, -) - -interface UsersRouteRouteChildren { - UsersUserIdRoute: typeof UsersUserIdRoute - UsersIndexRoute: typeof UsersIndexRoute +declare module './routes/deferred' { + const createFileRoute: CreateFileRoute< + '/deferred', + FileRoutesByPath['/deferred']['parentRoute'], + FileRoutesByPath['/deferred']['id'], + FileRoutesByPath['/deferred']['path'], + FileRoutesByPath['/deferred']['fullPath'] + > } - -const UsersRouteRouteChildren: UsersRouteRouteChildren = { - UsersUserIdRoute: UsersUserIdRoute, - UsersIndexRoute: UsersIndexRoute, +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/redirect' { + const createFileRoute: CreateFileRoute< + '/redirect', + FileRoutesByPath['/redirect']['parentRoute'], + FileRoutesByPath['/redirect']['id'], + FileRoutesByPath['/redirect']['path'], + FileRoutesByPath['/redirect']['fullPath'] + > +} +declare module './routes/users' { + const createFileRoute: CreateFileRoute< + '/users', + FileRoutesByPath['/users']['parentRoute'], + FileRoutesByPath['/users']['id'], + FileRoutesByPath['/users']['path'], + FileRoutesByPath['/users']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout', + FileRoutesByPath['/_pathlessLayout/_nested-layout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/users.$userId' { + const createFileRoute: CreateFileRoute< + '/users/$userId', + FileRoutesByPath['/users/$userId']['parentRoute'], + FileRoutesByPath['/users/$userId']['id'], + FileRoutesByPath['/users/$userId']['path'], + FileRoutesByPath['/users/$userId']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/users.index' { + const createFileRoute: CreateFileRoute< + '/users/', + FileRoutesByPath['/users/']['parentRoute'], + FileRoutesByPath['/users/']['id'], + FileRoutesByPath['/users/']['path'], + FileRoutesByPath['/users/']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-a' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-a', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-b' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-b', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['fullPath'] + > +} +declare module './routes/posts_.$postId.deep' { + const createFileRoute: CreateFileRoute< + '/posts_/$postId/deep', + FileRoutesByPath['/posts_/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > } -const UsersRouteRouteWithChildren = UsersRouteRoute._addFileChildren( - UsersRouteRouteChildren, -) +// Create and export the route tree interface PathlessLayoutNestedLayoutRouteChildren { PathlessLayoutNestedLayoutRouteARoute: typeof PathlessLayoutNestedLayoutRouteARoute @@ -279,13 +381,37 @@ const PathlessLayoutRouteWithChildren = PathlessLayoutRoute._addFileChildren( PathlessLayoutRouteChildren, ) +interface PostsRouteChildren { + PostsPostIdRoute: typeof PostsPostIdRoute + PostsIndexRoute: typeof PostsIndexRoute +} + +const PostsRouteChildren: PostsRouteChildren = { + PostsPostIdRoute: PostsPostIdRoute, + PostsIndexRoute: PostsIndexRoute, +} + +const PostsRouteWithChildren = PostsRoute._addFileChildren(PostsRouteChildren) + +interface UsersRouteChildren { + UsersUserIdRoute: typeof UsersUserIdRoute + UsersIndexRoute: typeof UsersIndexRoute +} + +const UsersRouteChildren: UsersRouteChildren = { + UsersUserIdRoute: UsersUserIdRoute, + UsersIndexRoute: UsersIndexRoute, +} + +const UsersRouteWithChildren = UsersRoute._addFileChildren(UsersRouteChildren) + export interface FileRoutesByFullPath { '/': typeof IndexRoute - '/posts': typeof PostsRouteRouteWithChildren - '/users': typeof UsersRouteRouteWithChildren '': typeof PathlessLayoutNestedLayoutRouteWithChildren '/deferred': typeof DeferredRoute + '/posts': typeof PostsRouteWithChildren '/redirect': typeof RedirectRoute + '/users': typeof UsersRouteWithChildren '/posts/$postId': typeof PostsPostIdRoute '/users/$userId': typeof UsersUserIdRoute '/posts/': typeof PostsIndexRoute @@ -312,11 +438,11 @@ export interface FileRoutesByTo { export interface FileRoutesById { __root__: typeof rootRoute '/': typeof IndexRoute - '/posts': typeof PostsRouteRouteWithChildren - '/users': typeof UsersRouteRouteWithChildren '/_pathlessLayout': typeof PathlessLayoutRouteWithChildren '/deferred': typeof DeferredRoute + '/posts': typeof PostsRouteWithChildren '/redirect': typeof RedirectRoute + '/users': typeof UsersRouteWithChildren '/_pathlessLayout/_nested-layout': typeof PathlessLayoutNestedLayoutRouteWithChildren '/posts/$postId': typeof PostsPostIdRoute '/users/$userId': typeof UsersUserIdRoute @@ -331,11 +457,11 @@ export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath fullPaths: | '/' - | '/posts' - | '/users' | '' | '/deferred' + | '/posts' | '/redirect' + | '/users' | '/posts/$postId' | '/users/$userId' | '/posts/' @@ -359,11 +485,11 @@ export interface FileRouteTypes { id: | '__root__' | '/' - | '/posts' - | '/users' | '/_pathlessLayout' | '/deferred' + | '/posts' | '/redirect' + | '/users' | '/_pathlessLayout/_nested-layout' | '/posts/$postId' | '/users/$userId' @@ -377,21 +503,21 @@ export interface FileRouteTypes { export interface RootRouteChildren { IndexRoute: typeof IndexRoute - PostsRouteRoute: typeof PostsRouteRouteWithChildren - UsersRouteRoute: typeof UsersRouteRouteWithChildren PathlessLayoutRoute: typeof PathlessLayoutRouteWithChildren DeferredRoute: typeof DeferredRoute + PostsRoute: typeof PostsRouteWithChildren RedirectRoute: typeof RedirectRoute + UsersRoute: typeof UsersRouteWithChildren PostsPostIdDeepRoute: typeof PostsPostIdDeepRoute } const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, - PostsRouteRoute: PostsRouteRouteWithChildren, - UsersRouteRoute: UsersRouteRouteWithChildren, PathlessLayoutRoute: PathlessLayoutRouteWithChildren, DeferredRoute: DeferredRoute, + PostsRoute: PostsRouteWithChildren, RedirectRoute: RedirectRoute, + UsersRoute: UsersRouteWithChildren, PostsPostIdDeepRoute: PostsPostIdDeepRoute, } @@ -406,31 +532,17 @@ export const routeTree = rootRoute "filePath": "__root.tsx", "children": [ "/", - "/posts", - "/users", "/_pathlessLayout", "/deferred", + "/posts", "/redirect", + "/users", "/posts_/$postId/deep" ] }, "/": { "filePath": "index.tsx" }, - "/posts": { - "filePath": "posts.route.tsx", - "children": [ - "/posts/$postId", - "/posts/" - ] - }, - "/users": { - "filePath": "users.route.tsx", - "children": [ - "/users/$userId", - "/users/" - ] - }, "/_pathlessLayout": { "filePath": "_pathlessLayout.tsx", "children": [ @@ -440,9 +552,23 @@ export const routeTree = rootRoute "/deferred": { "filePath": "deferred.tsx" }, + "/posts": { + "filePath": "posts.tsx", + "children": [ + "/posts/$postId", + "/posts/" + ] + }, "/redirect": { "filePath": "redirect.tsx" }, + "/users": { + "filePath": "users.tsx", + "children": [ + "/users/$userId", + "/users/" + ] + }, "/_pathlessLayout/_nested-layout": { "filePath": "_pathlessLayout/_nested-layout.tsx", "parent": "/_pathlessLayout", diff --git a/examples/react/start-basic/src/routes/__root.tsx b/examples/react/start-basic/src/routes/__root.tsx index 70140f2306..407f04b58a 100644 --- a/examples/react/start-basic/src/routes/__root.tsx +++ b/examples/react/start-basic/src/routes/__root.tsx @@ -50,6 +50,12 @@ export const Route = createRootRoute({ { rel: 'manifest', href: '/site.webmanifest', color: '#fffff' }, { rel: 'icon', href: '/favicon.ico' }, ], + scripts: [ + { + src: '/customScript.js', + type: 'text/javascript', + }, + ], }), errorComponent: (props) => { return ( diff --git a/examples/react/start-basic/src/routes/_pathlessLayout.tsx b/examples/react/start-basic/src/routes/_pathlessLayout.tsx index c3b12442b8..5c4a461d8d 100644 --- a/examples/react/start-basic/src/routes/_pathlessLayout.tsx +++ b/examples/react/start-basic/src/routes/_pathlessLayout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx b/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx index 9a48b73a46..1e1400f5a7 100644 --- a/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx +++ b/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx index 426a8fe486..a0bd5240b7 100644 --- a/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +++ b/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx @@ -1,10 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')( - { - component: LayoutAComponent, - }, -) +export const Route = createFileRoute({ + component: LayoutAComponent, +}) function LayoutAComponent() { return
I'm A!
diff --git a/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx index 20facf2daf..2864ec1f28 100644 --- a/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +++ b/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx @@ -1,10 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')( - { - component: LayoutBComponent, - }, -) +export const Route = createFileRoute({ + component: LayoutBComponent, +}) function LayoutBComponent() { return
I'm B!
diff --git a/examples/react/start-basic/src/routes/api/users.$id.ts b/examples/react/start-basic/src/routes/api/users.$userId.ts similarity index 55% rename from examples/react/start-basic/src/routes/api/users.$id.ts rename to examples/react/start-basic/src/routes/api/users.$userId.ts index 1332a2cd07..f0575c881c 100644 --- a/examples/react/start-basic/src/routes/api/users.$id.ts +++ b/examples/react/start-basic/src/routes/api/users.$userId.ts @@ -1,13 +1,12 @@ import { json } from '@tanstack/react-start' -import { createAPIFileRoute } from '@tanstack/react-start/api' -import type { User } from '../../utils/users' +import type { User } from '~/utils/users' -export const APIRoute = createAPIFileRoute('/api/users/$id')({ - GET: async ({ request, params }) => { - console.info(`Fetching users by id=${params.id}... @`, request.url) +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ params, request }) => { + console.info(`Fetching users by id=${params.userId}... @`, request.url) try { const res = await fetch( - 'https://jsonplaceholder.typicode.com/users/' + params.id, + 'https://jsonplaceholder.typicode.com/users/' + params.userId, ) if (!res.ok) { throw new Error('Failed to fetch user') diff --git a/examples/react/start-basic/src/routes/api/users.ts b/examples/react/start-basic/src/routes/api/users.ts index 61ad3e5bf4..dd8e36bfab 100644 --- a/examples/react/start-basic/src/routes/api/users.ts +++ b/examples/react/start-basic/src/routes/api/users.ts @@ -1,19 +1,58 @@ -import { json } from '@tanstack/react-start' -import { createAPIFileRoute } from '@tanstack/react-start/api' -import type { User } from '../../utils/users' +import { createMiddleware, json } from '@tanstack/react-start' +import type { User } from '~/utils/users' -export const APIRoute = createAPIFileRoute('/api/users')({ - GET: async ({ request }) => { - console.info('Fetching users... @', request.url) - const res = await fetch('https://jsonplaceholder.typicode.com/users') - if (!res.ok) { - throw new Error('Failed to fetch users') - } +const userLoggerMiddleware = createMiddleware({ type: 'request' }).server( + async ({ next, request }) => { + console.info('In: /users') + const result = await next() + result.response.headers.set('x-users', 'true') + console.info('Out: /users') + return result + }, +) + +const testParentMiddleware = createMiddleware({ type: 'request' }).server( + async ({ next, request }) => { + console.info('In: testParentMiddleware') + const result = await next() + result.response.headers.set('x-test-parent', 'true') + console.info('Out: testParentMiddleware') + return result + }, +) - const data = (await res.json()) as Array +const testMiddleware = createMiddleware({ type: 'request' }) + .middleware([testParentMiddleware]) + .server(async ({ next, request }) => { + console.info('In: testMiddleware') + const result = await next() + result.response.headers.set('x-test', 'true') - const list = data.slice(0, 10) + // if (Math.random() > 0.5) { + // throw new Response(null, { + // status: 302, + // headers: { Location: 'https://www.google.com' }, + // }) + // } - return json(list.map((u) => ({ id: u.id, name: u.name, email: u.email }))) - }, -}) + console.info('Out: testMiddleware') + return result + }) + +export const ServerRoute = createServerFileRoute() + .middleware([testMiddleware, userLoggerMiddleware, testParentMiddleware]) + .methods({ + GET: async ({ request }) => { + console.info('Fetching users... @', request.url) + const res = await fetch('https://jsonplaceholder.typicode.com/users') + if (!res.ok) { + throw new Error('Failed to fetch users') + } + + const data = (await res.json()) as Array + + const list = data.slice(0, 10) + + return json(list.map((u) => ({ id: u.id, name: u.name, email: u.email }))) + }, + }) diff --git a/examples/react/start-basic/src/routes/customScript[.]js.ts b/examples/react/start-basic/src/routes/customScript[.]js.ts new file mode 100644 index 0000000000..6966a3379d --- /dev/null +++ b/examples/react/start-basic/src/routes/customScript[.]js.ts @@ -0,0 +1,9 @@ +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + return new Response('console.log("Hello from customScript.js!")', { + headers: { + 'Content-Type': 'application/javascript', + }, + }) + }, +}) diff --git a/examples/react/start-basic/src/routes/deferred.tsx b/examples/react/start-basic/src/routes/deferred.tsx index f3e09d1d4e..da895081df 100644 --- a/examples/react/start-basic/src/routes/deferred.tsx +++ b/examples/react/start-basic/src/routes/deferred.tsx @@ -1,4 +1,4 @@ -import { Await, createFileRoute } from '@tanstack/react-router' +import { Await } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import { Suspense, useState } from 'react' @@ -15,7 +15,7 @@ const slowServerFn = createServerFn({ method: 'GET' }) return { name, randomNumber: Math.floor(Math.random() * 100) } }) -export const Route = createFileRoute('/deferred')({ +export const Route = createFileRoute({ loader: async () => { return { deferredStuff: new Promise((r) => diff --git a/examples/react/start-basic/src/routes/index.tsx b/examples/react/start-basic/src/routes/index.tsx index 09a907cb18..f6c5b98b02 100644 --- a/examples/react/start-basic/src/routes/index.tsx +++ b/examples/react/start-basic/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/examples/react/start-basic/src/routes/posts.$postId.tsx b/examples/react/start-basic/src/routes/posts.$postId.tsx index d6de7c9dc3..f4184852e0 100644 --- a/examples/react/start-basic/src/routes/posts.$postId.tsx +++ b/examples/react/start-basic/src/routes/posts.$postId.tsx @@ -1,9 +1,9 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { fetchPost } from '../utils/posts' import { NotFound } from '~/components/NotFound' import { PostErrorComponent } from '~/components/PostError' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, @@ -25,7 +25,7 @@ function PostComponent() { postId: post.id, }} activeProps={{ className: 'text-black font-bold' }} - className="block py-1 text-blue-800 hover:text-blue-600" + className="inline-block py-1 text-blue-800 hover:text-blue-600" > Deep View diff --git a/examples/react/start-basic/src/routes/posts.index.tsx b/examples/react/start-basic/src/routes/posts.index.tsx index 5b5f08f95b..13529228bb 100644 --- a/examples/react/start-basic/src/routes/posts.index.tsx +++ b/examples/react/start-basic/src/routes/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/examples/react/start-basic/src/routes/posts.route.tsx b/examples/react/start-basic/src/routes/posts.tsx similarity index 82% rename from examples/react/start-basic/src/routes/posts.route.tsx rename to examples/react/start-basic/src/routes/posts.tsx index f29619363e..5bcd320911 100644 --- a/examples/react/start-basic/src/routes/posts.route.tsx +++ b/examples/react/start-basic/src/routes/posts.tsx @@ -1,12 +1,12 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../utils/posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: async () => fetchPosts(), - component: PostsLayoutComponent, + component: PostsComponent, }) -function PostsLayoutComponent() { +function PostsComponent() { const posts = Route.useLoaderData() return ( diff --git a/examples/react/start-basic/src/routes/posts_.$postId.deep.tsx b/examples/react/start-basic/src/routes/posts_.$postId.deep.tsx index 29e6c39b5a..624b76a6c1 100644 --- a/examples/react/start-basic/src/routes/posts_.$postId.deep.tsx +++ b/examples/react/start-basic/src/routes/posts_.$postId.deep.tsx @@ -1,8 +1,8 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { fetchPost } from '../utils/posts' import { PostErrorComponent } from '~/components/PostError' -export const Route = createFileRoute('/posts_/$postId/deep')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost({ data: postId, diff --git a/examples/react/start-basic/src/routes/redirect.tsx b/examples/react/start-basic/src/routes/redirect.tsx index c9286de13d..68a98d5683 100644 --- a/examples/react/start-basic/src/routes/redirect.tsx +++ b/examples/react/start-basic/src/routes/redirect.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect')({ +export const Route = createFileRoute({ beforeLoad: async () => { throw redirect({ to: '/posts', diff --git a/examples/react/start-basic/src/routes/users.$userId.tsx b/examples/react/start-basic/src/routes/users.$userId.tsx index 186b1c64e7..1f493d2945 100644 --- a/examples/react/start-basic/src/routes/users.$userId.tsx +++ b/examples/react/start-basic/src/routes/users.$userId.tsx @@ -1,18 +1,15 @@ -import { createFileRoute } from '@tanstack/react-router' -import type { User } from '~/utils/users' -import { DEPLOY_URL } from '~/utils/users' -import { NotFound } from '~/components/NotFound' -import { UserErrorComponent } from '~/components/UserError' +import { NotFound } from 'src/components/NotFound' +import { UserErrorComponent } from 'src/components/UserError' -export const Route = createFileRoute('/users/$userId')({ +export const Route = createFileRoute({ loader: async ({ params: { userId } }) => { try { - const res = await fetch(DEPLOY_URL + '/api/users/' + userId) + const res = await fetch('/api/users/' + userId) if (!res.ok) { throw new Error('Unexpected status code') } - const data = (await res.json()) as User + const data = await res.json() return data } catch { @@ -33,6 +30,14 @@ function UserComponent() {

{user.name}

{user.email}
+
) } diff --git a/examples/react/start-basic/src/routes/users.index.tsx b/examples/react/start-basic/src/routes/users.index.tsx index b6b0ee67fb..31d070db1f 100644 --- a/examples/react/start-basic/src/routes/users.index.tsx +++ b/examples/react/start-basic/src/routes/users.index.tsx @@ -1,9 +1,17 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/users/')({ +export const Route = createFileRoute({ component: UsersIndexComponent, }) function UsersIndexComponent() { - return
Select a user.
+ return ( +
+ Select a user or{' '} + + view as JSON + +
+ ) } diff --git a/examples/react/start-basic/src/routes/users.route.tsx b/examples/react/start-basic/src/routes/users.tsx similarity index 63% rename from examples/react/start-basic/src/routes/users.route.tsx rename to examples/react/start-basic/src/routes/users.tsx index ebc930e4da..9d1548980a 100644 --- a/examples/react/start-basic/src/routes/users.route.tsx +++ b/examples/react/start-basic/src/routes/users.tsx @@ -1,26 +1,22 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' -import { DEPLOY_URL } from '../utils/users' +import { Link, Outlet } from '@tanstack/react-router' import type { User } from '../utils/users' -export const Route = createFileRoute('/users')({ +export const Route = createFileRoute({ loader: async () => { - try { - const res = await fetch(DEPLOY_URL + '/api/users') - if (!res.ok) { - throw new Error('Unexpected status code') - } + const res = await fetch('/api/users') - const data = (await res.json()) as Array - - return data - } catch { - throw new Error('Failed to fetch users') + if (!res.ok) { + throw new Error('Unexpected status code') } + + const data = (await res.json()) as Array + + return data }, - component: UsersLayoutComponent, + component: UsersComponent, }) -function UsersLayoutComponent() { +function UsersComponent() { const users = Route.useLoaderData() return ( diff --git a/examples/react/start-basic/src/ssr.tsx b/examples/react/start-basic/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-basic/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-basic/src/tanstack-start.d.ts b/examples/react/start-basic/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-basic/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-basic/src/utils/loggingMiddleware.tsx b/examples/react/start-basic/src/utils/loggingMiddleware.tsx index 3944490725..3ea9a06439 100644 --- a/examples/react/start-basic/src/utils/loggingMiddleware.tsx +++ b/examples/react/start-basic/src/utils/loggingMiddleware.tsx @@ -1,6 +1,6 @@ import { createMiddleware } from '@tanstack/react-start' -const preLogMiddleware = createMiddleware() +const preLogMiddleware = createMiddleware({ type: 'function' }) .client(async (ctx) => { const clientTime = new Date() @@ -25,14 +25,14 @@ const preLogMiddleware = createMiddleware() }) }) -export const logMiddleware = createMiddleware() +export const logMiddleware = createMiddleware({ type: 'function' }) .middleware([preLogMiddleware]) .client(async (ctx) => { const res = await ctx.next() const now = new Date() console.log('Client Req/Res:', { - duration: res.context.clientTime.getTime() - now.getTime(), + duration: now.getTime() - res.context.clientTime.getTime(), durationToServer: res.context.durationToServer, durationFromServer: now.getTime() - res.context.serverTime.getTime(), }) diff --git a/examples/react/start-basic/src/utils/posts.tsx b/examples/react/start-basic/src/utils/posts.tsx index d12abb30ab..52877be68c 100644 --- a/examples/react/start-basic/src/utils/posts.tsx +++ b/examples/react/start-basic/src/utils/posts.tsx @@ -7,7 +7,7 @@ export type PostType = { body: string } -export const fetchPost = createServerFn({ method: 'GET' }) +export const fetchPost = createServerFn() .validator((d: string) => d) .handler(async ({ data }) => { console.info(`Fetching post with id ${data}...`) @@ -27,16 +27,14 @@ export const fetchPost = createServerFn({ method: 'GET' }) return post }) -export const fetchPosts = createServerFn({ method: 'GET' }).handler( - async () => { - console.info('Fetching posts...') - const res = await fetch('https://jsonplaceholder.typicode.com/posts') - if (!res.ok) { - throw new Error('Failed to fetch posts') - } +export const fetchPosts = createServerFn().handler(async () => { + console.info('Fetching posts...') + const res = await fetch('https://jsonplaceholder.typicode.com/posts') + if (!res.ok) { + throw new Error('Failed to fetch posts') + } - const posts = (await res.json()) as Array + const posts = (await res.json()) as Array - return posts - }, -) + return posts.slice(0, 10) +}) diff --git a/examples/react/start-basic/src/utils/users.tsx b/examples/react/start-basic/src/utils/users.tsx index b810f455fe..7ba645b383 100644 --- a/examples/react/start-basic/src/utils/users.tsx +++ b/examples/react/start-basic/src/utils/users.tsx @@ -3,5 +3,3 @@ export type User = { name: string email: string } - -export const DEPLOY_URL = 'http://localhost:3000' diff --git a/examples/react/start-basic/vite.config.ts b/examples/react/start-basic/vite.config.ts new file mode 100644 index 0000000000..1f5fd1961a --- /dev/null +++ b/examples/react/start-basic/vite.config.ts @@ -0,0 +1,15 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/examples/react/start-clerk-basic/.gitignore b/examples/react/start-clerk-basic/.gitignore index b15fed94e2..2818549158 100644 --- a/examples/react/start-clerk-basic/.gitignore +++ b/examples/react/start-clerk-basic/.gitignore @@ -7,14 +7,10 @@ yarn.lock .cache .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/start-clerk-basic/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-clerk-basic/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/examples/react/start-clerk-basic/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-clerk-basic/app.config.ts b/examples/react/start-clerk-basic/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/examples/react/start-clerk-basic/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/examples/react/start-clerk-basic/package.json b/examples/react/start-clerk-basic/package.json index 81c2bb8456..3a9ef253d8 100644 --- a/examples/react/start-clerk-basic/package.json +++ b/examples/react/start-clerk-basic/package.json @@ -4,20 +4,19 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { "@clerk/tanstack-react-start": "0.12.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/react/start-clerk-basic/src/client.tsx b/examples/react/start-clerk-basic/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-clerk-basic/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-clerk-basic/src/routeTree.gen.ts b/examples/react/start-clerk-basic/src/routeTree.gen.ts index b4b4f459a8..00f53c8623 100644 --- a/examples/react/start-clerk-basic/src/routeTree.gen.ts +++ b/examples/react/start-clerk-basic/src/routeTree.gen.ts @@ -8,48 +8,50 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as AuthedImport } from './routes/_authed' -import { Route as IndexImport } from './routes/index' -import { Route as AuthedPostsImport } from './routes/_authed/posts' -import { Route as AuthedPostsIndexImport } from './routes/_authed/posts.index' -import { Route as AuthedProfileSplatImport } from './routes/_authed/profile.$' -import { Route as AuthedPostsPostIdImport } from './routes/_authed/posts.$postId' +import { Route as AuthedRouteImport } from './routes/_authed' +import { Route as IndexRouteImport } from './routes/index' +import { Route as AuthedPostsRouteImport } from './routes/_authed/posts' +import { Route as AuthedPostsIndexRouteImport } from './routes/_authed/posts.index' +import { Route as AuthedProfileSplatRouteImport } from './routes/_authed/profile.$' +import { Route as AuthedPostsPostIdRouteImport } from './routes/_authed/posts.$postId' // Create/Update Routes -const AuthedRoute = AuthedImport.update({ +const AuthedRoute = AuthedRouteImport.update({ id: '/_authed', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const AuthedPostsRoute = AuthedPostsImport.update({ +const AuthedPostsRoute = AuthedPostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => AuthedRoute, } as any) -const AuthedPostsIndexRoute = AuthedPostsIndexImport.update({ +const AuthedPostsIndexRoute = AuthedPostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => AuthedPostsRoute, } as any) -const AuthedProfileSplatRoute = AuthedProfileSplatImport.update({ +const AuthedProfileSplatRoute = AuthedProfileSplatRouteImport.update({ id: '/profile/$', path: '/profile/$', getParentRoute: () => AuthedRoute, } as any) -const AuthedPostsPostIdRoute = AuthedPostsPostIdImport.update({ +const AuthedPostsPostIdRoute = AuthedPostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => AuthedPostsRoute, @@ -63,47 +65,104 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_authed': { id: '/_authed' path: '' fullPath: '' - preLoaderRoute: typeof AuthedImport + preLoaderRoute: typeof AuthedRouteImport parentRoute: typeof rootRoute } '/_authed/posts': { id: '/_authed/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof AuthedPostsImport - parentRoute: typeof AuthedImport + preLoaderRoute: typeof AuthedPostsRouteImport + parentRoute: typeof AuthedRouteImport } '/_authed/posts/$postId': { id: '/_authed/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof AuthedPostsPostIdImport - parentRoute: typeof AuthedPostsImport + preLoaderRoute: typeof AuthedPostsPostIdRouteImport + parentRoute: typeof AuthedPostsRouteImport } '/_authed/profile/$': { id: '/_authed/profile/$' path: '/profile/$' fullPath: '/profile/$' - preLoaderRoute: typeof AuthedProfileSplatImport - parentRoute: typeof AuthedImport + preLoaderRoute: typeof AuthedProfileSplatRouteImport + parentRoute: typeof AuthedRouteImport } '/_authed/posts/': { id: '/_authed/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof AuthedPostsIndexImport - parentRoute: typeof AuthedPostsImport + preLoaderRoute: typeof AuthedPostsIndexRouteImport + parentRoute: typeof AuthedPostsRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_authed' { + const createFileRoute: CreateFileRoute< + '/_authed', + FileRoutesByPath['/_authed']['parentRoute'], + FileRoutesByPath['/_authed']['id'], + FileRoutesByPath['/_authed']['path'], + FileRoutesByPath['/_authed']['fullPath'] + > +} +declare module './routes/_authed/posts' { + const createFileRoute: CreateFileRoute< + '/_authed/posts', + FileRoutesByPath['/_authed/posts']['parentRoute'], + FileRoutesByPath['/_authed/posts']['id'], + FileRoutesByPath['/_authed/posts']['path'], + FileRoutesByPath['/_authed/posts']['fullPath'] + > +} +declare module './routes/_authed/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/_authed/posts/$postId', + FileRoutesByPath['/_authed/posts/$postId']['parentRoute'], + FileRoutesByPath['/_authed/posts/$postId']['id'], + FileRoutesByPath['/_authed/posts/$postId']['path'], + FileRoutesByPath['/_authed/posts/$postId']['fullPath'] + > +} +declare module './routes/_authed/profile.$' { + const createFileRoute: CreateFileRoute< + '/_authed/profile/$', + FileRoutesByPath['/_authed/profile/$']['parentRoute'], + FileRoutesByPath['/_authed/profile/$']['id'], + FileRoutesByPath['/_authed/profile/$']['path'], + FileRoutesByPath['/_authed/profile/$']['fullPath'] + > +} +declare module './routes/_authed/posts.index' { + const createFileRoute: CreateFileRoute< + '/_authed/posts/', + FileRoutesByPath['/_authed/posts/']['parentRoute'], + FileRoutesByPath['/_authed/posts/']['id'], + FileRoutesByPath['/_authed/posts/']['path'], + FileRoutesByPath['/_authed/posts/']['fullPath'] + > +} + // Create and export the route tree interface AuthedPostsRouteChildren { diff --git a/examples/react/start-clerk-basic/src/routes/__root.tsx b/examples/react/start-clerk-basic/src/routes/__root.tsx index 99eaa2c24a..2cd503f80a 100644 --- a/examples/react/start-clerk-basic/src/routes/__root.tsx +++ b/examples/react/start-clerk-basic/src/routes/__root.tsx @@ -1,4 +1,3 @@ -/// import { HeadContent, Link, diff --git a/examples/react/start-clerk-basic/src/routes/_authed.tsx b/examples/react/start-clerk-basic/src/routes/_authed.tsx index 1f68471a91..7e56fea09b 100644 --- a/examples/react/start-clerk-basic/src/routes/_authed.tsx +++ b/examples/react/start-clerk-basic/src/routes/_authed.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import { SignIn } from '@clerk/tanstack-react-start' -export const Route = createFileRoute('/_authed')({ +export const Route = createFileRoute({ beforeLoad: ({ context }) => { if (!context.userId) { throw new Error('Not authenticated') diff --git a/examples/react/start-clerk-basic/src/routes/_authed/posts.$postId.tsx b/examples/react/start-clerk-basic/src/routes/_authed/posts.$postId.tsx index 039271bb89..c6c36f3ea4 100644 --- a/examples/react/start-clerk-basic/src/routes/_authed/posts.$postId.tsx +++ b/examples/react/start-clerk-basic/src/routes/_authed/posts.$postId.tsx @@ -1,9 +1,9 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import type { ErrorComponentProps } from '@tanstack/react-router' import { NotFound } from '~/components/NotFound.js' import { fetchPost } from '~/utils/posts.js' -export const Route = createFileRoute('/_authed/posts/$postId')({ +export const Route = createFileRoute({ loader: ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, diff --git a/examples/react/start-clerk-basic/src/routes/_authed/posts.index.tsx b/examples/react/start-clerk-basic/src/routes/_authed/posts.index.tsx index ea9e667e54..13529228bb 100644 --- a/examples/react/start-clerk-basic/src/routes/_authed/posts.index.tsx +++ b/examples/react/start-clerk-basic/src/routes/_authed/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_authed/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/examples/react/start-clerk-basic/src/routes/_authed/posts.tsx b/examples/react/start-clerk-basic/src/routes/_authed/posts.tsx index 86c8ef4138..f9b50197cf 100644 --- a/examples/react/start-clerk-basic/src/routes/_authed/posts.tsx +++ b/examples/react/start-clerk-basic/src/routes/_authed/posts.tsx @@ -1,7 +1,7 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '~/utils/posts.js' -export const Route = createFileRoute('/_authed/posts')({ +export const Route = createFileRoute({ loader: () => fetchPosts(), component: PostsComponent, }) diff --git a/examples/react/start-clerk-basic/src/routes/_authed/profile.$.tsx b/examples/react/start-clerk-basic/src/routes/_authed/profile.$.tsx index 208a38e230..f9b50197cf 100644 --- a/examples/react/start-clerk-basic/src/routes/_authed/profile.$.tsx +++ b/examples/react/start-clerk-basic/src/routes/_authed/profile.$.tsx @@ -1,7 +1,7 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '~/utils/posts.js' -export const Route = createFileRoute('/_authed/profile/$')({ +export const Route = createFileRoute({ loader: () => fetchPosts(), component: PostsComponent, }) diff --git a/examples/react/start-clerk-basic/src/routes/index.tsx b/examples/react/start-clerk-basic/src/routes/index.tsx index 6ae388a178..66baf1e9f1 100644 --- a/examples/react/start-clerk-basic/src/routes/index.tsx +++ b/examples/react/start-clerk-basic/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/react-start/clerk-basic/src/ssr.tsx b/examples/react/start-clerk-basic/src/server.ts similarity index 79% rename from e2e/react-start/clerk-basic/src/ssr.tsx rename to examples/react/start-clerk-basic/src/server.ts index eab1a0c9f4..5e1d9e4492 100644 --- a/e2e/react-start/clerk-basic/src/ssr.tsx +++ b/examples/react/start-clerk-basic/src/server.ts @@ -2,15 +2,14 @@ import { createStartHandler, defaultStreamHandler, } from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' import { createClerkHandler } from '@clerk/tanstack-react-start/server' import { createRouter } from './router' const handler = createStartHandler({ createRouter, - getRouterManifest, }) +// @ts-expect-error const clerkHandler = createClerkHandler(handler) export default clerkHandler(defaultStreamHandler) diff --git a/examples/react/start-clerk-basic/src/ssr.tsx b/examples/react/start-clerk-basic/src/ssr.tsx deleted file mode 100644 index 060cd4816b..0000000000 --- a/examples/react/start-clerk-basic/src/ssr.tsx +++ /dev/null @@ -1,17 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' -import { createClerkHandler } from '@clerk/tanstack-react-start/server' -import { createRouter } from './router' - -const handler = createStartHandler({ - createRouter, - getRouterManifest, -}) - -const clerkHandler = createClerkHandler(handler) - -export default clerkHandler(defaultStreamHandler) diff --git a/examples/react/start-clerk-basic/src/tanstack-start.d.ts b/examples/react/start-clerk-basic/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-clerk-basic/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-clerk-basic/vite.config.ts b/examples/react/start-clerk-basic/vite.config.ts new file mode 100644 index 0000000000..1f5fd1961a --- /dev/null +++ b/examples/react/start-clerk-basic/vite.config.ts @@ -0,0 +1,15 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/examples/react/start-convex-trellaux/.gitignore b/examples/react/start-convex-trellaux/.gitignore index 30518e7416..ba7dbddfbe 100644 --- a/examples/react/start-convex-trellaux/.gitignore +++ b/examples/react/start-convex-trellaux/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin .env.local diff --git a/examples/react/start-convex-trellaux/.stackblitzrc b/examples/react/start-convex-trellaux/.stackblitzrc index 2f76846e62..e616ee3a78 100644 --- a/examples/react/start-convex-trellaux/.stackblitzrc +++ b/examples/react/start-convex-trellaux/.stackblitzrc @@ -1,3 +1,3 @@ { - "startCommand": "cp .env.local.example .env.local && npx vinxi dev" + "startCommand": "cp .env.local.example .env.local && npx vite dev" } diff --git a/examples/react/start-convex-trellaux/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-convex-trellaux/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/examples/react/start-convex-trellaux/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-convex-trellaux/app.config.ts b/examples/react/start-convex-trellaux/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/examples/react/start-convex-trellaux/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/examples/react/start-convex-trellaux/package.json b/examples/react/start-convex-trellaux/package.json index ab54a780df..7a0e5edd0e 100644 --- a/examples/react/start-convex-trellaux/package.json +++ b/examples/react/start-convex-trellaux/package.json @@ -5,19 +5,19 @@ "type": "module", "scripts": { "dev": "npx convex dev --once && concurrently -r npm:dev:web npm:dev:db", - "dev:web": "vinxi dev", + "dev:web": "vite dev", "dev:db": "convex dev --run board:seed", - "build": "vinxi build", - "start": "vinxi start" + "build": "vite build", + "start": "vite start" }, "dependencies": { "@convex-dev/react-query": "0.0.0-alpha.8", "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-with-query": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-with-query": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "concurrently": "^8.2.2", "convex": "^1.19.0", "ky": "^1.7.4", @@ -28,7 +28,6 @@ "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", "tiny-invariant": "^1.3.3", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/examples/react/start-convex-trellaux/src/client.tsx b/examples/react/start-convex-trellaux/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-convex-trellaux/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-convex-trellaux/src/routeTree.gen.ts b/examples/react/start-convex-trellaux/src/routeTree.gen.ts index 7ee57387dc..e8cc65e620 100644 --- a/examples/react/start-convex-trellaux/src/routeTree.gen.ts +++ b/examples/react/start-convex-trellaux/src/routeTree.gen.ts @@ -8,21 +8,23 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' -import { Route as BoardsBoardIdImport } from './routes/boards.$boardId' +import { Route as IndexRouteImport } from './routes/index' +import { Route as BoardsBoardIdRouteImport } from './routes/boards.$boardId' // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const BoardsBoardIdRoute = BoardsBoardIdImport.update({ +const BoardsBoardIdRoute = BoardsBoardIdRouteImport.update({ id: '/boards/$boardId', path: '/boards/$boardId', getParentRoute: () => rootRoute, @@ -36,19 +38,40 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/boards/$boardId': { id: '/boards/$boardId' path: '/boards/$boardId' fullPath: '/boards/$boardId' - preLoaderRoute: typeof BoardsBoardIdImport + preLoaderRoute: typeof BoardsBoardIdRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/boards.$boardId' { + const createFileRoute: CreateFileRoute< + '/boards/$boardId', + FileRoutesByPath['/boards/$boardId']['parentRoute'], + FileRoutesByPath['/boards/$boardId']['id'], + FileRoutesByPath['/boards/$boardId']['path'], + FileRoutesByPath['/boards/$boardId']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/examples/react/start-convex-trellaux/src/routes/boards.$boardId.tsx b/examples/react/start-convex-trellaux/src/routes/boards.$boardId.tsx index 36896cbb02..19400b89f6 100644 --- a/examples/react/start-convex-trellaux/src/routes/boards.$boardId.tsx +++ b/examples/react/start-convex-trellaux/src/routes/boards.$boardId.tsx @@ -1,9 +1,8 @@ -import { createFileRoute } from '@tanstack/react-router' import { Board } from '~/components/Board' import { Loader } from '~/components/Loader' import { boardQueries } from '~/queries' -export const Route = createFileRoute('/boards/$boardId')({ +export const Route = createFileRoute({ component: Home, pendingComponent: () => , loader: async ({ params, context: { queryClient } }) => { diff --git a/examples/react/start-convex-trellaux/src/routes/index.tsx b/examples/react/start-convex-trellaux/src/routes/index.tsx index 154fc22e70..212bf2f5f8 100644 --- a/examples/react/start-convex-trellaux/src/routes/index.tsx +++ b/examples/react/start-convex-trellaux/src/routes/index.tsx @@ -1,10 +1,10 @@ import { useSuspenseQuery } from '@tanstack/react-query' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { convexQuery } from '@convex-dev/react-query' import { api } from 'convex/_generated/api' import { Loader } from '~/components/Loader' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, pendingComponent: () => , }) diff --git a/examples/react/start-convex-trellaux/src/ssr.tsx b/examples/react/start-convex-trellaux/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-convex-trellaux/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-convex-trellaux/src/tanstack-start.d.ts b/examples/react/start-convex-trellaux/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-convex-trellaux/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-convex-trellaux/vite.config.ts b/examples/react/start-convex-trellaux/vite.config.ts new file mode 100644 index 0000000000..1f5fd1961a --- /dev/null +++ b/examples/react/start-convex-trellaux/vite.config.ts @@ -0,0 +1,15 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/examples/react/start-counter/.gitignore b/examples/react/start-counter/.gitignore index 2b76174be5..08eba9e706 100644 --- a/examples/react/start-counter/.gitignore +++ b/examples/react/start-counter/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/start-counter/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-counter/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/examples/react/start-counter/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-counter/app.config.ts b/examples/react/start-counter/app.config.ts deleted file mode 100644 index 83ec1302eb..0000000000 --- a/examples/react/start-counter/app.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -// app.config.ts -import { defineConfig } from '@tanstack/react-start/config' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, -}) diff --git a/examples/react/start-counter/package.json b/examples/react/start-counter/package.json index 5597354b06..3bb589bff7 100644 --- a/examples/react/start-counter/package.json +++ b/examples/react/start-counter/package.json @@ -4,17 +4,16 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "react": "^19.0.0", - "react-dom": "^19.0.0", - "vinxi": "0.5.3" + "react-dom": "^19.0.0" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/react/start-counter/src/client.tsx b/examples/react/start-counter/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-counter/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-counter/src/routeTree.gen.ts b/examples/react/start-counter/src/routeTree.gen.ts index 5e682936ba..dd5eda94a9 100644 --- a/examples/react/start-counter/src/routeTree.gen.ts +++ b/examples/react/start-counter/src/routeTree.gen.ts @@ -8,14 +8,16 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -29,12 +31,24 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/examples/react/start-counter/src/routes/index.tsx b/examples/react/start-counter/src/routes/index.tsx index 5a02f33eba..04431b1329 100644 --- a/examples/react/start-counter/src/routes/index.tsx +++ b/examples/react/start-counter/src/routes/index.tsx @@ -1,5 +1,5 @@ import * as fs from 'node:fs' -import { createFileRoute, useRouter } from '@tanstack/react-router' +import { useRouter } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' const filePath = 'count.txt' @@ -21,7 +21,7 @@ const updateCount = createServerFn({ method: 'POST' }) await fs.promises.writeFile(filePath, `${count + data}`) }) -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, loader: async () => await getCount(), }) diff --git a/examples/react/start-counter/src/ssr.tsx b/examples/react/start-counter/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-counter/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-counter/src/tanstack-start.d.ts b/examples/react/start-counter/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-counter/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-counter/vite.config.ts b/examples/react/start-counter/vite.config.ts new file mode 100644 index 0000000000..86790438cf --- /dev/null +++ b/examples/react/start-counter/vite.config.ts @@ -0,0 +1,9 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [tanstackStart()], +}) diff --git a/examples/react/start-large/.gitignore b/examples/react/start-large/.gitignore index cb9991202d..ca4ef70bc0 100644 --- a/examples/react/start-large/.gitignore +++ b/examples/react/start-large/.gitignore @@ -13,10 +13,7 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi \ No newline at end of file +/public/build \ No newline at end of file diff --git a/examples/react/start-large/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-large/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..75f8bd4d20 --- /dev/null +++ b/examples/react/start-large/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,110 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +import { ServerRoute as SearchSearchPlaceholderRouteImport } from './../../src/routes/search/searchPlaceholder' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +const SearchSearchPlaceholderRoute = SearchSearchPlaceholderRouteImport.update({ + id: '/search/searchPlaceholder', + path: '/search/searchPlaceholder', + getParentRoute: () => rootRoute, +} as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath { + '/search/searchPlaceholder': { + id: '/search/searchPlaceholder' + path: '/search/searchPlaceholder' + fullPath: '/search/searchPlaceholder' + preLoaderRoute: typeof SearchSearchPlaceholderRouteImport + parentRoute: typeof rootRoute + } + } +} + +// Add type-safety to the createFileRoute function across the route tree + +declare module './../../src/routes/search/searchPlaceholder' { + const createServerFileRoute: CreateServerFileRoute< + FileRoutesByPath['/search/searchPlaceholder']['parentRoute'], + FileRoutesByPath['/search/searchPlaceholder']['id'], + FileRoutesByPath['/search/searchPlaceholder']['path'], + FileRoutesByPath['/search/searchPlaceholder']['fullPath'], + unknown + > +} + +// Create and export the route tree + +export interface FileRoutesByFullPath { + '/search/searchPlaceholder': typeof SearchSearchPlaceholderRoute +} + +export interface FileRoutesByTo { + '/search/searchPlaceholder': typeof SearchSearchPlaceholderRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/search/searchPlaceholder': typeof SearchSearchPlaceholderRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/search/searchPlaceholder' + fileRoutesByTo: FileRoutesByTo + to: '/search/searchPlaceholder' + id: '__root__' | '/search/searchPlaceholder' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + SearchSearchPlaceholderRoute: typeof SearchSearchPlaceholderRoute +} + +const rootRouteChildren: RootRouteChildren = { + SearchSearchPlaceholderRoute: SearchSearchPlaceholderRoute, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/search/searchPlaceholder" + ] + }, + "/search/searchPlaceholder": { + "filePath": "search/searchPlaceholder.tsx" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-large/app.config.ts b/examples/react/start-large/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/examples/react/start-large/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/examples/react/start-large/package.json b/examples/react/start-large/package.json index a9c4ced79d..5bf4907221 100644 --- a/examples/react/start-large/package.json +++ b/examples/react/start-large/package.json @@ -4,23 +4,22 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start", + "dev": "vite dev", + "build": "vite build", + "start": "vite start", "gen": "node ./src/createRoutes.mjs", "test:types": "tsc --extendedDiagnostics" }, "dependencies": { "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "valibot": "^1.0.0-beta.15", - "vinxi": "0.5.3" + "valibot": "^1.0.0-beta.15" }, "devDependencies": { "@types/node": "^22.5.4", @@ -30,7 +29,7 @@ "autoprefixer": "^10.4.20", "tailwindcss": "^3.4.17", "typescript": "^5.7.2", - "vite": "6.1.4", + "vite": "^6.3.5", "vite-tsconfig-paths": "^5.1.4" }, "keywords": [], diff --git a/examples/react/start-large/src/client.tsx b/examples/react/start-large/src/client.tsx deleted file mode 100644 index 4d4c49a500..0000000000 --- a/examples/react/start-large/src/client.tsx +++ /dev/null @@ -1,9 +0,0 @@ -// src/client.tsx -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-large/src/routeTree.gen.ts b/examples/react/start-large/src/routeTree.gen.ts index e4f3a85ab1..44cc9055f8 100644 --- a/examples/react/start-large/src/routeTree.gen.ts +++ b/examples/react/start-large/src/routeTree.gen.ts @@ -8,63 +8,65 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as RelativeImport } from './routes/relative' -import { Route as LinkPropsImport } from './routes/linkProps' -import { Route as AbsoluteImport } from './routes/absolute' -import { Route as SearchRouteImport } from './routes/search/route' -import { Route as ParamsRouteImport } from './routes/params/route' -import { Route as IndexImport } from './routes/index' -import { Route as SearchSearchPlaceholderImport } from './routes/search/searchPlaceholder' -import { Route as ParamsParamsPlaceholderImport } from './routes/params/$paramsPlaceholder' +import { Route as RelativeRouteImport } from './routes/relative' +import { Route as LinkPropsRouteImport } from './routes/linkProps' +import { Route as AbsoluteRouteImport } from './routes/absolute' +import { Route as SearchRouteRouteImport } from './routes/search/route' +import { Route as ParamsRouteRouteImport } from './routes/params/route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as SearchSearchPlaceholderRouteImport } from './routes/search/searchPlaceholder' +import { Route as ParamsParamsPlaceholderRouteImport } from './routes/params/$paramsPlaceholder' // Create/Update Routes -const RelativeRoute = RelativeImport.update({ +const RelativeRoute = RelativeRouteImport.update({ id: '/relative', path: '/relative', getParentRoute: () => rootRoute, } as any) -const LinkPropsRoute = LinkPropsImport.update({ +const LinkPropsRoute = LinkPropsRouteImport.update({ id: '/linkProps', path: '/linkProps', getParentRoute: () => rootRoute, } as any) -const AbsoluteRoute = AbsoluteImport.update({ +const AbsoluteRoute = AbsoluteRouteImport.update({ id: '/absolute', path: '/absolute', getParentRoute: () => rootRoute, } as any) -const SearchRouteRoute = SearchRouteImport.update({ +const SearchRouteRoute = SearchRouteRouteImport.update({ id: '/search', path: '/search', getParentRoute: () => rootRoute, } as any) -const ParamsRouteRoute = ParamsRouteImport.update({ +const ParamsRouteRoute = ParamsRouteRouteImport.update({ id: '/params', path: '/params', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const SearchSearchPlaceholderRoute = SearchSearchPlaceholderImport.update({ +const SearchSearchPlaceholderRoute = SearchSearchPlaceholderRouteImport.update({ id: '/searchPlaceholder', path: '/searchPlaceholder', getParentRoute: () => SearchRouteRoute, } as any) -const ParamsParamsPlaceholderRoute = ParamsParamsPlaceholderImport.update({ +const ParamsParamsPlaceholderRoute = ParamsParamsPlaceholderRouteImport.update({ id: '/$paramsPlaceholder', path: '/$paramsPlaceholder', getParentRoute: () => ParamsRouteRoute, @@ -78,61 +80,136 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/params': { id: '/params' path: '/params' fullPath: '/params' - preLoaderRoute: typeof ParamsRouteImport + preLoaderRoute: typeof ParamsRouteRouteImport parentRoute: typeof rootRoute } '/search': { id: '/search' path: '/search' fullPath: '/search' - preLoaderRoute: typeof SearchRouteImport + preLoaderRoute: typeof SearchRouteRouteImport parentRoute: typeof rootRoute } '/absolute': { id: '/absolute' path: '/absolute' fullPath: '/absolute' - preLoaderRoute: typeof AbsoluteImport + preLoaderRoute: typeof AbsoluteRouteImport parentRoute: typeof rootRoute } '/linkProps': { id: '/linkProps' path: '/linkProps' fullPath: '/linkProps' - preLoaderRoute: typeof LinkPropsImport + preLoaderRoute: typeof LinkPropsRouteImport parentRoute: typeof rootRoute } '/relative': { id: '/relative' path: '/relative' fullPath: '/relative' - preLoaderRoute: typeof RelativeImport + preLoaderRoute: typeof RelativeRouteImport parentRoute: typeof rootRoute } '/params/$paramsPlaceholder': { id: '/params/$paramsPlaceholder' path: '/$paramsPlaceholder' fullPath: '/params/$paramsPlaceholder' - preLoaderRoute: typeof ParamsParamsPlaceholderImport - parentRoute: typeof ParamsRouteImport + preLoaderRoute: typeof ParamsParamsPlaceholderRouteImport + parentRoute: typeof ParamsRouteRouteImport } '/search/searchPlaceholder': { id: '/search/searchPlaceholder' path: '/searchPlaceholder' fullPath: '/search/searchPlaceholder' - preLoaderRoute: typeof SearchSearchPlaceholderImport - parentRoute: typeof SearchRouteImport + preLoaderRoute: typeof SearchSearchPlaceholderRouteImport + parentRoute: typeof SearchRouteRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/params/route' { + const createFileRoute: CreateFileRoute< + '/params', + FileRoutesByPath['/params']['parentRoute'], + FileRoutesByPath['/params']['id'], + FileRoutesByPath['/params']['path'], + FileRoutesByPath['/params']['fullPath'] + > +} +declare module './routes/search/route' { + const createFileRoute: CreateFileRoute< + '/search', + FileRoutesByPath['/search']['parentRoute'], + FileRoutesByPath['/search']['id'], + FileRoutesByPath['/search']['path'], + FileRoutesByPath['/search']['fullPath'] + > +} +declare module './routes/absolute' { + const createFileRoute: CreateFileRoute< + '/absolute', + FileRoutesByPath['/absolute']['parentRoute'], + FileRoutesByPath['/absolute']['id'], + FileRoutesByPath['/absolute']['path'], + FileRoutesByPath['/absolute']['fullPath'] + > +} +declare module './routes/linkProps' { + const createFileRoute: CreateFileRoute< + '/linkProps', + FileRoutesByPath['/linkProps']['parentRoute'], + FileRoutesByPath['/linkProps']['id'], + FileRoutesByPath['/linkProps']['path'], + FileRoutesByPath['/linkProps']['fullPath'] + > +} +declare module './routes/relative' { + const createFileRoute: CreateFileRoute< + '/relative', + FileRoutesByPath['/relative']['parentRoute'], + FileRoutesByPath['/relative']['id'], + FileRoutesByPath['/relative']['path'], + FileRoutesByPath['/relative']['fullPath'] + > +} +declare module './routes/params/$paramsPlaceholder' { + const createFileRoute: CreateFileRoute< + '/params/$paramsPlaceholder', + FileRoutesByPath['/params/$paramsPlaceholder']['parentRoute'], + FileRoutesByPath['/params/$paramsPlaceholder']['id'], + FileRoutesByPath['/params/$paramsPlaceholder']['path'], + FileRoutesByPath['/params/$paramsPlaceholder']['fullPath'] + > +} +declare module './routes/search/searchPlaceholder' { + const createFileRoute: CreateFileRoute< + '/search/searchPlaceholder', + FileRoutesByPath['/search/searchPlaceholder']['parentRoute'], + FileRoutesByPath['/search/searchPlaceholder']['id'], + FileRoutesByPath['/search/searchPlaceholder']['path'], + FileRoutesByPath['/search/searchPlaceholder']['fullPath'] + > +} + // Create and export the route tree interface ParamsRouteRouteChildren { diff --git a/examples/react/start-large/src/routes/__root.tsx b/examples/react/start-large/src/routes/__root.tsx index 789c85c351..b52ca36ae8 100644 --- a/examples/react/start-large/src/routes/__root.tsx +++ b/examples/react/start-large/src/routes/__root.tsx @@ -7,7 +7,6 @@ import { } from '@tanstack/react-router' import type { QueryClient } from '@tanstack/react-query' import type { ReactNode } from 'react' -import appCss from '~/styles.css?url' import { TanStackRouterDevtools } from '@tanstack/react-router-devtools' export interface Context { queryClient: QueryClient @@ -15,7 +14,7 @@ export interface Context { export const Route = createRootRouteWithContext()({ head: () => ({ - links: [{ rel: 'stylesheet', href: appCss }], + links: [{ rel: 'stylesheet' }], meta: [ { charSet: 'utf-8', diff --git a/examples/react/start-large/src/routes/absolute.tsx b/examples/react/start-large/src/routes/absolute.tsx index ba1f875050..857515fa10 100644 --- a/examples/react/start-large/src/routes/absolute.tsx +++ b/examples/react/start-large/src/routes/absolute.tsx @@ -1,7 +1,7 @@ import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' -export const Route = createFileRoute('/absolute')({ +export const Route = createFileRoute({ component: AbsoluteComponent, }) diff --git a/examples/react/start-large/src/routes/index.tsx b/examples/react/start-large/src/routes/index.tsx index eac82a9174..b23956ae17 100644 --- a/examples/react/start-large/src/routes/index.tsx +++ b/examples/react/start-large/src/routes/index.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/examples/react/start-large/src/routes/linkProps.tsx b/examples/react/start-large/src/routes/linkProps.tsx index 4804161ccf..89ef1c2a36 100644 --- a/examples/react/start-large/src/routes/linkProps.tsx +++ b/examples/react/start-large/src/routes/linkProps.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { Link, createFileRoute, linkOptions } from '@tanstack/react-router' +import { Link, linkOptions } from '@tanstack/react-router' import { customRedirect, ListItems, @@ -7,7 +7,7 @@ import { useCustomNavigate, } from '~/typePrimitives' -export const Route = createFileRoute('/linkProps')({ +export const Route = createFileRoute({ component: LinkPropsPage, loader: () => { throw customRedirect({ diff --git a/examples/react/start-large/src/routes/params/$paramsPlaceholder.tsx b/examples/react/start-large/src/routes/params/$paramsPlaceholder.tsx index 45c00d1837..99486e6380 100644 --- a/examples/react/start-large/src/routes/params/$paramsPlaceholder.tsx +++ b/examples/react/start-large/src/routes/params/$paramsPlaceholder.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import * as v from 'valibot' import { queryOptions } from '@tanstack/react-query' import { createMiddleware, createServerFn } from '@tanstack/react-start' @@ -14,7 +14,7 @@ const loaderResult = v.object({ params, }) -const middleware = createMiddleware() +const middleware = createMiddleware({ type: 'function' }) .validator(params) .client(({ next }) => { const context = { client: { paramsPlaceholder: 'paramsPlaceholder' } } @@ -44,7 +44,7 @@ const paramsQueryOptions = queryOptions({ }, }) -export const Route = createFileRoute('/params/$paramsPlaceholder')({ +export const Route = createFileRoute({ component: ParamsComponent, context: () => ({ paramsQueryOptions: queryOptions({ diff --git a/examples/react/start-large/src/routes/params/route.tsx b/examples/react/start-large/src/routes/params/route.tsx index 32f2b82024..a37f312161 100644 --- a/examples/react/start-large/src/routes/params/route.tsx +++ b/examples/react/start-large/src/routes/params/route.tsx @@ -1,6 +1,5 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/params')({ +export const Route = createFileRoute({ component: () =>
Hello /params!
, }) diff --git a/examples/react/start-large/src/routes/relative.tsx b/examples/react/start-large/src/routes/relative.tsx index 6f6e581efd..cf25ec6f9f 100644 --- a/examples/react/start-large/src/routes/relative.tsx +++ b/examples/react/start-large/src/routes/relative.tsx @@ -1,7 +1,7 @@ import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' -export const Route = createFileRoute('/relative')({ +export const Route = createFileRoute({ component: RelativeComponent, }) diff --git a/examples/react/start-large/src/routes/search/route.tsx b/examples/react/start-large/src/routes/search/route.tsx index 3bcbe420e1..9829854586 100644 --- a/examples/react/start-large/src/routes/search/route.tsx +++ b/examples/react/start-large/src/routes/search/route.tsx @@ -1,11 +1,10 @@ -import { createFileRoute } from '@tanstack/react-router' import * as v from 'valibot' const search = v.object({ rootSearch: v.number(), }) -export const Route = createFileRoute('/search')({ +export const Route = createFileRoute({ component: () =>
Hello /search!
, validateSearch: search, }) diff --git a/examples/react/start-large/src/routes/search/searchPlaceholder.tsx b/examples/react/start-large/src/routes/search/searchPlaceholder.tsx index 56dc0a2931..1071a38cb7 100644 --- a/examples/react/start-large/src/routes/search/searchPlaceholder.tsx +++ b/examples/react/start-large/src/routes/search/searchPlaceholder.tsx @@ -1,4 +1,4 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import * as v from 'valibot' import { queryOptions } from '@tanstack/react-query' @@ -15,7 +15,7 @@ const loaderResult = v.object({ searchPlaceholder: v.number(), }) -const middleware = createMiddleware() +const middleware = createMiddleware({ type: 'function' }) .validator(search) .client(({ next }) => { const context = { client: { searchPlaceholder: 'searchPlaceholder' } } @@ -42,7 +42,13 @@ const fn = createServerFn() return result }) -export const Route = createFileRoute('/search/searchPlaceholder')({ +export const ServerRoute = createServerFileRoute().methods((api) => ({ + GET: api.handler(() => { + return 'searchPlaceholder' + }), +})) + +export const Route = createFileRoute({ component: SearchComponent, validateSearch: search, loaderDeps: ({ search }) => ({ search }), @@ -52,8 +58,16 @@ export const Route = createFileRoute('/search/searchPlaceholder')({ queryFn: () => fn({ data: ctx.deps.search }), }), }), - loader: (opts) => - opts.context.queryClient.ensureQueryData(opts.context.searchQueryOptions), + loader: async (opts) => { + const search = await opts.context.queryClient.ensureQueryData( + opts.context.searchQueryOptions, + ) + + return { + search, + external, + } + }, }) function SearchComponent() { diff --git a/examples/react/start-large/src/ssr.tsx b/examples/react/start-large/src/ssr.tsx deleted file mode 100644 index a24fb32843..0000000000 --- a/examples/react/start-large/src/ssr.tsx +++ /dev/null @@ -1,14 +0,0 @@ -// src/ssr.tsx -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-large/src/tanstack-start.d.ts b/examples/react/start-large/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-large/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-large/vite.config.ts b/examples/react/start-large/vite.config.ts new file mode 100644 index 0000000000..1f5fd1961a --- /dev/null +++ b/examples/react/start-large/vite.config.ts @@ -0,0 +1,15 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/examples/react/start-material-ui/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-material-ui/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/examples/react/start-material-ui/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-material-ui/app.config.ts b/examples/react/start-material-ui/app.config.ts deleted file mode 100644 index 659f799bb9..0000000000 --- a/examples/react/start-material-ui/app.config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - ssr: { - noExternal: ['@mui/*'], - }, - - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/examples/react/start-material-ui/package.json b/examples/react/start-material-ui/package.json index e327c367b7..ae67daab56 100644 --- a/examples/react/start-material-ui/package.json +++ b/examples/react/start-material-ui/package.json @@ -4,9 +4,9 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { "@emotion/cache": "11.14.0", @@ -14,12 +14,11 @@ "@emotion/styled": "11.14.0", "@fontsource-variable/roboto": "5.2.5", "@mui/material": "6.4.7", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-start": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/examples/react/start-material-ui/src/client.tsx b/examples/react/start-material-ui/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-material-ui/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-material-ui/src/routeTree.gen.ts b/examples/react/start-material-ui/src/routeTree.gen.ts index 48c183c8da..3f5c19883b 100644 --- a/examples/react/start-material-ui/src/routeTree.gen.ts +++ b/examples/react/start-material-ui/src/routeTree.gen.ts @@ -8,21 +8,23 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as AboutImport } from './routes/about' -import { Route as IndexImport } from './routes/index' +import { Route as AboutRouteImport } from './routes/about' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const AboutRoute = AboutImport.update({ +const AboutRoute = AboutRouteImport.update({ id: '/about', path: '/about', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -36,19 +38,40 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/about': { id: '/about' path: '/about' fullPath: '/about' - preLoaderRoute: typeof AboutImport + preLoaderRoute: typeof AboutRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/about' { + const createFileRoute: CreateFileRoute< + '/about', + FileRoutesByPath['/about']['parentRoute'], + FileRoutesByPath['/about']['id'], + FileRoutesByPath['/about']['path'], + FileRoutesByPath['/about']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/examples/react/start-material-ui/src/routes/about.tsx b/examples/react/start-material-ui/src/routes/about.tsx index 39492e85d7..1a9b347084 100644 --- a/examples/react/start-material-ui/src/routes/about.tsx +++ b/examples/react/start-material-ui/src/routes/about.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import { Typography } from '@mui/material' -export const Route = createFileRoute('/about')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/examples/react/start-material-ui/src/routes/index.tsx b/examples/react/start-material-ui/src/routes/index.tsx index 75f5d14de4..f52a53f5ad 100644 --- a/examples/react/start-material-ui/src/routes/index.tsx +++ b/examples/react/start-material-ui/src/routes/index.tsx @@ -1,9 +1,8 @@ -import { createFileRoute } from '@tanstack/react-router' import { Stack, Typography } from '@mui/material' import z from 'zod' import { Counter } from '~/components/Counter' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ validateSearch: z.object({ count: z.number().optional(), }), diff --git a/examples/react/start-material-ui/src/ssr.tsx b/examples/react/start-material-ui/src/ssr.tsx deleted file mode 100644 index 65a580f25e..0000000000 --- a/examples/react/start-material-ui/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-material-ui/src/tanstack-start.d.ts b/examples/react/start-material-ui/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-material-ui/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-material-ui/vite.config.ts b/examples/react/start-material-ui/vite.config.ts new file mode 100644 index 0000000000..1f5fd1961a --- /dev/null +++ b/examples/react/start-material-ui/vite.config.ts @@ -0,0 +1,15 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/examples/react/start-supabase-basic/.gitignore b/examples/react/start-supabase-basic/.gitignore index 5578fb7487..8293849e8d 100644 --- a/examples/react/start-supabase-basic/.gitignore +++ b/examples/react/start-supabase-basic/.gitignore @@ -9,14 +9,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/start-supabase-basic/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-supabase-basic/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/examples/react/start-supabase-basic/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-supabase-basic/app.config.ts b/examples/react/start-supabase-basic/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/examples/react/start-supabase-basic/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/examples/react/start-supabase-basic/package.json b/examples/react/start-supabase-basic/package.json index 45d347e083..009839f1a9 100644 --- a/examples/react/start-supabase-basic/package.json +++ b/examples/react/start-supabase-basic/package.json @@ -5,9 +5,9 @@ "main": "index.js", "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "keywords": [], "author": "", @@ -15,12 +15,11 @@ "dependencies": { "@supabase/ssr": "^0.5.2", "@supabase/supabase-js": "^2.48.1", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "react": "^19.0.0", - "react-dom": "^19.0.0", - "vinxi": "0.5.3" + "react-dom": "^19.0.0" }, "devDependencies": { "@types/react": "^19.0.8", diff --git a/examples/react/start-supabase-basic/src/client.tsx b/examples/react/start-supabase-basic/src/client.tsx deleted file mode 100644 index 4d4c49a500..0000000000 --- a/examples/react/start-supabase-basic/src/client.tsx +++ /dev/null @@ -1,9 +0,0 @@ -// src/client.tsx -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-supabase-basic/src/routeTree.gen.ts b/examples/react/start-supabase-basic/src/routeTree.gen.ts index a37809fd07..664daacd0d 100644 --- a/examples/react/start-supabase-basic/src/routeTree.gen.ts +++ b/examples/react/start-supabase-basic/src/routeTree.gen.ts @@ -8,62 +8,64 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as SignupImport } from './routes/signup' -import { Route as LogoutImport } from './routes/logout' -import { Route as LoginImport } from './routes/login' -import { Route as AuthedImport } from './routes/_authed' -import { Route as IndexImport } from './routes/index' -import { Route as AuthedPostsImport } from './routes/_authed/posts' -import { Route as AuthedPostsIndexImport } from './routes/_authed/posts.index' -import { Route as AuthedPostsPostIdImport } from './routes/_authed/posts.$postId' +import { Route as SignupRouteImport } from './routes/signup' +import { Route as LogoutRouteImport } from './routes/logout' +import { Route as LoginRouteImport } from './routes/login' +import { Route as AuthedRouteImport } from './routes/_authed' +import { Route as IndexRouteImport } from './routes/index' +import { Route as AuthedPostsRouteImport } from './routes/_authed/posts' +import { Route as AuthedPostsIndexRouteImport } from './routes/_authed/posts.index' +import { Route as AuthedPostsPostIdRouteImport } from './routes/_authed/posts.$postId' // Create/Update Routes -const SignupRoute = SignupImport.update({ +const SignupRoute = SignupRouteImport.update({ id: '/signup', path: '/signup', getParentRoute: () => rootRoute, } as any) -const LogoutRoute = LogoutImport.update({ +const LogoutRoute = LogoutRouteImport.update({ id: '/logout', path: '/logout', getParentRoute: () => rootRoute, } as any) -const LoginRoute = LoginImport.update({ +const LoginRoute = LoginRouteImport.update({ id: '/login', path: '/login', getParentRoute: () => rootRoute, } as any) -const AuthedRoute = AuthedImport.update({ +const AuthedRoute = AuthedRouteImport.update({ id: '/_authed', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const AuthedPostsRoute = AuthedPostsImport.update({ +const AuthedPostsRoute = AuthedPostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => AuthedRoute, } as any) -const AuthedPostsIndexRoute = AuthedPostsIndexImport.update({ +const AuthedPostsIndexRoute = AuthedPostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => AuthedPostsRoute, } as any) -const AuthedPostsPostIdRoute = AuthedPostsPostIdImport.update({ +const AuthedPostsPostIdRoute = AuthedPostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => AuthedPostsRoute, @@ -77,61 +79,136 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_authed': { id: '/_authed' path: '' fullPath: '' - preLoaderRoute: typeof AuthedImport + preLoaderRoute: typeof AuthedRouteImport parentRoute: typeof rootRoute } '/login': { id: '/login' path: '/login' fullPath: '/login' - preLoaderRoute: typeof LoginImport + preLoaderRoute: typeof LoginRouteImport parentRoute: typeof rootRoute } '/logout': { id: '/logout' path: '/logout' fullPath: '/logout' - preLoaderRoute: typeof LogoutImport + preLoaderRoute: typeof LogoutRouteImport parentRoute: typeof rootRoute } '/signup': { id: '/signup' path: '/signup' fullPath: '/signup' - preLoaderRoute: typeof SignupImport + preLoaderRoute: typeof SignupRouteImport parentRoute: typeof rootRoute } '/_authed/posts': { id: '/_authed/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof AuthedPostsImport - parentRoute: typeof AuthedImport + preLoaderRoute: typeof AuthedPostsRouteImport + parentRoute: typeof AuthedRouteImport } '/_authed/posts/$postId': { id: '/_authed/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof AuthedPostsPostIdImport - parentRoute: typeof AuthedPostsImport + preLoaderRoute: typeof AuthedPostsPostIdRouteImport + parentRoute: typeof AuthedPostsRouteImport } '/_authed/posts/': { id: '/_authed/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof AuthedPostsIndexImport - parentRoute: typeof AuthedPostsImport + preLoaderRoute: typeof AuthedPostsIndexRouteImport + parentRoute: typeof AuthedPostsRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_authed' { + const createFileRoute: CreateFileRoute< + '/_authed', + FileRoutesByPath['/_authed']['parentRoute'], + FileRoutesByPath['/_authed']['id'], + FileRoutesByPath['/_authed']['path'], + FileRoutesByPath['/_authed']['fullPath'] + > +} +declare module './routes/login' { + const createFileRoute: CreateFileRoute< + '/login', + FileRoutesByPath['/login']['parentRoute'], + FileRoutesByPath['/login']['id'], + FileRoutesByPath['/login']['path'], + FileRoutesByPath['/login']['fullPath'] + > +} +declare module './routes/logout' { + const createFileRoute: CreateFileRoute< + '/logout', + FileRoutesByPath['/logout']['parentRoute'], + FileRoutesByPath['/logout']['id'], + FileRoutesByPath['/logout']['path'], + FileRoutesByPath['/logout']['fullPath'] + > +} +declare module './routes/signup' { + const createFileRoute: CreateFileRoute< + '/signup', + FileRoutesByPath['/signup']['parentRoute'], + FileRoutesByPath['/signup']['id'], + FileRoutesByPath['/signup']['path'], + FileRoutesByPath['/signup']['fullPath'] + > +} +declare module './routes/_authed/posts' { + const createFileRoute: CreateFileRoute< + '/_authed/posts', + FileRoutesByPath['/_authed/posts']['parentRoute'], + FileRoutesByPath['/_authed/posts']['id'], + FileRoutesByPath['/_authed/posts']['path'], + FileRoutesByPath['/_authed/posts']['fullPath'] + > +} +declare module './routes/_authed/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/_authed/posts/$postId', + FileRoutesByPath['/_authed/posts/$postId']['parentRoute'], + FileRoutesByPath['/_authed/posts/$postId']['id'], + FileRoutesByPath['/_authed/posts/$postId']['path'], + FileRoutesByPath['/_authed/posts/$postId']['fullPath'] + > +} +declare module './routes/_authed/posts.index' { + const createFileRoute: CreateFileRoute< + '/_authed/posts/', + FileRoutesByPath['/_authed/posts/']['parentRoute'], + FileRoutesByPath['/_authed/posts/']['id'], + FileRoutesByPath['/_authed/posts/']['path'], + FileRoutesByPath['/_authed/posts/']['fullPath'] + > +} + // Create and export the route tree interface AuthedPostsRouteChildren { diff --git a/examples/react/start-supabase-basic/src/routes/_authed.tsx b/examples/react/start-supabase-basic/src/routes/_authed.tsx index 91b9ca133f..4ecd57cb86 100644 --- a/examples/react/start-supabase-basic/src/routes/_authed.tsx +++ b/examples/react/start-supabase-basic/src/routes/_authed.tsx @@ -1,4 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import { Login } from '../components/Login' import { getSupabaseServerClient } from '../utils/supabase' @@ -20,7 +19,7 @@ export const loginFn = createServerFn({ method: 'POST' }) } }) -export const Route = createFileRoute('/_authed')({ +export const Route = createFileRoute({ beforeLoad: ({ context }) => { if (!context.user) { throw new Error('Not authenticated') diff --git a/examples/react/start-supabase-basic/src/routes/_authed/posts.$postId.tsx b/examples/react/start-supabase-basic/src/routes/_authed/posts.$postId.tsx index 4dd11756a8..0c58d7839f 100644 --- a/examples/react/start-supabase-basic/src/routes/_authed/posts.$postId.tsx +++ b/examples/react/start-supabase-basic/src/routes/_authed/posts.$postId.tsx @@ -1,9 +1,9 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import type { ErrorComponentProps } from '@tanstack/react-router' import { NotFound } from '~/components/NotFound' import { fetchPost } from '~/utils/posts' -export const Route = createFileRoute('/_authed/posts/$postId')({ +export const Route = createFileRoute({ loader: ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, diff --git a/examples/react/start-supabase-basic/src/routes/_authed/posts.index.tsx b/examples/react/start-supabase-basic/src/routes/_authed/posts.index.tsx index ea9e667e54..13529228bb 100644 --- a/examples/react/start-supabase-basic/src/routes/_authed/posts.index.tsx +++ b/examples/react/start-supabase-basic/src/routes/_authed/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_authed/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/examples/react/start-supabase-basic/src/routes/_authed/posts.tsx b/examples/react/start-supabase-basic/src/routes/_authed/posts.tsx index f7d863b8b9..fbcf599a08 100644 --- a/examples/react/start-supabase-basic/src/routes/_authed/posts.tsx +++ b/examples/react/start-supabase-basic/src/routes/_authed/posts.tsx @@ -1,7 +1,7 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../../utils/posts' -export const Route = createFileRoute('/_authed/posts')({ +export const Route = createFileRoute({ loader: () => fetchPosts(), component: PostsComponent, }) diff --git a/examples/react/start-supabase-basic/src/routes/index.tsx b/examples/react/start-supabase-basic/src/routes/index.tsx index 09a907cb18..f6c5b98b02 100644 --- a/examples/react/start-supabase-basic/src/routes/index.tsx +++ b/examples/react/start-supabase-basic/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/examples/react/start-supabase-basic/src/routes/login.tsx b/examples/react/start-supabase-basic/src/routes/login.tsx index 64b539d819..9d7bd16865 100644 --- a/examples/react/start-supabase-basic/src/routes/login.tsx +++ b/examples/react/start-supabase-basic/src/routes/login.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' import { Login } from '../components/Login' -export const Route = createFileRoute('/login')({ +export const Route = createFileRoute({ component: LoginComp, }) diff --git a/examples/react/start-supabase-basic/src/routes/logout.tsx b/examples/react/start-supabase-basic/src/routes/logout.tsx index a2f495c7fb..4b170c9bdd 100644 --- a/examples/react/start-supabase-basic/src/routes/logout.tsx +++ b/examples/react/start-supabase-basic/src/routes/logout.tsx @@ -1,4 +1,4 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import { getSupabaseServerClient } from '../utils/supabase' @@ -18,7 +18,7 @@ const logoutFn = createServerFn().handler(async () => { }) }) -export const Route = createFileRoute('/logout')({ +export const Route = createFileRoute({ preload: false, loader: () => logoutFn(), }) diff --git a/examples/react/start-supabase-basic/src/routes/signup.tsx b/examples/react/start-supabase-basic/src/routes/signup.tsx index f37a2fa6a8..5896510b23 100644 --- a/examples/react/start-supabase-basic/src/routes/signup.tsx +++ b/examples/react/start-supabase-basic/src/routes/signup.tsx @@ -1,4 +1,4 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' import { createServerFn, useServerFn } from '@tanstack/react-start' import { useMutation } from '../hooks/useMutation' import { Auth } from '../components/Auth' @@ -27,7 +27,7 @@ export const signupFn = createServerFn({ method: 'POST' }) }) }) -export const Route = createFileRoute('/signup')({ +export const Route = createFileRoute({ component: SignupComp, }) diff --git a/examples/react/start-supabase-basic/src/ssr.tsx b/examples/react/start-supabase-basic/src/ssr.tsx deleted file mode 100644 index a24fb32843..0000000000 --- a/examples/react/start-supabase-basic/src/ssr.tsx +++ /dev/null @@ -1,14 +0,0 @@ -// src/ssr.tsx -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-supabase-basic/src/tanstack-start.d.ts b/examples/react/start-supabase-basic/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-supabase-basic/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-supabase-basic/vite.config.ts b/examples/react/start-supabase-basic/vite.config.ts new file mode 100644 index 0000000000..1f5fd1961a --- /dev/null +++ b/examples/react/start-supabase-basic/vite.config.ts @@ -0,0 +1,15 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/examples/react/start-tailwind-v4/.gitignore b/examples/react/start-tailwind-v4/.gitignore new file mode 100644 index 0000000000..0bb5a583db --- /dev/null +++ b/examples/react/start-tailwind-v4/.gitignore @@ -0,0 +1,20 @@ +node_modules +package-lock.json +yarn.lock + +.DS_Store +.cache +.env +.vercel +.output +.nitro +/build/ +/api/ +/server/build +/public/build# Sentry Config File +.env.sentry-build-plugin +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +.tanstack-start/build \ No newline at end of file diff --git a/examples/react/start-tailwind-v4/.prettierignore b/examples/react/start-tailwind-v4/.prettierignore new file mode 100644 index 0000000000..2be5eaa6ec --- /dev/null +++ b/examples/react/start-tailwind-v4/.prettierignore @@ -0,0 +1,4 @@ +**/build +**/public +pnpm-lock.yaml +routeTree.gen.ts \ No newline at end of file diff --git a/examples/react/start-tailwind-v4/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-tailwind-v4/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/examples/react/start-tailwind-v4/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-tailwind-v4/.vscode/settings.json b/examples/react/start-tailwind-v4/.vscode/settings.json new file mode 100644 index 0000000000..00b5278e58 --- /dev/null +++ b/examples/react/start-tailwind-v4/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "files.watcherExclude": { + "**/routeTree.gen.ts": true + }, + "search.exclude": { + "**/routeTree.gen.ts": true + }, + "files.readonlyInclude": { + "**/routeTree.gen.ts": true + } +} diff --git a/examples/react/start-tailwind-v4/README.md b/examples/react/start-tailwind-v4/README.md new file mode 100644 index 0000000000..90cba4aac1 --- /dev/null +++ b/examples/react/start-tailwind-v4/README.md @@ -0,0 +1,72 @@ +# Welcome to TanStack.com! + +This site is built with TanStack Router! + +- [TanStack Router Docs](https://tanstack.com/router) + +It's deployed automagically with Netlify! + +- [Netlify](https://netlify.com/) + +## Development + +From your terminal: + +```sh +pnpm install +pnpm dev +``` + +This starts your app in development mode, rebuilding assets on file changes. + +## Editing and previewing the docs of TanStack projects locally + +The documentations for all TanStack projects except for `React Charts` are hosted on [https://tanstack.com](https://tanstack.com), powered by this TanStack Router app. +In production, the markdown doc pages are fetched from the GitHub repos of the projects, but in development they are read from the local file system. + +Follow these steps if you want to edit the doc pages of a project (in these steps we'll assume it's [`TanStack/form`](https://github.com/tanstack/form)) and preview them locally : + +1. Create a new directory called `tanstack`. + +```sh +mkdir tanstack +``` + +2. Enter the directory and clone this repo and the repo of the project there. + +```sh +cd tanstack +git clone git@github.com:TanStack/tanstack.com.git +git clone git@github.com:TanStack/form.git +``` + +> [!NOTE] +> Your `tanstack` directory should look like this: +> +> ``` +> tanstack/ +> | +> +-- form/ +> | +> +-- tanstack.com/ +> ``` + +> [!WARNING] +> Make sure the name of the directory in your local file system matches the name of the project's repo. For example, `tanstack/form` must be cloned into `form` (this is the default) instead of `some-other-name`, because that way, the doc pages won't be found. + +3. Enter the `tanstack/tanstack.com` directory, install the dependencies and run the app in dev mode: + +```sh +cd tanstack.com +pnpm i +# The app will run on https://localhost:3000 by default +pnpm dev +``` + +4. Now you can visit http://localhost:3000/form/latest/docs/overview in the browser and see the changes you make in `tanstack/form/docs`. + +> [!NOTE] +> The updated pages need to be manually reloaded in the browser. + +> [!WARNING] +> You will need to update the `docs/config.json` file (in the project's repo) if you add a new doc page! diff --git a/examples/react/start-tailwind-v4/package.json b/examples/react/start-tailwind-v4/package.json new file mode 100644 index 0000000000..8c9a821ecf --- /dev/null +++ b/examples/react/start-tailwind-v4/package.json @@ -0,0 +1,30 @@ +{ + "name": "tanstack-start-tailwind-v4", + "private": true, + "sideEffects": false, + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "start": "node .output/server/index.mjs" + }, + "dependencies": { + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tailwind-merge": "^2.6.0", + "vite": "^6.3.5", + "zod": "^3.24.2" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.1.6", + "@types/node": "^22.5.4", + "@types/react": "^19.0.8", + "@types/react-dom": "^19.0.3", + "tailwindcss": "^4.1.6", + "typescript": "^5.7.2", + "vite-tsconfig-paths": "^5.1.4" + } +} diff --git a/examples/react/start-tailwind-v4/src/routeTree.gen.ts b/examples/react/start-tailwind-v4/src/routeTree.gen.ts new file mode 100644 index 0000000000..dd5eda94a9 --- /dev/null +++ b/examples/react/start-tailwind-v4/src/routeTree.gen.ts @@ -0,0 +1,102 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + +// Import Routes + +import { Route as rootRoute } from './routes/__root' +import { Route as IndexRouteImport } from './routes/index' + +// Create/Update Routes + +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRoute, +} as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRoute + } + } +} + +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} + +// Create and export the route tree + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute +} + +export interface FileRoutesByTo { + '/': typeof IndexRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/': typeof IndexRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/' + fileRoutesByTo: FileRoutesByTo + to: '/' + id: '__root__' | '/' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/" + ] + }, + "/": { + "filePath": "index.tsx" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-tailwind-v4/src/router.tsx b/examples/react/start-tailwind-v4/src/router.tsx new file mode 100644 index 0000000000..b8744cb41f --- /dev/null +++ b/examples/react/start-tailwind-v4/src/router.tsx @@ -0,0 +1,18 @@ +import { createRouter as createTanStackRouter } from '@tanstack/react-router' +import { routeTree } from './routeTree.gen' + +export function createRouter() { + const router = createTanStackRouter({ + routeTree, + defaultPreload: 'intent', + scrollRestoration: true, + }) + + return router +} + +declare module '@tanstack/react-router' { + interface Register { + router: ReturnType + } +} diff --git a/examples/react/start-tailwind-v4/src/routes/__root.tsx b/examples/react/start-tailwind-v4/src/routes/__root.tsx new file mode 100644 index 0000000000..0d08681e8f --- /dev/null +++ b/examples/react/start-tailwind-v4/src/routes/__root.tsx @@ -0,0 +1,52 @@ +import { + HeadContent, + Link, + Outlet, + Scripts, + createRootRoute, +} from '@tanstack/react-router' +import { TanStackRouterDevtools } from '@tanstack/react-router-devtools' +import * as React from 'react' +import appCss from '~/styles/app.css?url' + +export const Route = createRootRoute({ + head: () => ({ + links: [{ rel: 'stylesheet', href: appCss }], + }), + component: RootComponent, +}) + +function RootComponent() { + return ( + + + + ) +} + +function RootDocument({ children }: { children: React.ReactNode }) { + return ( + + + + + +
+ + Home + +
+
+ {children} + + + + + ) +} diff --git a/examples/react/start-tailwind-v4/src/routes/index.tsx b/examples/react/start-tailwind-v4/src/routes/index.tsx new file mode 100644 index 0000000000..f6c5b98b02 --- /dev/null +++ b/examples/react/start-tailwind-v4/src/routes/index.tsx @@ -0,0 +1,11 @@ +export const Route = createFileRoute({ + component: Home, +}) + +function Home() { + return ( +
+

Welcome Home!!!

+
+ ) +} diff --git a/examples/react/start-tailwind-v4/src/styles/app.css b/examples/react/start-tailwind-v4/src/styles/app.css new file mode 100644 index 0000000000..dcca122a5c --- /dev/null +++ b/examples/react/start-tailwind-v4/src/styles/app.css @@ -0,0 +1,20 @@ +@import 'tailwindcss' source('../'); + +@layer base { + html { + color-scheme: light dark; + } + + * { + @apply border-gray-200 dark:border-gray-800; + } + + html, + body { + @apply text-gray-900 bg-gray-50 dark:bg-gray-950 dark:text-gray-200; + } + + .using-mouse * { + outline: none !important; + } +} diff --git a/examples/react/start-tailwind-v4/src/tanstack-start.d.ts b/examples/react/start-tailwind-v4/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-tailwind-v4/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-tailwind-v4/tsconfig.json b/examples/react/start-tailwind-v4/tsconfig.json new file mode 100644 index 0000000000..3a9fb7cd71 --- /dev/null +++ b/examples/react/start-tailwind-v4/tsconfig.json @@ -0,0 +1,22 @@ +{ + "include": ["**/*.ts", "**/*.tsx"], + "compilerOptions": { + "strict": true, + "esModuleInterop": true, + "jsx": "react-jsx", + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "isolatedModules": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "target": "ES2022", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "paths": { + "~/*": ["./src/*"] + }, + "noEmit": true + } +} diff --git a/examples/react/start-tailwind-v4/vite.config.ts b/examples/react/start-tailwind-v4/vite.config.ts new file mode 100644 index 0000000000..6a8f14e7c0 --- /dev/null +++ b/examples/react/start-tailwind-v4/vite.config.ts @@ -0,0 +1,17 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + tailwindcss(), + ], +}) diff --git a/examples/react/start-trellaux/.gitignore b/examples/react/start-trellaux/.gitignore index d3387e00cd..3c8e6870b3 100644 --- a/examples/react/start-trellaux/.gitignore +++ b/examples/react/start-trellaux/.gitignore @@ -7,12 +7,8 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin diff --git a/examples/react/start-trellaux/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-trellaux/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..52adc3a6f3 --- /dev/null +++ b/examples/react/start-trellaux/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/react-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/react-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-trellaux/app.config.ts b/examples/react/start-trellaux/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/examples/react/start-trellaux/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/examples/react/start-trellaux/package.json b/examples/react/start-trellaux/package.json index 8e30f6062d..eca0851c68 100644 --- a/examples/react/start-trellaux/package.json +++ b/examples/react/start-trellaux/package.json @@ -4,17 +4,17 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-with-query": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-with-query": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "ky": "^1.7.4", "msw": "^2.7.0", "react": "^19.0.0", @@ -23,7 +23,6 @@ "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", "tiny-invariant": "^1.3.3", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/examples/react/start-trellaux/src/client.tsx b/examples/react/start-trellaux/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-trellaux/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-trellaux/src/routeTree.gen.ts b/examples/react/start-trellaux/src/routeTree.gen.ts index 7ee57387dc..e8cc65e620 100644 --- a/examples/react/start-trellaux/src/routeTree.gen.ts +++ b/examples/react/start-trellaux/src/routeTree.gen.ts @@ -8,21 +8,23 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' -import { Route as BoardsBoardIdImport } from './routes/boards.$boardId' +import { Route as IndexRouteImport } from './routes/index' +import { Route as BoardsBoardIdRouteImport } from './routes/boards.$boardId' // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const BoardsBoardIdRoute = BoardsBoardIdImport.update({ +const BoardsBoardIdRoute = BoardsBoardIdRouteImport.update({ id: '/boards/$boardId', path: '/boards/$boardId', getParentRoute: () => rootRoute, @@ -36,19 +38,40 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/boards/$boardId': { id: '/boards/$boardId' path: '/boards/$boardId' fullPath: '/boards/$boardId' - preLoaderRoute: typeof BoardsBoardIdImport + preLoaderRoute: typeof BoardsBoardIdRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/boards.$boardId' { + const createFileRoute: CreateFileRoute< + '/boards/$boardId', + FileRoutesByPath['/boards/$boardId']['parentRoute'], + FileRoutesByPath['/boards/$boardId']['id'], + FileRoutesByPath['/boards/$boardId']['path'], + FileRoutesByPath['/boards/$boardId']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/examples/react/start-trellaux/src/routes/boards.$boardId.tsx b/examples/react/start-trellaux/src/routes/boards.$boardId.tsx index 36896cbb02..19400b89f6 100644 --- a/examples/react/start-trellaux/src/routes/boards.$boardId.tsx +++ b/examples/react/start-trellaux/src/routes/boards.$boardId.tsx @@ -1,9 +1,8 @@ -import { createFileRoute } from '@tanstack/react-router' import { Board } from '~/components/Board' import { Loader } from '~/components/Loader' import { boardQueries } from '~/queries' -export const Route = createFileRoute('/boards/$boardId')({ +export const Route = createFileRoute({ component: Home, pendingComponent: () => , loader: async ({ params, context: { queryClient } }) => { diff --git a/examples/react/start-trellaux/src/routes/index.tsx b/examples/react/start-trellaux/src/routes/index.tsx index 3b9e1a5fac..85baed6c0b 100644 --- a/examples/react/start-trellaux/src/routes/index.tsx +++ b/examples/react/start-trellaux/src/routes/index.tsx @@ -1,9 +1,9 @@ import { useSuspenseQuery } from '@tanstack/react-query' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { Loader } from '~/components/Loader' import { boardQueries } from '~/queries' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, pendingComponent: () => , }) diff --git a/examples/react/start-trellaux/src/ssr.tsx b/examples/react/start-trellaux/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-trellaux/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-trellaux/src/tanstack-start.d.ts b/examples/react/start-trellaux/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/react/start-trellaux/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/react/start-trellaux/vite.config.ts b/examples/react/start-trellaux/vite.config.ts new file mode 100644 index 0000000000..1f5fd1961a --- /dev/null +++ b/examples/react/start-trellaux/vite.config.ts @@ -0,0 +1,15 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}) diff --git a/examples/react/start-workos/.gitignore b/examples/react/start-workos/.gitignore index c274dbb056..51e00c0d4a 100644 --- a/examples/react/start-workos/.gitignore +++ b/examples/react/start-workos/.gitignore @@ -7,10 +7,8 @@ yarn.lock .env .vercel .output -.vinxi /build/ /api/ /server/build /public/build -.vinxi diff --git a/examples/react/start-workos/.prettierignore b/examples/react/start-workos/.prettierignore new file mode 100644 index 0000000000..2be5eaa6ec --- /dev/null +++ b/examples/react/start-workos/.prettierignore @@ -0,0 +1,4 @@ +**/build +**/public +pnpm-lock.yaml +routeTree.gen.ts \ No newline at end of file diff --git a/examples/react/start-workos/.tanstack-start/server-routes/routeTree.gen.ts b/examples/react/start-workos/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..e4a8044a28 --- /dev/null +++ b/examples/react/start-workos/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,62 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { FileRoutesByPath, CreateServerFileRoute } from '@tanstack/react-start/server'; +import { createServerRoute, createServerFileRoute } from '@tanstack/react-start/server'; + +// Create/Update Routes + +const rootRoute = createServerRoute(); + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute; +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath; + fullPaths: never; + fileRoutesByTo: FileRoutesByTo; + to: never; + id: '__root__'; + fileRoutesById: FileRoutesById; +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {}; + +export const routeTree = rootRoute._addFileChildren(rootRouteChildren)._addFileTypes(); + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/react/start-workos/app.config.ts b/examples/react/start-workos/app.config.ts deleted file mode 100644 index 3096b30089..0000000000 --- a/examples/react/start-workos/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config'; -import tsConfigPaths from 'vite-tsconfig-paths'; - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}); diff --git a/examples/react/start-workos/package.json b/examples/react/start-workos/package.json index 9b4f6be98b..4d6251869e 100644 --- a/examples/react/start-workos/package.json +++ b/examples/react/start-workos/package.json @@ -5,24 +5,24 @@ "main": "index.js", "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "keywords": [], "author": "", - "license": "ISC", + "license": "MIT", "dependencies": { "@radix-ui/themes": "^3.2.1", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "@workos-inc/node": "^7.45.0", "iron-session": "^8.0.4", "jose": "^6.0.10", "react": "^19.0.0", "react-dom": "^19.0.0", - "vinxi": "0.5.3" + "vite": "^6.3.5" }, "devDependencies": { "@types/react": "^19.0.8", diff --git a/examples/react/start-workos/src/client.tsx b/examples/react/start-workos/src/client.tsx deleted file mode 100644 index 253f9bc7ea..0000000000 --- a/examples/react/start-workos/src/client.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { StartClient } from '@tanstack/react-start'; -import { hydrateRoot } from 'react-dom/client'; -import { createRouter } from './router'; - -const router = createRouter(); - -hydrateRoot(document, ); diff --git a/examples/react/start-workos/src/routeTree.gen.ts b/examples/react/start-workos/src/routeTree.gen.ts index f7cb0a82d5..1ff74abe50 100644 --- a/examples/react/start-workos/src/routeTree.gen.ts +++ b/examples/react/start-workos/src/routeTree.gen.ts @@ -8,34 +8,36 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router'; + // Import Routes import { Route as rootRoute } from './routes/__root'; -import { Route as LogoutImport } from './routes/logout'; -import { Route as AuthenticatedImport } from './routes/_authenticated'; -import { Route as IndexImport } from './routes/index'; -import { Route as AuthenticatedAccountImport } from './routes/_authenticated/account'; +import { Route as LogoutRouteImport } from './routes/logout'; +import { Route as AuthenticatedRouteImport } from './routes/_authenticated'; +import { Route as IndexRouteImport } from './routes/index'; +import { Route as AuthenticatedAccountRouteImport } from './routes/_authenticated/account'; // Create/Update Routes -const LogoutRoute = LogoutImport.update({ +const LogoutRoute = LogoutRouteImport.update({ id: '/logout', path: '/logout', getParentRoute: () => rootRoute, } as any); -const AuthenticatedRoute = AuthenticatedImport.update({ +const AuthenticatedRoute = AuthenticatedRouteImport.update({ id: '/_authenticated', getParentRoute: () => rootRoute, } as any); -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any); -const AuthenticatedAccountRoute = AuthenticatedAccountImport.update({ +const AuthenticatedAccountRoute = AuthenticatedAccountRouteImport.update({ id: '/account', path: '/account', getParentRoute: () => AuthenticatedRoute, @@ -49,33 +51,72 @@ declare module '@tanstack/react-router' { id: '/'; path: '/'; fullPath: '/'; - preLoaderRoute: typeof IndexImport; + preLoaderRoute: typeof IndexRouteImport; parentRoute: typeof rootRoute; }; '/_authenticated': { id: '/_authenticated'; path: ''; fullPath: ''; - preLoaderRoute: typeof AuthenticatedImport; + preLoaderRoute: typeof AuthenticatedRouteImport; parentRoute: typeof rootRoute; }; '/logout': { id: '/logout'; path: '/logout'; fullPath: '/logout'; - preLoaderRoute: typeof LogoutImport; + preLoaderRoute: typeof LogoutRouteImport; parentRoute: typeof rootRoute; }; '/_authenticated/account': { id: '/_authenticated/account'; path: '/account'; fullPath: '/account'; - preLoaderRoute: typeof AuthenticatedAccountImport; - parentRoute: typeof AuthenticatedImport; + preLoaderRoute: typeof AuthenticatedAccountRouteImport; + parentRoute: typeof AuthenticatedRouteImport; }; } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + >; +} +declare module './routes/_authenticated' { + const createFileRoute: CreateFileRoute< + '/_authenticated', + FileRoutesByPath['/_authenticated']['parentRoute'], + FileRoutesByPath['/_authenticated']['id'], + FileRoutesByPath['/_authenticated']['path'], + FileRoutesByPath['/_authenticated']['fullPath'] + >; +} +declare module './routes/logout' { + const createFileRoute: CreateFileRoute< + '/logout', + FileRoutesByPath['/logout']['parentRoute'], + FileRoutesByPath['/logout']['id'], + FileRoutesByPath['/logout']['path'], + FileRoutesByPath['/logout']['fullPath'] + >; +} +declare module './routes/_authenticated/account' { + const createFileRoute: CreateFileRoute< + '/_authenticated/account', + FileRoutesByPath['/_authenticated/account']['parentRoute'], + FileRoutesByPath['/_authenticated/account']['id'], + FileRoutesByPath['/_authenticated/account']['path'], + FileRoutesByPath['/_authenticated/account']['fullPath'] + >; +} + // Create and export the route tree interface AuthenticatedRouteChildren { diff --git a/examples/react/start-workos/src/routes/_authenticated.tsx b/examples/react/start-workos/src/routes/_authenticated.tsx index 2533014a27..a44930eaa1 100644 --- a/examples/react/start-workos/src/routes/_authenticated.tsx +++ b/examples/react/start-workos/src/routes/_authenticated.tsx @@ -1,7 +1,7 @@ -import { createFileRoute, redirect } from '@tanstack/react-router'; +import { redirect } from '@tanstack/react-router'; import { getSignInUrl } from '../authkit/serverFunctions'; -export const Route = createFileRoute('/_authenticated')({ +export const Route = createFileRoute({ beforeLoad: async ({ context, location }) => { if (!context.user) { const path = location.pathname; diff --git a/examples/react/start-workos/src/routes/_authenticated/account.tsx b/examples/react/start-workos/src/routes/_authenticated/account.tsx index b5a8a660a1..7776e66e53 100644 --- a/examples/react/start-workos/src/routes/_authenticated/account.tsx +++ b/examples/react/start-workos/src/routes/_authenticated/account.tsx @@ -1,8 +1,8 @@ import { Box, Flex, Heading, Text, TextField } from '@radix-ui/themes'; -import { createFileRoute } from '@tanstack/react-router'; +import {} from '@tanstack/react-router'; import { getAuth } from '../../authkit/serverFunctions'; -export const Route = createFileRoute('/_authenticated/account')({ +export const Route = createFileRoute({ component: RouteComponent, loader: async ({ context }) => { const { user } = context; diff --git a/examples/react/start-workos/src/routes/index.tsx b/examples/react/start-workos/src/routes/index.tsx index 6f2c64415b..f6ecd09981 100644 --- a/examples/react/start-workos/src/routes/index.tsx +++ b/examples/react/start-workos/src/routes/index.tsx @@ -1,9 +1,9 @@ import { Button, Flex, Heading, Text } from '@radix-ui/themes'; -import { Link, createFileRoute } from '@tanstack/react-router'; +import { Link } from '@tanstack/react-router'; import { getSignInUrl } from '../authkit/serverFunctions'; import SignInButton from '../components/sign-in-button'; -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, loader: async ({ context }) => { const { user } = context; diff --git a/examples/react/start-workos/src/routes/logout.tsx b/examples/react/start-workos/src/routes/logout.tsx index 41e8bc0b88..dc61380a45 100644 --- a/examples/react/start-workos/src/routes/logout.tsx +++ b/examples/react/start-workos/src/routes/logout.tsx @@ -1,7 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router'; import { signOut } from '../authkit/serverFunctions'; -export const Route = createFileRoute('/logout')({ +export const Route = createFileRoute({ preload: false, loader: () => signOut(), }); diff --git a/examples/react/start-workos/src/ssr.tsx b/examples/react/start-workos/src/ssr.tsx deleted file mode 100644 index 32848ff35a..0000000000 --- a/examples/react/start-workos/src/ssr.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { createStartHandler, defaultStreamHandler } from '@tanstack/react-start/server'; -import { getRouterManifest } from '@tanstack/react-start/router-manifest'; - -import { createRouter } from './router'; - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler); diff --git a/examples/react/start-workos/src/tanstack-start.d.ts b/examples/react/start-workos/src/tanstack-start.d.ts new file mode 100644 index 0000000000..833d577af8 --- /dev/null +++ b/examples/react/start-workos/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen'; diff --git a/examples/react/start-workos/vite.config.ts b/examples/react/start-workos/vite.config.ts new file mode 100644 index 0000000000..cd888de96e --- /dev/null +++ b/examples/react/start-workos/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite'; +import tsConfigPaths from 'vite-tsconfig-paths'; +import { tanstackStart } from '@tanstack/react-start/plugin/vite'; + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + ], +}); diff --git a/examples/react/view-transitions/package.json b/examples/react/view-transitions/package.json index 3b99a514bc..b1afc49790 100644 --- a/examples/react/view-transitions/package.json +++ b/examples/react/view-transitions/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", @@ -25,6 +25,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/view-transitions/src/routeTree.gen.ts b/examples/react/view-transitions/src/routeTree.gen.ts index 7dc7f740d9..73f3d006a7 100644 --- a/examples/react/view-transitions/src/routeTree.gen.ts +++ b/examples/react/view-transitions/src/routeTree.gen.ts @@ -11,46 +11,46 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as HowItWorksImport } from './routes/how-it-works' -import { Route as ExploreImport } from './routes/explore' -import { Route as PostsRouteImport } from './routes/posts.route' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as PostsPostIdImport } from './routes/posts.$postId' +import { Route as HowItWorksRouteImport } from './routes/how-it-works' +import { Route as ExploreRouteImport } from './routes/explore' +import { Route as PostsRouteRouteImport } from './routes/posts.route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' // Create/Update Routes -const HowItWorksRoute = HowItWorksImport.update({ +const HowItWorksRoute = HowItWorksRouteImport.update({ id: '/how-it-works', path: '/how-it-works', getParentRoute: () => rootRoute, } as any) -const ExploreRoute = ExploreImport.update({ +const ExploreRoute = ExploreRouteImport.update({ id: '/explore', path: '/explore', getParentRoute: () => rootRoute, } as any) -const PostsRouteRoute = PostsRouteImport.update({ +const PostsRouteRoute = PostsRouteRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRouteRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRouteRoute, @@ -64,43 +64,43 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsRouteRouteImport parentRoute: typeof rootRoute } '/explore': { id: '/explore' path: '/explore' fullPath: '/explore' - preLoaderRoute: typeof ExploreImport + preLoaderRoute: typeof ExploreRouteImport parentRoute: typeof rootRoute } '/how-it-works': { id: '/how-it-works' path: '/how-it-works' fullPath: '/how-it-works' - preLoaderRoute: typeof HowItWorksImport + preLoaderRoute: typeof HowItWorksRouteImport parentRoute: typeof rootRoute } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteRouteImport } } } diff --git a/examples/react/view-transitions/src/routes/explore.tsx b/examples/react/view-transitions/src/routes/explore.tsx index b70a6f3bd5..1bb60ed1fc 100644 --- a/examples/react/view-transitions/src/routes/explore.tsx +++ b/examples/react/view-transitions/src/routes/explore.tsx @@ -1,4 +1,5 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' export const Route = createFileRoute('/explore')({ component: RouteComponent, diff --git a/examples/react/view-transitions/src/routes/how-it-works.tsx b/examples/react/view-transitions/src/routes/how-it-works.tsx index ab4dd4c714..3ae9a88d52 100644 --- a/examples/react/view-transitions/src/routes/how-it-works.tsx +++ b/examples/react/view-transitions/src/routes/how-it-works.tsx @@ -1,4 +1,5 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' export const Route = createFileRoute('/how-it-works')({ component: RouteComponent, diff --git a/examples/react/view-transitions/src/routes/index.tsx b/examples/react/view-transitions/src/routes/index.tsx index 132ba18dbb..19f597dc7b 100644 --- a/examples/react/view-transitions/src/routes/index.tsx +++ b/examples/react/view-transitions/src/routes/index.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' export const Route = createFileRoute('/')({ component: Home, diff --git a/examples/react/view-transitions/src/routes/posts.$postId.tsx b/examples/react/view-transitions/src/routes/posts.$postId.tsx index cded91ef96..956ca50ecd 100644 --- a/examples/react/view-transitions/src/routes/posts.$postId.tsx +++ b/examples/react/view-transitions/src/routes/posts.$postId.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import { ErrorComponent } from '@tanstack/react-router' import { fetchPost } from '../posts' import type { ErrorComponentProps } from '@tanstack/react-router' diff --git a/examples/react/view-transitions/src/routes/posts.index.tsx b/examples/react/view-transitions/src/routes/posts.index.tsx index 056433ca0a..c6b65f1892 100644 --- a/examples/react/view-transitions/src/routes/posts.index.tsx +++ b/examples/react/view-transitions/src/routes/posts.index.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' +import * as React from 'react' export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, diff --git a/examples/react/view-transitions/src/routes/posts.route.tsx b/examples/react/view-transitions/src/routes/posts.route.tsx index c63dc78ff2..88296c3c54 100644 --- a/examples/react/view-transitions/src/routes/posts.route.tsx +++ b/examples/react/view-transitions/src/routes/posts.route.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../posts' export const Route = createFileRoute('/posts')({ diff --git a/examples/react/view-transitions/vite.config.js b/examples/react/view-transitions/vite.config.js index f22a7fa76f..47e327b746 100644 --- a/examples/react/view-transitions/vite.config.js +++ b/examples/react/view-transitions/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'react', autoCodeSplitting: true, }), diff --git a/examples/react/with-framer-motion/package.json b/examples/react/with-framer-motion/package.json index 3bdb7d217c..1d4c3f179c 100644 --- a/examples/react/with-framer-motion/package.json +++ b/examples/react/with-framer-motion/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", "framer-motion": "^11.18.2", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -25,6 +25,6 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/react/with-trpc-react-query/.gitignore b/examples/react/with-trpc-react-query/.gitignore index be342025da..ca63f49885 100644 --- a/examples/react/with-trpc-react-query/.gitignore +++ b/examples/react/with-trpc-react-query/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/with-trpc-react-query/app.config.js b/examples/react/with-trpc-react-query/app.config.js index ef4eb87c7b..394f58c645 100644 --- a/examples/react/with-trpc-react-query/app.config.js +++ b/examples/react/with-trpc-react-query/app.config.js @@ -1,8 +1,10 @@ -import { createApp } from 'vinxi' +import { defineConfig } from 'vite' import reactRefresh from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' -export default createApp({ +// TODO: Need to migrate this to vite and the new TanStack Start plugin + +export default defineConfig({ server: { preset: 'node-server', // change to 'netlify' or 'bun' or anyof the supported presets for nitro (nitro.unjs.io) experimental: { @@ -29,7 +31,7 @@ export default createApp({ handler: './index.html', target: 'browser', plugins: () => [ - TanStackRouterVite({ + tanstackRouter({ target: 'react', autoCodeSplitting: true, routesDirectory: './src/routes', diff --git a/examples/react/with-trpc-react-query/package.json b/examples/react/with-trpc-react-query/package.json index bc9b26032a..d12f3dae63 100644 --- a/examples/react/with-trpc-react-query/package.json +++ b/examples/react/with-trpc-react-query/package.json @@ -3,17 +3,17 @@ "private": true, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "@trpc/client": "11.0.0-rc.772", "@trpc/server": "11.0.0-rc.772", "@trpc/tanstack-react-query": "11.0.0-rc.772", @@ -23,7 +23,6 @@ "postcss": "^8.5.1", "autoprefixer": "^10.4.20", "tailwindcss": "^3.4.17", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/examples/react/with-trpc-react-query/src/main.tsx b/examples/react/with-trpc-react-query/src/main.tsx index 4cc69baaac..bda5f47256 100644 --- a/examples/react/with-trpc-react-query/src/main.tsx +++ b/examples/react/with-trpc-react-query/src/main.tsx @@ -1,5 +1,3 @@ -/// - import React from 'react' import ReactDOM from 'react-dom/client' import { RouterProvider } from '@tanstack/react-router' diff --git a/examples/react/with-trpc-react-query/src/router.tsx b/examples/react/with-trpc-react-query/src/router.tsx index 1dfd9c4131..0d9dd5c4e4 100644 --- a/examples/react/with-trpc-react-query/src/router.tsx +++ b/examples/react/with-trpc-react-query/src/router.tsx @@ -15,7 +15,7 @@ export const trpc = createTRPCOptionsProxy({ client: createTRPCClient({ links: [ httpBatchLink({ - // since we are using Vinxi, the server is running on the same port, + // since we are using Vite, the server is running on the same port, // this means in dev the url is `http://localhost:3000/trpc` // and since its from the same origin, we don't need to explicitly set the full URL url: '/trpc', diff --git a/examples/react/with-trpc/.gitignore b/examples/react/with-trpc/.gitignore index be342025da..ca63f49885 100644 --- a/examples/react/with-trpc/.gitignore +++ b/examples/react/with-trpc/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/with-trpc/app.config.js b/examples/react/with-trpc/app.config.js index ef4eb87c7b..394f58c645 100644 --- a/examples/react/with-trpc/app.config.js +++ b/examples/react/with-trpc/app.config.js @@ -1,8 +1,10 @@ -import { createApp } from 'vinxi' +import { defineConfig } from 'vite' import reactRefresh from '@vitejs/plugin-react' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' -export default createApp({ +// TODO: Need to migrate this to vite and the new TanStack Start plugin + +export default defineConfig({ server: { preset: 'node-server', // change to 'netlify' or 'bun' or anyof the supported presets for nitro (nitro.unjs.io) experimental: { @@ -29,7 +31,7 @@ export default createApp({ handler: './index.html', target: 'browser', plugins: () => [ - TanStackRouterVite({ + tanstackRouter({ target: 'react', autoCodeSplitting: true, routesDirectory: './src/routes', diff --git a/examples/react/with-trpc/package.json b/examples/react/with-trpc/package.json index 2414353240..4aa7d66c3a 100644 --- a/examples/react/with-trpc/package.json +++ b/examples/react/with-trpc/package.json @@ -3,15 +3,15 @@ "private": true, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { - "@tanstack/react-router": "^1.120.3", - "@tanstack/react-router-devtools": "^1.120.3", - "@tanstack/router-plugin": "^1.120.3", - "@tanstack/react-start": "^1.120.3", + "@tanstack/react-router": "^1.121.0-alpha.11", + "@tanstack/react-router-devtools": "^1.121.0-alpha.11", + "@tanstack/router-plugin": "^1.121.0-alpha.11", + "@tanstack/react-start": "^1.121.0-alpha.11", "@trpc/client": "11.0.0-rc.772", "@trpc/server": "11.0.0-rc.772", "react": "^19.0.0", @@ -20,7 +20,6 @@ "postcss": "^8.5.1", "autoprefixer": "^10.4.20", "tailwindcss": "^3.4.17", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/examples/react/with-trpc/src/main.tsx b/examples/react/with-trpc/src/main.tsx index 3cff783e4b..ff5d7de693 100644 --- a/examples/react/with-trpc/src/main.tsx +++ b/examples/react/with-trpc/src/main.tsx @@ -1,5 +1,3 @@ -/// - import React from 'react' import ReactDOM from 'react-dom/client' import { RouterProvider, createRouter } from '@tanstack/react-router' diff --git a/examples/react/with-trpc/src/trpc.ts b/examples/react/with-trpc/src/trpc.ts index 243e4a6f5e..2320dcdfb6 100644 --- a/examples/react/with-trpc/src/trpc.ts +++ b/examples/react/with-trpc/src/trpc.ts @@ -4,7 +4,7 @@ import type { AppRouter } from '../trpc-server.handler' export const trpc = createTRPCClient({ links: [ httpBatchLink({ - // since we are using Vinxi, the server is running on the same port, + // since we are using Vite, the server is running on the same port, // this means in dev the url is `http://localhost:3000/trpc` // and since its from the same origin, we don't need to explicitly set the full URL url: '/trpc', diff --git a/examples/solid/basic-devtools-panel/package.json b/examples/solid/basic-devtools-panel/package.json index ecc30cd748..64117109b7 100644 --- a/examples/solid/basic-devtools-panel/package.json +++ b/examples/solid/basic-devtools-panel/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/solid-router": "^1.120.3", - "@tanstack/solid-router-devtools": "^1.120.3", + "@tanstack/solid-router": "^1.121.0-alpha.11", + "@tanstack/solid-router-devtools": "^1.121.0-alpha.11", "solid-js": "^1.9.5", "redaxios": "^0.5.1", "postcss": "^8.5.1", @@ -20,6 +20,6 @@ "devDependencies": { "vite-plugin-solid": "^2.11.6", "typescript": "^5.7.2", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/examples/solid/basic-file-based/package.json b/examples/solid/basic-file-based/package.json index 2c97989801..8e8fdb676a 100644 --- a/examples/solid/basic-file-based/package.json +++ b/examples/solid/basic-file-based/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/solid-router": "^1.120.3", - "@tanstack/solid-router-devtools": "^1.120.3", + "@tanstack/solid-router": "^1.121.0-alpha.11", + "@tanstack/solid-router-devtools": "^1.121.0-alpha.11", "autoprefixer": "^10.4.20", "postcss": "^8.5.1", "redaxios": "^0.5.1", @@ -19,9 +19,9 @@ "zod": "^3.24.2" }, "devDependencies": { - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-solid": "^2.11.2" } } diff --git a/examples/solid/basic-file-based/src/routeTree.gen.ts b/examples/solid/basic-file-based/src/routeTree.gen.ts index 1f53fb23d7..13710a3f4a 100644 --- a/examples/solid/basic-file-based/src/routeTree.gen.ts +++ b/examples/solid/basic-file-based/src/routeTree.gen.ts @@ -11,62 +11,61 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PostsImport } from './routes/posts' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as PathlessLayoutNestedLayoutImport } from './routes/_pathlessLayout/_nested-layout' -import { Route as PathlessLayoutNestedLayoutRouteBImport } from './routes/_pathlessLayout/_nested-layout/route-b' -import { Route as PathlessLayoutNestedLayoutRouteAImport } from './routes/_pathlessLayout/_nested-layout/route-a' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' +import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' +import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' // Create/Update Routes -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const PathlessLayoutNestedLayoutRoute = PathlessLayoutNestedLayoutImport.update( - { +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ id: '/_nested-layout', getParentRoute: () => PathlessLayoutRoute, - } as any, -) + } as any) const PathlessLayoutNestedLayoutRouteBRoute = - PathlessLayoutNestedLayoutRouteBImport.update({ + PathlessLayoutNestedLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutNestedLayoutRoute, } as any) const PathlessLayoutNestedLayoutRouteARoute = - PathlessLayoutNestedLayoutRouteAImport.update({ + PathlessLayoutNestedLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutNestedLayoutRoute, @@ -80,57 +79,57 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout/_nested-layout': { id: '/_pathlessLayout/_nested-layout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutNestedLayoutImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/_pathlessLayout/_nested-layout/route-a': { id: '/_pathlessLayout/_nested-layout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteAImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/_pathlessLayout/_nested-layout/route-b': { id: '/_pathlessLayout/_nested-layout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } } } diff --git a/examples/solid/basic-file-based/src/routes/_pathlessLayout.tsx b/examples/solid/basic-file-based/src/routes/_pathlessLayout.tsx index af197bc038..227a421bfe 100644 --- a/examples/solid/basic-file-based/src/routes/_pathlessLayout.tsx +++ b/examples/solid/basic-file-based/src/routes/_pathlessLayout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/_pathlessLayout')({ component: LayoutComponent, diff --git a/examples/solid/basic-file-based/src/routes/_pathlessLayout/_nested-layout.tsx b/examples/solid/basic-file-based/src/routes/_pathlessLayout/_nested-layout.tsx index f54a42abb4..bea54d9af4 100644 --- a/examples/solid/basic-file-based/src/routes/_pathlessLayout/_nested-layout.tsx +++ b/examples/solid/basic-file-based/src/routes/_pathlessLayout/_nested-layout.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({ component: LayoutComponent, diff --git a/examples/solid/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/examples/solid/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx index a22902a271..2484c0be81 100644 --- a/examples/solid/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +++ b/examples/solid/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')( { component: LayoutAComponent, diff --git a/examples/solid/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/examples/solid/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx index 36231d2153..14549ab011 100644 --- a/examples/solid/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +++ b/examples/solid/basic-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')( { component: LayoutBComponent, diff --git a/examples/solid/basic-file-based/src/routes/index.tsx b/examples/solid/basic-file-based/src/routes/index.tsx index bdfb4c7676..3f905db60c 100644 --- a/examples/solid/basic-file-based/src/routes/index.tsx +++ b/examples/solid/basic-file-based/src/routes/index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/')({ component: Home, }) diff --git a/examples/solid/basic-file-based/src/routes/posts.index.tsx b/examples/solid/basic-file-based/src/routes/posts.index.tsx index 33d0386c19..812b581e0a 100644 --- a/examples/solid/basic-file-based/src/routes/posts.index.tsx +++ b/examples/solid/basic-file-based/src/routes/posts.index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, }) diff --git a/examples/solid/basic-file-based/src/routes/posts.tsx b/examples/solid/basic-file-based/src/routes/posts.tsx index 11a999f50a..86fb7a1841 100644 --- a/examples/solid/basic-file-based/src/routes/posts.tsx +++ b/examples/solid/basic-file-based/src/routes/posts.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import { fetchPosts } from '../posts' export const Route = createFileRoute('/posts')({ diff --git a/examples/solid/basic-file-based/vite.config.js b/examples/solid/basic-file-based/vite.config.js index 2b2f26819d..74e9ca3db3 100644 --- a/examples/solid/basic-file-based/vite.config.js +++ b/examples/solid/basic-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import solid from 'vite-plugin-solid' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'solid', autoCodeSplitting: true, }), diff --git a/examples/solid/basic-non-nested-devtools/package.json b/examples/solid/basic-non-nested-devtools/package.json index 9f0ae1d786..d4437db5db 100644 --- a/examples/solid/basic-non-nested-devtools/package.json +++ b/examples/solid/basic-non-nested-devtools/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/solid-router": "^1.120.3", - "@tanstack/solid-router-devtools": "^1.120.3", + "@tanstack/solid-router": "^1.121.0-alpha.11", + "@tanstack/solid-router-devtools": "^1.121.0-alpha.11", "redaxios": "^0.5.1", "postcss": "^8.5.1", "solid-js": "^1.9.5", @@ -21,7 +21,7 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-solid": "^2.11.2" } } diff --git a/examples/solid/basic-solid-query-file-based/package.json b/examples/solid/basic-solid-query-file-based/package.json index f074c64838..0c88c30965 100644 --- a/examples/solid/basic-solid-query-file-based/package.json +++ b/examples/solid/basic-solid-query-file-based/package.json @@ -12,8 +12,8 @@ "dependencies": { "@tanstack/solid-query": "^5.71.9", "@tanstack/solid-query-devtools": "^5.71.9", - "@tanstack/solid-router": "^1.120.3", - "@tanstack/solid-router-devtools": "^1.120.3", + "@tanstack/solid-router": "^1.121.0-alpha.11", + "@tanstack/solid-router-devtools": "^1.121.0-alpha.11", "solid-js": "^1.9.5", "redaxios": "^0.5.1", "postcss": "^8.5.1", @@ -22,9 +22,9 @@ "zod": "^3.24.2" }, "devDependencies": { - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-solid": "^2.11.2" } } diff --git a/examples/solid/basic-solid-query-file-based/src/routeTree.gen.ts b/examples/solid/basic-solid-query-file-based/src/routeTree.gen.ts index 1f53fb23d7..13710a3f4a 100644 --- a/examples/solid/basic-solid-query-file-based/src/routeTree.gen.ts +++ b/examples/solid/basic-solid-query-file-based/src/routeTree.gen.ts @@ -11,62 +11,61 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PostsImport } from './routes/posts' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as PathlessLayoutNestedLayoutImport } from './routes/_pathlessLayout/_nested-layout' -import { Route as PathlessLayoutNestedLayoutRouteBImport } from './routes/_pathlessLayout/_nested-layout/route-b' -import { Route as PathlessLayoutNestedLayoutRouteAImport } from './routes/_pathlessLayout/_nested-layout/route-a' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' +import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' +import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' // Create/Update Routes -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const PathlessLayoutNestedLayoutRoute = PathlessLayoutNestedLayoutImport.update( - { +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ id: '/_nested-layout', getParentRoute: () => PathlessLayoutRoute, - } as any, -) + } as any) const PathlessLayoutNestedLayoutRouteBRoute = - PathlessLayoutNestedLayoutRouteBImport.update({ + PathlessLayoutNestedLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutNestedLayoutRoute, } as any) const PathlessLayoutNestedLayoutRouteARoute = - PathlessLayoutNestedLayoutRouteAImport.update({ + PathlessLayoutNestedLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutNestedLayoutRoute, @@ -80,57 +79,57 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout/_nested-layout': { id: '/_pathlessLayout/_nested-layout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutNestedLayoutImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/_pathlessLayout/_nested-layout/route-a': { id: '/_pathlessLayout/_nested-layout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteAImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/_pathlessLayout/_nested-layout/route-b': { id: '/_pathlessLayout/_nested-layout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } } } diff --git a/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout.tsx b/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout.tsx index b52af5379b..7cdec28d8d 100644 --- a/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout.tsx +++ b/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/_pathlessLayout')({ component: LayoutComponent, diff --git a/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout/_nested-layout.tsx b/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout/_nested-layout.tsx index f9a1b90b23..04a1d07c42 100644 --- a/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout/_nested-layout.tsx +++ b/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout/_nested-layout.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({ component: PathlessLayoutComponent, diff --git a/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx index a22902a271..2484c0be81 100644 --- a/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +++ b/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')( { component: LayoutAComponent, diff --git a/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx index 36231d2153..14549ab011 100644 --- a/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +++ b/examples/solid/basic-solid-query-file-based/src/routes/_pathlessLayout/_nested-layout/route-b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')( { component: LayoutBComponent, diff --git a/examples/solid/basic-solid-query-file-based/src/routes/index.tsx b/examples/solid/basic-solid-query-file-based/src/routes/index.tsx index bdfb4c7676..3f905db60c 100644 --- a/examples/solid/basic-solid-query-file-based/src/routes/index.tsx +++ b/examples/solid/basic-solid-query-file-based/src/routes/index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/')({ component: Home, }) diff --git a/examples/solid/basic-solid-query-file-based/src/routes/posts.$postId.tsx b/examples/solid/basic-solid-query-file-based/src/routes/posts.$postId.tsx index 619428c4b5..f771b7be7e 100644 --- a/examples/solid/basic-solid-query-file-based/src/routes/posts.$postId.tsx +++ b/examples/solid/basic-solid-query-file-based/src/routes/posts.$postId.tsx @@ -1,8 +1,5 @@ -import { - ErrorComponent, - createFileRoute, - useRouter, -} from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { ErrorComponent, useRouter } from '@tanstack/solid-router' import { useQuery } from '@tanstack/solid-query' import { createEffect, createMemo } from 'solid-js' import { PostNotFoundError } from '../posts' diff --git a/examples/solid/basic-solid-query-file-based/src/routes/posts.index.tsx b/examples/solid/basic-solid-query-file-based/src/routes/posts.index.tsx index 33d0386c19..812b581e0a 100644 --- a/examples/solid/basic-solid-query-file-based/src/routes/posts.index.tsx +++ b/examples/solid/basic-solid-query-file-based/src/routes/posts.index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/posts/')({ component: PostsIndexComponent, }) diff --git a/examples/solid/basic-solid-query-file-based/src/routes/posts.tsx b/examples/solid/basic-solid-query-file-based/src/routes/posts.tsx index b0af26be32..eb3b3c9072 100644 --- a/examples/solid/basic-solid-query-file-based/src/routes/posts.tsx +++ b/examples/solid/basic-solid-query-file-based/src/routes/posts.tsx @@ -1,4 +1,5 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import { useQuery } from '@tanstack/solid-query' import { postsQueryOptions } from '../postsQueryOptions' import { createMemo } from 'solid-js' diff --git a/examples/solid/basic-solid-query-file-based/vite.config.js b/examples/solid/basic-solid-query-file-based/vite.config.js index 4af89e7520..1660a56c17 100644 --- a/examples/solid/basic-solid-query-file-based/vite.config.js +++ b/examples/solid/basic-solid-query-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import solid from 'vite-plugin-solid' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'solid', autoCodeSplitting: true }), + tanstackRouter({ target: 'solid', autoCodeSplitting: true }), solid(), ], }) diff --git a/examples/solid/basic-solid-query/package.json b/examples/solid/basic-solid-query/package.json index 72aa31853b..850740c6cd 100644 --- a/examples/solid/basic-solid-query/package.json +++ b/examples/solid/basic-solid-query/package.json @@ -11,8 +11,8 @@ "dependencies": { "@tanstack/solid-query": "^5.71.9", "@tanstack/solid-query-devtools": "^5.71.9", - "@tanstack/solid-router": "^1.120.3", - "@tanstack/solid-router-devtools": "^1.120.3", + "@tanstack/solid-router": "^1.121.0-alpha.11", + "@tanstack/solid-router-devtools": "^1.121.0-alpha.11", "solid-js": "^1.9.5", "redaxios": "^0.5.1", "postcss": "^8.5.1", @@ -20,9 +20,9 @@ "tailwindcss": "^3.4.17" }, "devDependencies": { - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-solid": "^2.11.2" } } diff --git a/examples/solid/basic/package.json b/examples/solid/basic/package.json index c602e83393..9ea2c27c89 100644 --- a/examples/solid/basic/package.json +++ b/examples/solid/basic/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/solid-router": "^1.120.3", - "@tanstack/solid-router-devtools": "^1.120.3", + "@tanstack/solid-router": "^1.121.0-alpha.11", + "@tanstack/solid-router-devtools": "^1.121.0-alpha.11", "redaxios": "^0.5.1", "postcss": "^8.5.1", "solid-js": "^1.9.5", @@ -21,7 +21,7 @@ "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-solid": "^2.11.2" } } diff --git a/examples/solid/kitchen-sink-file-based/package.json b/examples/solid/kitchen-sink-file-based/package.json index 190dd6540c..6463e257dc 100644 --- a/examples/solid/kitchen-sink-file-based/package.json +++ b/examples/solid/kitchen-sink-file-based/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/solid-router": "^1.120.3", - "@tanstack/solid-router-devtools": "^1.120.3", + "@tanstack/solid-router": "^1.121.0-alpha.11", + "@tanstack/solid-router-devtools": "^1.121.0-alpha.11", "immer": "^10.1.1", "solid-js": "^1.9.5", "redaxios": "^0.5.1", @@ -20,9 +20,9 @@ "zod": "^3.24.2" }, "devDependencies": { - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-solid": "^2.11.2" } } diff --git a/examples/solid/kitchen-sink-file-based/src/routeTree.gen.ts b/examples/solid/kitchen-sink-file-based/src/routeTree.gen.ts index 0deb820043..f7af0fbf39 100644 --- a/examples/solid/kitchen-sink-file-based/src/routeTree.gen.ts +++ b/examples/solid/kitchen-sink-file-based/src/routeTree.gen.ts @@ -11,128 +11,127 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as LoginImport } from './routes/login' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as AuthImport } from './routes/_auth' -import { Route as DashboardRouteImport } from './routes/dashboard.route' -import { Route as IndexImport } from './routes/index' -import { Route as ExpensiveIndexImport } from './routes/expensive/index' -import { Route as DashboardIndexImport } from './routes/dashboard.index' -import { Route as PathlessLayoutRouteBImport } from './routes/_pathlessLayout.route-b' -import { Route as PathlessLayoutRouteAImport } from './routes/_pathlessLayout.route-a' -import { Route as AuthProfileImport } from './routes/_auth.profile' -import { Route as thisFolderIsNotInTheUrlRouteGroupImport } from './routes/(this-folder-is-not-in-the-url)/route-group' -import { Route as DashboardUsersRouteImport } from './routes/dashboard.users.route' -import { Route as DashboardInvoicesRouteImport } from './routes/dashboard.invoices.route' -import { Route as DashboardUsersIndexImport } from './routes/dashboard.users.index' -import { Route as DashboardInvoicesIndexImport } from './routes/dashboard.invoices.index' -import { Route as DashboardUsersUserImport } from './routes/dashboard.users.user' -import { Route as DashboardInvoicesInvoiceIdImport } from './routes/dashboard.invoices.$invoiceId' +import { Route as LoginRouteImport } from './routes/login' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as AuthRouteImport } from './routes/_auth' +import { Route as DashboardRouteRouteImport } from './routes/dashboard.route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as ExpensiveIndexRouteImport } from './routes/expensive/index' +import { Route as DashboardIndexRouteImport } from './routes/dashboard.index' +import { Route as PathlessLayoutRouteBRouteImport } from './routes/_pathlessLayout.route-b' +import { Route as PathlessLayoutRouteARouteImport } from './routes/_pathlessLayout.route-a' +import { Route as AuthProfileRouteImport } from './routes/_auth.profile' +import { Route as thisFolderIsNotInTheUrlRouteGroupRouteImport } from './routes/(this-folder-is-not-in-the-url)/route-group' +import { Route as DashboardUsersRouteRouteImport } from './routes/dashboard.users.route' +import { Route as DashboardInvoicesRouteRouteImport } from './routes/dashboard.invoices.route' +import { Route as DashboardUsersIndexRouteImport } from './routes/dashboard.users.index' +import { Route as DashboardInvoicesIndexRouteImport } from './routes/dashboard.invoices.index' +import { Route as DashboardUsersUserRouteImport } from './routes/dashboard.users.user' +import { Route as DashboardInvoicesInvoiceIdRouteImport } from './routes/dashboard.invoices.$invoiceId' // Create/Update Routes -const LoginRoute = LoginImport.update({ +const LoginRoute = LoginRouteImport.update({ id: '/login', path: '/login', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const AuthRoute = AuthImport.update({ +const AuthRoute = AuthRouteImport.update({ id: '/_auth', getParentRoute: () => rootRoute, } as any) -const DashboardRouteRoute = DashboardRouteImport.update({ +const DashboardRouteRoute = DashboardRouteRouteImport.update({ id: '/dashboard', path: '/dashboard', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const ExpensiveIndexRoute = ExpensiveIndexImport.update({ +const ExpensiveIndexRoute = ExpensiveIndexRouteImport.update({ id: '/expensive/', path: '/expensive/', getParentRoute: () => rootRoute, } as any) -const DashboardIndexRoute = DashboardIndexImport.update({ +const DashboardIndexRoute = DashboardIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => DashboardRouteRoute, } as any) -const PathlessLayoutRouteBRoute = PathlessLayoutRouteBImport.update({ +const PathlessLayoutRouteBRoute = PathlessLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutRoute, } as any) -const PathlessLayoutRouteARoute = PathlessLayoutRouteAImport.update({ +const PathlessLayoutRouteARoute = PathlessLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutRoute, } as any) -const AuthProfileRoute = AuthProfileImport.update({ +const AuthProfileRoute = AuthProfileRouteImport.update({ id: '/profile', path: '/profile', getParentRoute: () => AuthRoute, } as any) const thisFolderIsNotInTheUrlRouteGroupRoute = - thisFolderIsNotInTheUrlRouteGroupImport.update({ + thisFolderIsNotInTheUrlRouteGroupRouteImport.update({ id: '/(this-folder-is-not-in-the-url)/route-group', path: '/route-group', getParentRoute: () => rootRoute, } as any) -const DashboardUsersRouteRoute = DashboardUsersRouteImport.update({ +const DashboardUsersRouteRoute = DashboardUsersRouteRouteImport.update({ id: '/users', path: '/users', getParentRoute: () => DashboardRouteRoute, } as any) -const DashboardInvoicesRouteRoute = DashboardInvoicesRouteImport.update({ +const DashboardInvoicesRouteRoute = DashboardInvoicesRouteRouteImport.update({ id: '/invoices', path: '/invoices', getParentRoute: () => DashboardRouteRoute, } as any) -const DashboardUsersIndexRoute = DashboardUsersIndexImport.update({ +const DashboardUsersIndexRoute = DashboardUsersIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => DashboardUsersRouteRoute, } as any) -const DashboardInvoicesIndexRoute = DashboardInvoicesIndexImport.update({ +const DashboardInvoicesIndexRoute = DashboardInvoicesIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => DashboardInvoicesRouteRoute, } as any) -const DashboardUsersUserRoute = DashboardUsersUserImport.update({ +const DashboardUsersUserRoute = DashboardUsersUserRouteImport.update({ id: '/user', path: '/user', getParentRoute: () => DashboardUsersRouteRoute, } as any) -const DashboardInvoicesInvoiceIdRoute = DashboardInvoicesInvoiceIdImport.update( - { +const DashboardInvoicesInvoiceIdRoute = + DashboardInvoicesInvoiceIdRouteImport.update({ id: '/$invoiceId', path: '/$invoiceId', getParentRoute: () => DashboardInvoicesRouteRoute, - } as any, -) + } as any) // Populate the FileRoutesByPath interface @@ -142,120 +141,120 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/dashboard': { id: '/dashboard' path: '/dashboard' fullPath: '/dashboard' - preLoaderRoute: typeof DashboardRouteImport + preLoaderRoute: typeof DashboardRouteRouteImport parentRoute: typeof rootRoute } '/_auth': { id: '/_auth' path: '' fullPath: '' - preLoaderRoute: typeof AuthImport + preLoaderRoute: typeof AuthRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/login': { id: '/login' path: '/login' fullPath: '/login' - preLoaderRoute: typeof LoginImport + preLoaderRoute: typeof LoginRouteImport parentRoute: typeof rootRoute } '/dashboard/invoices': { id: '/dashboard/invoices' path: '/invoices' fullPath: '/dashboard/invoices' - preLoaderRoute: typeof DashboardInvoicesRouteImport - parentRoute: typeof DashboardRouteImport + preLoaderRoute: typeof DashboardInvoicesRouteRouteImport + parentRoute: typeof DashboardRouteRouteImport } '/dashboard/users': { id: '/dashboard/users' path: '/users' fullPath: '/dashboard/users' - preLoaderRoute: typeof DashboardUsersRouteImport - parentRoute: typeof DashboardRouteImport + preLoaderRoute: typeof DashboardUsersRouteRouteImport + parentRoute: typeof DashboardRouteRouteImport } '/(this-folder-is-not-in-the-url)/route-group': { id: '/(this-folder-is-not-in-the-url)/route-group' path: '/route-group' fullPath: '/route-group' - preLoaderRoute: typeof thisFolderIsNotInTheUrlRouteGroupImport + preLoaderRoute: typeof thisFolderIsNotInTheUrlRouteGroupRouteImport parentRoute: typeof rootRoute } '/_auth/profile': { id: '/_auth/profile' path: '/profile' fullPath: '/profile' - preLoaderRoute: typeof AuthProfileImport - parentRoute: typeof AuthImport + preLoaderRoute: typeof AuthProfileRouteImport + parentRoute: typeof AuthRouteImport } '/_pathlessLayout/route-a': { id: '/_pathlessLayout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutRouteAImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/_pathlessLayout/route-b': { id: '/_pathlessLayout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutRouteBImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/dashboard/': { id: '/dashboard/' path: '/' fullPath: '/dashboard/' - preLoaderRoute: typeof DashboardIndexImport - parentRoute: typeof DashboardRouteImport + preLoaderRoute: typeof DashboardIndexRouteImport + parentRoute: typeof DashboardRouteRouteImport } '/expensive/': { id: '/expensive/' path: '/expensive' fullPath: '/expensive' - preLoaderRoute: typeof ExpensiveIndexImport + preLoaderRoute: typeof ExpensiveIndexRouteImport parentRoute: typeof rootRoute } '/dashboard/invoices/$invoiceId': { id: '/dashboard/invoices/$invoiceId' path: '/$invoiceId' fullPath: '/dashboard/invoices/$invoiceId' - preLoaderRoute: typeof DashboardInvoicesInvoiceIdImport - parentRoute: typeof DashboardInvoicesRouteImport + preLoaderRoute: typeof DashboardInvoicesInvoiceIdRouteImport + parentRoute: typeof DashboardInvoicesRouteRouteImport } '/dashboard/users/user': { id: '/dashboard/users/user' path: '/user' fullPath: '/dashboard/users/user' - preLoaderRoute: typeof DashboardUsersUserImport - parentRoute: typeof DashboardUsersRouteImport + preLoaderRoute: typeof DashboardUsersUserRouteImport + parentRoute: typeof DashboardUsersRouteRouteImport } '/dashboard/invoices/': { id: '/dashboard/invoices/' path: '/' fullPath: '/dashboard/invoices/' - preLoaderRoute: typeof DashboardInvoicesIndexImport - parentRoute: typeof DashboardInvoicesRouteImport + preLoaderRoute: typeof DashboardInvoicesIndexRouteImport + parentRoute: typeof DashboardInvoicesRouteRouteImport } '/dashboard/users/': { id: '/dashboard/users/' path: '/' fullPath: '/dashboard/users/' - preLoaderRoute: typeof DashboardUsersIndexImport - parentRoute: typeof DashboardUsersRouteImport + preLoaderRoute: typeof DashboardUsersIndexRouteImport + parentRoute: typeof DashboardUsersRouteRouteImport } } } diff --git a/examples/solid/kitchen-sink-file-based/src/routes/(this-folder-is-not-in-the-url)/route-group.tsx b/examples/solid/kitchen-sink-file-based/src/routes/(this-folder-is-not-in-the-url)/route-group.tsx index c06e439a1b..93cddb7fbb 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/(this-folder-is-not-in-the-url)/route-group.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/(this-folder-is-not-in-the-url)/route-group.tsx @@ -1,5 +1,5 @@ -import * as Solid from 'solid-js' import { createFileRoute } from '@tanstack/solid-router' +import * as Solid from 'solid-js' export const Route = createFileRoute( '/(this-folder-is-not-in-the-url)/route-group', diff --git a/examples/solid/kitchen-sink-file-based/src/routes/_auth.profile.tsx b/examples/solid/kitchen-sink-file-based/src/routes/_auth.profile.tsx index f67d367ee1..8756fe59e3 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/_auth.profile.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/_auth.profile.tsx @@ -1,5 +1,5 @@ -import * as Solid from 'solid-js' import { createFileRoute } from '@tanstack/solid-router' +import * as Solid from 'solid-js' export const Route = createFileRoute('/_auth/profile')({ component: ProfileComponent, diff --git a/examples/solid/kitchen-sink-file-based/src/routes/_auth.tsx b/examples/solid/kitchen-sink-file-based/src/routes/_auth.tsx index a5b98f8631..063eb5956d 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/_auth.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/_auth.tsx @@ -1,4 +1,5 @@ -import { createFileRoute, redirect } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { redirect } from '@tanstack/solid-router' import { auth } from '../utils/auth' export const Route = createFileRoute('/_auth')({ diff --git a/examples/solid/kitchen-sink-file-based/src/routes/_pathlessLayout.route-a.tsx b/examples/solid/kitchen-sink-file-based/src/routes/_pathlessLayout.route-a.tsx index c1c392cbad..73d603f19e 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/_pathlessLayout.route-a.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/_pathlessLayout.route-a.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_pathlessLayout/route-a')({ component: LayoutAComponent, }) diff --git a/examples/solid/kitchen-sink-file-based/src/routes/_pathlessLayout.route-b.tsx b/examples/solid/kitchen-sink-file-based/src/routes/_pathlessLayout.route-b.tsx index 30dd035c93..c3181d4905 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/_pathlessLayout.route-b.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/_pathlessLayout.route-b.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/_pathlessLayout/route-b')({ component: LayoutBComponent, }) diff --git a/examples/solid/kitchen-sink-file-based/src/routes/_pathlessLayout.tsx b/examples/solid/kitchen-sink-file-based/src/routes/_pathlessLayout.tsx index 9e090b1166..3b6c2f007a 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/_pathlessLayout.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/_pathlessLayout.tsx @@ -1,4 +1,5 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' export const Route = createFileRoute('/_pathlessLayout')({ component: PathlessLayoutComponent, diff --git a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.index.tsx b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.index.tsx index f967ed4f4b..d929550691 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.index.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.index.tsx @@ -1,5 +1,6 @@ -import * as Solid from 'solid-js' import { createFileRoute } from '@tanstack/solid-router' +import * as Solid from 'solid-js' + import { fetchInvoices } from '../utils/mockTodos' export const Route = createFileRoute('/dashboard/')({ diff --git a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.invoices.$invoiceId.tsx b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.invoices.$invoiceId.tsx index c5c35e15b9..1f8de1cd12 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.invoices.$invoiceId.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.invoices.$invoiceId.tsx @@ -1,10 +1,6 @@ +import { createFileRoute } from '@tanstack/solid-router' import * as Solid from 'solid-js' -import { - Link, - createFileRoute, - useNavigate, - useRouter, -} from '@tanstack/solid-router' +import { Link, useNavigate, useRouter } from '@tanstack/solid-router' import { z } from 'zod' import { InvoiceFields } from '../components/InvoiceFields' import { useMutation } from '../hooks/useMutation' diff --git a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.invoices.index.tsx b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.invoices.index.tsx index 936a2b01b3..04f48fdb31 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.invoices.index.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.invoices.index.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/solid-router' import * as Solid from 'solid-js' -import { createFileRoute, useRouter } from '@tanstack/solid-router' +import { useRouter } from '@tanstack/solid-router' import { InvoiceFields } from '../components/InvoiceFields' import { Spinner } from '../components/Spinner' import { useMutation } from '../hooks/useMutation' diff --git a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.invoices.route.tsx b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.invoices.route.tsx index 11668cac8e..a8e60043db 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.invoices.route.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.invoices.route.tsx @@ -1,10 +1,6 @@ +import { createFileRoute } from '@tanstack/solid-router' import * as Solid from 'solid-js' -import { - Link, - MatchRoute, - Outlet, - createFileRoute, -} from '@tanstack/solid-router' +import { Link, MatchRoute, Outlet } from '@tanstack/solid-router' import { Spinner } from '../components/Spinner' import { fetchInvoices } from '../utils/mockTodos' diff --git a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.route.tsx b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.route.tsx index c10209e841..de7f1922ab 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.route.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.route.tsx @@ -1,10 +1,6 @@ +import { createFileRoute } from '@tanstack/solid-router' import * as Solid from 'solid-js' -import { - Link, - Outlet, - createFileRoute, - linkOptions, -} from '@tanstack/solid-router' +import { Link, Outlet, linkOptions } from '@tanstack/solid-router' export const Route = createFileRoute('/dashboard')({ component: DashboardComponent, diff --git a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.users.index.tsx b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.users.index.tsx index 268107589d..e86fd08079 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.users.index.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.users.index.tsx @@ -1,5 +1,5 @@ -import * as Solid from 'solid-js' import { createFileRoute } from '@tanstack/solid-router' +import * as Solid from 'solid-js' export const Route = createFileRoute('/dashboard/users/')({ component: UsersIndexComponent, diff --git a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.users.route.tsx b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.users.route.tsx index dee3a070ec..846d56dd48 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.users.route.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.users.route.tsx @@ -1,9 +1,9 @@ +import { createFileRoute } from '@tanstack/solid-router' import * as Solid from 'solid-js' import { Link, MatchRoute, Outlet, - createFileRoute, retainSearchParams, useNavigate, useRouterState, diff --git a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.users.user.tsx b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.users.user.tsx index 84cecbe1c0..b05172fb49 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/dashboard.users.user.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/dashboard.users.user.tsx @@ -1,5 +1,6 @@ -import * as Solid from 'solid-js' import { createFileRoute } from '@tanstack/solid-router' +import * as Solid from 'solid-js' + import { z } from 'zod' import { fetchUserById } from '../utils/mockTodos' diff --git a/examples/solid/kitchen-sink-file-based/src/routes/index.tsx b/examples/solid/kitchen-sink-file-based/src/routes/index.tsx index 3301318ef3..2fd9f1ce71 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/index.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/index.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/solid-router' import * as Solid from 'solid-js' -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' export const Route = createFileRoute('/')({ component: IndexComponent, diff --git a/examples/solid/kitchen-sink-file-based/src/routes/login.tsx b/examples/solid/kitchen-sink-file-based/src/routes/login.tsx index 1a4bed3e9c..8367e59e10 100644 --- a/examples/solid/kitchen-sink-file-based/src/routes/login.tsx +++ b/examples/solid/kitchen-sink-file-based/src/routes/login.tsx @@ -1,5 +1,6 @@ +import { createFileRoute } from '@tanstack/solid-router' import * as Solid from 'solid-js' -import { createFileRoute, useRouter } from '@tanstack/solid-router' +import { useRouter } from '@tanstack/solid-router' import { z } from 'zod' export const Route = createFileRoute('/login')({ diff --git a/examples/solid/kitchen-sink-file-based/vite.config.js b/examples/solid/kitchen-sink-file-based/vite.config.js index 59c70c1244..a4b5a71096 100644 --- a/examples/solid/kitchen-sink-file-based/vite.config.js +++ b/examples/solid/kitchen-sink-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' import solidPlugin from 'vite-plugin-solid' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ target: 'solid', autoCodeSplitting: true }), + tanstackRouter({ target: 'solid', autoCodeSplitting: true }), solidPlugin(), ], }) diff --git a/examples/solid/quickstart-file-based/package.json b/examples/solid/quickstart-file-based/package.json index e22354139e..ca737eafb4 100644 --- a/examples/solid/quickstart-file-based/package.json +++ b/examples/solid/quickstart-file-based/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/solid-router": "^1.120.3", - "@tanstack/solid-router-devtools": "^1.120.3", + "@tanstack/solid-router": "^1.121.0-alpha.11", + "@tanstack/solid-router-devtools": "^1.121.0-alpha.11", "autoprefixer": "^10.4.20", "postcss": "^8.5.1", "redaxios": "^0.5.1", @@ -19,9 +19,9 @@ "zod": "^3.24.2" }, "devDependencies": { - "@tanstack/router-plugin": "^1.120.3", + "@tanstack/router-plugin": "^1.121.0-alpha.11", "typescript": "^5.7.2", - "vite": "^6.1.0", + "vite": "^6.3.5", "vite-plugin-solid": "^2.11.2" } } diff --git a/examples/solid/quickstart-file-based/src/routeTree.gen.ts b/examples/solid/quickstart-file-based/src/routeTree.gen.ts index cb367c516c..f1ce74b320 100644 --- a/examples/solid/quickstart-file-based/src/routeTree.gen.ts +++ b/examples/solid/quickstart-file-based/src/routeTree.gen.ts @@ -11,18 +11,18 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as AboutImport } from './routes/about' -import { Route as IndexImport } from './routes/index' +import { Route as AboutRouteImport } from './routes/about' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const AboutRoute = AboutImport.update({ +const AboutRoute = AboutRouteImport.update({ id: '/about', path: '/about', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -36,14 +36,14 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/about': { id: '/about' path: '/about' fullPath: '/about' - preLoaderRoute: typeof AboutImport + preLoaderRoute: typeof AboutRouteImport parentRoute: typeof rootRoute } } diff --git a/examples/solid/quickstart-file-based/src/routes/about.tsx b/examples/solid/quickstart-file-based/src/routes/about.tsx index 4596223513..47f6c510f2 100644 --- a/examples/solid/quickstart-file-based/src/routes/about.tsx +++ b/examples/solid/quickstart-file-based/src/routes/about.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/about')({ component: AboutComponent, }) diff --git a/examples/solid/quickstart-file-based/src/routes/index.tsx b/examples/solid/quickstart-file-based/src/routes/index.tsx index c71b5d33f2..10d3d3acaf 100644 --- a/examples/solid/quickstart-file-based/src/routes/index.tsx +++ b/examples/solid/quickstart-file-based/src/routes/index.tsx @@ -1,5 +1,4 @@ import { createFileRoute } from '@tanstack/solid-router' - export const Route = createFileRoute('/')({ component: HomeComponent, }) diff --git a/examples/solid/quickstart-file-based/vite.config.js b/examples/solid/quickstart-file-based/vite.config.js index 2b2f26819d..74e9ca3db3 100644 --- a/examples/solid/quickstart-file-based/vite.config.js +++ b/examples/solid/quickstart-file-based/vite.config.js @@ -1,11 +1,11 @@ import { defineConfig } from 'vite' import solid from 'vite-plugin-solid' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from '@tanstack/router-plugin/vite' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ - TanStackRouterVite({ + tanstackRouter({ target: 'solid', autoCodeSplitting: true, }), diff --git a/examples/solid/start-bare/.tanstack-start/server-routes/routeTree.gen.ts b/examples/solid/start-bare/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..2dc6bfc4bd --- /dev/null +++ b/examples/solid/start-bare/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/solid-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/solid-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/solid-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/solid/start-bare/app.config.ts b/examples/solid/start-bare/app.config.ts deleted file mode 100644 index 19c03a0458..0000000000 --- a/examples/solid/start-bare/app.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineConfig } from '@tanstack/solid-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - tailwindcss(), - ], - }, -}) diff --git a/examples/solid/start-bare/package.json b/examples/solid/start-bare/package.json index 2a94ab0a76..c0abe82f4c 100644 --- a/examples/solid/start-bare/package.json +++ b/examples/solid/start-bare/package.json @@ -4,18 +4,18 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { - "@tanstack/solid-router": "^1.120.3", - "@tanstack/solid-router-devtools": "^1.120.3", - "@tanstack/solid-start": "^1.120.3", + "@tanstack/solid-router": "^1.121.0-alpha.11", + "@tanstack/solid-router-devtools": "^1.121.0-alpha.11", + "@tanstack/solid-start": "^1.121.0-alpha.11", "solid-js": "^1.9.5", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", + "vite": "^6.3.5", "zod": "^3.24.2" }, "devDependencies": { diff --git a/examples/solid/start-bare/src/client.tsx b/examples/solid/start-bare/src/client.tsx deleted file mode 100644 index ba0f02fac0..0000000000 --- a/examples/solid/start-bare/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrate } from 'solid-js/web' -import { StartClient } from '@tanstack/solid-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrate(() => , document.body) diff --git a/examples/solid/start-bare/src/routeTree.gen.ts b/examples/solid/start-bare/src/routeTree.gen.ts index cb367c516c..ba17474a57 100644 --- a/examples/solid/start-bare/src/routeTree.gen.ts +++ b/examples/solid/start-bare/src/routeTree.gen.ts @@ -8,21 +8,23 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/solid-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as AboutImport } from './routes/about' -import { Route as IndexImport } from './routes/index' +import { Route as AboutRouteImport } from './routes/about' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const AboutRoute = AboutImport.update({ +const AboutRoute = AboutRouteImport.update({ id: '/about', path: '/about', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -36,19 +38,40 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/about': { id: '/about' path: '/about' fullPath: '/about' - preLoaderRoute: typeof AboutImport + preLoaderRoute: typeof AboutRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/about' { + const createFileRoute: CreateFileRoute< + '/about', + FileRoutesByPath['/about']['parentRoute'], + FileRoutesByPath['/about']['id'], + FileRoutesByPath['/about']['path'], + FileRoutesByPath['/about']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/examples/solid/start-bare/src/routes/about.tsx b/examples/solid/start-bare/src/routes/about.tsx index d66c7db828..f0d5d234a0 100644 --- a/examples/solid/start-bare/src/routes/about.tsx +++ b/examples/solid/start-bare/src/routes/about.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/about')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/examples/solid/start-bare/src/routes/index.tsx b/examples/solid/start-bare/src/routes/index.tsx index 6a91bd1999..2f6c3c11e9 100644 --- a/examples/solid/start-bare/src/routes/index.tsx +++ b/examples/solid/start-bare/src/routes/index.tsx @@ -1,6 +1,5 @@ -import { createFileRoute } from '@tanstack/solid-router' import Counter from '~/components/Counter' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/examples/solid/start-bare/src/ssr.tsx b/examples/solid/start-bare/src/ssr.tsx deleted file mode 100644 index 6d10bea05f..0000000000 --- a/examples/solid/start-bare/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/solid-start/server' -import { getRouterManifest } from '@tanstack/solid-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/solid/start-bare/src/tanstack-start.d.ts b/examples/solid/start-bare/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/solid/start-bare/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/solid/start-bare/vite.config.ts b/examples/solid/start-bare/vite.config.ts new file mode 100644 index 0000000000..e5bc95116e --- /dev/null +++ b/examples/solid/start-bare/vite.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + tailwindcss(), + ], +}) diff --git a/examples/solid/start-basic-static/.gitignore b/examples/solid/start-basic-static/.gitignore new file mode 100644 index 0000000000..ca63f49885 --- /dev/null +++ b/examples/solid/start-basic-static/.gitignore @@ -0,0 +1,18 @@ +node_modules +package-lock.json +yarn.lock + +.DS_Store +.cache +.env +.vercel +.output +/build/ +/api/ +/server/build +/public/build# Sentry Config File +.env.sentry-build-plugin +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/examples/solid/start-basic-static/.prettierignore b/examples/solid/start-basic-static/.prettierignore new file mode 100644 index 0000000000..2be5eaa6ec --- /dev/null +++ b/examples/solid/start-basic-static/.prettierignore @@ -0,0 +1,4 @@ +**/build +**/public +pnpm-lock.yaml +routeTree.gen.ts \ No newline at end of file diff --git a/examples/solid/start-basic-static/.tanstack-start/server-routes/routeTree.gen.ts b/examples/solid/start-basic-static/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..2dc6bfc4bd --- /dev/null +++ b/examples/solid/start-basic-static/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/solid-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/solid-start/server' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/solid-start/server' { + interface FileRoutesByPath {} +} + +// Add type-safety to the createFileRoute function across the route tree + +// Create and export the route tree + +export interface FileRoutesByFullPath {} + +export interface FileRoutesByTo {} + +export interface FileRoutesById { + __root__: typeof rootRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: '__root__' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren {} + +const rootRouteChildren: RootRouteChildren = {} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [] + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/solid/start-basic-static/README.md b/examples/solid/start-basic-static/README.md new file mode 100644 index 0000000000..eb580a5bf8 --- /dev/null +++ b/examples/solid/start-basic-static/README.md @@ -0,0 +1,72 @@ +# Welcome to TanStack.com! + +This site is built with TanStack Router! + +- [TanStack Router Docs](https://tanstack.com/router) + +It's deployed automagically with Vercel! + +- [Vercel](https://vercel.com/) + +## Development + +From your terminal: + +```sh +pnpm install +pnpm dev +``` + +This starts your app in development mode, rebuilding assets on file changes. + +## Editing and previewing the docs of TanStack projects locally + +The documentations for all TanStack projects except for `React Charts` are hosted on [https://tanstack.com](https://tanstack.com), powered by this TanStack Router app. +In production, the markdown doc pages are fetched from the GitHub repos of the projects, but in development they are read from the local file system. + +Follow these steps if you want to edit the doc pages of a project (in these steps we'll assume it's [`TanStack/form`](https://github.com/tanstack/form)) and preview them locally : + +1. Create a new directory called `tanstack`. + +```sh +mkdir tanstack +``` + +2. Enter the directory and clone this repo and the repo of the project there. + +```sh +cd tanstack +git clone git@github.com:TanStack/tanstack.com.git +git clone git@github.com:TanStack/form.git +``` + +> [!NOTE] +> Your `tanstack` directory should look like this: +> +> ``` +> tanstack/ +> | +> +-- form/ +> | +> +-- tanstack.com/ +> ``` + +> [!WARNING] +> Make sure the name of the directory in your local file system matches the name of the project's repo. For example, `tanstack/form` must be cloned into `form` (this is the default) instead of `some-other-name`, because that way, the doc pages won't be found. + +3. Enter the `tanstack/tanstack.com` directory, install the dependencies and run the app in dev mode: + +```sh +cd tanstack.com +pnpm i +# The app will run on https://localhost:3000 by default +pnpm dev +``` + +4. Now you can visit http://localhost:3000/form/latest/docs/overview in the browser and see the changes you make in `tanstack/form/docs`. + +> [!NOTE] +> The updated pages need to be manually reloaded in the browser. + +> [!WARNING] +> You will need to update the `docs/config.json` file (in the project's repo) if you add a new doc page! diff --git a/examples/solid/start-basic-static/package.json b/examples/solid/start-basic-static/package.json new file mode 100644 index 0000000000..e566e51305 --- /dev/null +++ b/examples/solid/start-basic-static/package.json @@ -0,0 +1,27 @@ +{ + "name": "tanstack-solid-start-example-basic-static", + "private": true, + "sideEffects": false, + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "start": "vite start" + }, + "dependencies": { + "@tanstack/solid-router": "^1.121.0-alpha.11", + "@tanstack/solid-router-devtools": "^1.121.0-alpha.11", + "@tanstack/solid-start": "^1.121.0-alpha.11", + "solid-js": "^1.9.5", + "redaxios": "^0.5.1", + "tailwind-merge": "^2.5.5" + }, + "devDependencies": { + "@types/node": "^22.5.4", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.49", + "tailwindcss": "^3.4.15", + "typescript": "^5.6.2", + "vite-tsconfig-paths": "^5.1.3" + } +} diff --git a/examples/solid/start-basic-static/postcss.config.cjs b/examples/solid/start-basic-static/postcss.config.cjs new file mode 100644 index 0000000000..8e638a6bcd --- /dev/null +++ b/examples/solid/start-basic-static/postcss.config.cjs @@ -0,0 +1,7 @@ +module.exports = { + plugins: [ + require('tailwindcss/nesting'), + require('tailwindcss'), + require('autoprefixer'), + ], +} diff --git a/examples/solid/start-basic-static/public/android-chrome-192x192.png b/examples/solid/start-basic-static/public/android-chrome-192x192.png new file mode 100644 index 0000000000..09c8324f8c Binary files /dev/null and b/examples/solid/start-basic-static/public/android-chrome-192x192.png differ diff --git a/examples/solid/start-basic-static/public/android-chrome-512x512.png b/examples/solid/start-basic-static/public/android-chrome-512x512.png new file mode 100644 index 0000000000..11d626ea3d Binary files /dev/null and b/examples/solid/start-basic-static/public/android-chrome-512x512.png differ diff --git a/examples/solid/start-basic-static/public/apple-touch-icon.png b/examples/solid/start-basic-static/public/apple-touch-icon.png new file mode 100644 index 0000000000..5a9423cc02 Binary files /dev/null and b/examples/solid/start-basic-static/public/apple-touch-icon.png differ diff --git a/examples/solid/start-basic-static/public/favicon-16x16.png b/examples/solid/start-basic-static/public/favicon-16x16.png new file mode 100644 index 0000000000..e3389b0044 Binary files /dev/null and b/examples/solid/start-basic-static/public/favicon-16x16.png differ diff --git a/examples/solid/start-basic-static/public/favicon-32x32.png b/examples/solid/start-basic-static/public/favicon-32x32.png new file mode 100644 index 0000000000..900c77d444 Binary files /dev/null and b/examples/solid/start-basic-static/public/favicon-32x32.png differ diff --git a/examples/solid/start-basic-static/public/favicon.ico b/examples/solid/start-basic-static/public/favicon.ico new file mode 100644 index 0000000000..1a1751676f Binary files /dev/null and b/examples/solid/start-basic-static/public/favicon.ico differ diff --git a/examples/solid/start-basic-static/public/favicon.png b/examples/solid/start-basic-static/public/favicon.png new file mode 100644 index 0000000000..1e77bc0609 Binary files /dev/null and b/examples/solid/start-basic-static/public/favicon.png differ diff --git a/examples/solid/start-basic-static/public/site.webmanifest b/examples/solid/start-basic-static/public/site.webmanifest new file mode 100644 index 0000000000..fa99de77db --- /dev/null +++ b/examples/solid/start-basic-static/public/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/examples/solid/start-basic-static/src/components/DefaultCatchBoundary.tsx b/examples/solid/start-basic-static/src/components/DefaultCatchBoundary.tsx new file mode 100644 index 0000000000..0dff3919fd --- /dev/null +++ b/examples/solid/start-basic-static/src/components/DefaultCatchBoundary.tsx @@ -0,0 +1,53 @@ +import { + ErrorComponent, + Link, + rootRouteId, + useMatch, + useRouter, +} from '@tanstack/solid-router' +import type { ErrorComponentProps } from '@tanstack/solid-router' + +export function DefaultCatchBoundary({ error }: ErrorComponentProps) { + const router = useRouter() + const isRoot = useMatch({ + strict: false, + select: (state) => state.id === rootRouteId, + }) + + console.error('DefaultCatchBoundary Error:', error) + + return ( +
+ +
+ + {isRoot() ? ( + + Home + + ) : ( + { + e.preventDefault() + window.history.back() + }} + > + Go Back + + )} +
+
+ ) +} diff --git a/examples/solid/start-basic-static/src/components/NotFound.tsx b/examples/solid/start-basic-static/src/components/NotFound.tsx new file mode 100644 index 0000000000..ca4c1960fa --- /dev/null +++ b/examples/solid/start-basic-static/src/components/NotFound.tsx @@ -0,0 +1,25 @@ +import { Link } from '@tanstack/solid-router' + +export function NotFound({ children }: { children?: any }) { + return ( +
+
+ {children ||

The page you are looking for does not exist.

} +
+

+ + + Start Over + +

+
+ ) +} diff --git a/examples/solid/start-basic-static/src/routeTree.gen.ts b/examples/solid/start-basic-static/src/routeTree.gen.ts new file mode 100644 index 0000000000..91d6a4bf15 --- /dev/null +++ b/examples/solid/start-basic-static/src/routeTree.gen.ts @@ -0,0 +1,609 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/solid-router' + +// Import Routes + +import { Route as rootRoute } from './routes/__root' +import { Route as UsersRouteImport } from './routes/users' +import { Route as RedirectRouteImport } from './routes/redirect' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as DeferredRouteImport } from './routes/deferred' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as UsersIndexRouteImport } from './routes/users.index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as UsersUserIdRouteImport } from './routes/users.$userId' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts_.$postId.deep' +import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' +import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' + +// Create/Update Routes + +const UsersRoute = UsersRouteImport.update({ + id: '/users', + path: '/users', + getParentRoute: () => rootRoute, +} as any) + +const RedirectRoute = RedirectRouteImport.update({ + id: '/redirect', + path: '/redirect', + getParentRoute: () => rootRoute, +} as any) + +const PostsRoute = PostsRouteImport.update({ + id: '/posts', + path: '/posts', + getParentRoute: () => rootRoute, +} as any) + +const DeferredRoute = DeferredRouteImport.update({ + id: '/deferred', + path: '/deferred', + getParentRoute: () => rootRoute, +} as any) + +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ + id: '/_pathlessLayout', + getParentRoute: () => rootRoute, +} as any) + +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRoute, +} as any) + +const UsersIndexRoute = UsersIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => UsersRoute, +} as any) + +const PostsIndexRoute = PostsIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => PostsRoute, +} as any) + +const UsersUserIdRoute = UsersUserIdRouteImport.update({ + id: '/$userId', + path: '/$userId', + getParentRoute: () => UsersRoute, +} as any) + +const PostsPostIdRoute = PostsPostIdRouteImport.update({ + id: '/$postId', + path: '/$postId', + getParentRoute: () => PostsRoute, +} as any) + +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ + id: '/_nested-layout', + getParentRoute: () => PathlessLayoutRoute, + } as any) + +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ + id: '/posts_/$postId/deep', + path: '/posts/$postId/deep', + getParentRoute: () => rootRoute, +} as any) + +const PathlessLayoutNestedLayoutRouteBRoute = + PathlessLayoutNestedLayoutRouteBRouteImport.update({ + id: '/route-b', + path: '/route-b', + getParentRoute: () => PathlessLayoutNestedLayoutRoute, + } as any) + +const PathlessLayoutNestedLayoutRouteARoute = + PathlessLayoutNestedLayoutRouteARouteImport.update({ + id: '/route-a', + path: '/route-a', + getParentRoute: () => PathlessLayoutNestedLayoutRoute, + } as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/solid-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRoute + } + '/_pathlessLayout': { + id: '/_pathlessLayout' + path: '' + fullPath: '' + preLoaderRoute: typeof PathlessLayoutRouteImport + parentRoute: typeof rootRoute + } + '/deferred': { + id: '/deferred' + path: '/deferred' + fullPath: '/deferred' + preLoaderRoute: typeof DeferredRouteImport + parentRoute: typeof rootRoute + } + '/posts': { + id: '/posts' + path: '/posts' + fullPath: '/posts' + preLoaderRoute: typeof PostsRouteImport + parentRoute: typeof rootRoute + } + '/redirect': { + id: '/redirect' + path: '/redirect' + fullPath: '/redirect' + preLoaderRoute: typeof RedirectRouteImport + parentRoute: typeof rootRoute + } + '/users': { + id: '/users' + path: '/users' + fullPath: '/users' + preLoaderRoute: typeof UsersRouteImport + parentRoute: typeof rootRoute + } + '/_pathlessLayout/_nested-layout': { + id: '/_pathlessLayout/_nested-layout' + path: '' + fullPath: '' + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport + parentRoute: typeof PathlessLayoutRouteImport + } + '/posts/$postId': { + id: '/posts/$postId' + path: '/$postId' + fullPath: '/posts/$postId' + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport + } + '/users/$userId': { + id: '/users/$userId' + path: '/$userId' + fullPath: '/users/$userId' + preLoaderRoute: typeof UsersUserIdRouteImport + parentRoute: typeof UsersRouteImport + } + '/posts/': { + id: '/posts/' + path: '/' + fullPath: '/posts/' + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport + } + '/users/': { + id: '/users/' + path: '/' + fullPath: '/users/' + preLoaderRoute: typeof UsersIndexRouteImport + parentRoute: typeof UsersRouteImport + } + '/_pathlessLayout/_nested-layout/route-a': { + id: '/_pathlessLayout/_nested-layout/route-a' + path: '/route-a' + fullPath: '/route-a' + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport + } + '/_pathlessLayout/_nested-layout/route-b': { + id: '/_pathlessLayout/_nested-layout/route-b' + path: '/route-b' + fullPath: '/route-b' + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport + } + '/posts_/$postId/deep': { + id: '/posts_/$postId/deep' + path: '/posts/$postId/deep' + fullPath: '/posts/$postId/deep' + preLoaderRoute: typeof PostsPostIdDeepRouteImport + parentRoute: typeof rootRoute + } + } +} + +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_pathlessLayout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout', + FileRoutesByPath['/_pathlessLayout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout']['id'], + FileRoutesByPath['/_pathlessLayout']['path'], + FileRoutesByPath['/_pathlessLayout']['fullPath'] + > +} +declare module './routes/deferred' { + const createFileRoute: CreateFileRoute< + '/deferred', + FileRoutesByPath['/deferred']['parentRoute'], + FileRoutesByPath['/deferred']['id'], + FileRoutesByPath['/deferred']['path'], + FileRoutesByPath['/deferred']['fullPath'] + > +} +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/redirect' { + const createFileRoute: CreateFileRoute< + '/redirect', + FileRoutesByPath['/redirect']['parentRoute'], + FileRoutesByPath['/redirect']['id'], + FileRoutesByPath['/redirect']['path'], + FileRoutesByPath['/redirect']['fullPath'] + > +} +declare module './routes/users' { + const createFileRoute: CreateFileRoute< + '/users', + FileRoutesByPath['/users']['parentRoute'], + FileRoutesByPath['/users']['id'], + FileRoutesByPath['/users']['path'], + FileRoutesByPath['/users']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout', + FileRoutesByPath['/_pathlessLayout/_nested-layout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/users.$userId' { + const createFileRoute: CreateFileRoute< + '/users/$userId', + FileRoutesByPath['/users/$userId']['parentRoute'], + FileRoutesByPath['/users/$userId']['id'], + FileRoutesByPath['/users/$userId']['path'], + FileRoutesByPath['/users/$userId']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/users.index' { + const createFileRoute: CreateFileRoute< + '/users/', + FileRoutesByPath['/users/']['parentRoute'], + FileRoutesByPath['/users/']['id'], + FileRoutesByPath['/users/']['path'], + FileRoutesByPath['/users/']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-a' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-a', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-b' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-b', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['fullPath'] + > +} +declare module './routes/posts_.$postId.deep' { + const createFileRoute: CreateFileRoute< + '/posts_/$postId/deep', + FileRoutesByPath['/posts_/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > +} + +// Create and export the route tree + +interface PathlessLayoutNestedLayoutRouteChildren { + PathlessLayoutNestedLayoutRouteARoute: typeof PathlessLayoutNestedLayoutRouteARoute + PathlessLayoutNestedLayoutRouteBRoute: typeof PathlessLayoutNestedLayoutRouteBRoute +} + +const PathlessLayoutNestedLayoutRouteChildren: PathlessLayoutNestedLayoutRouteChildren = + { + PathlessLayoutNestedLayoutRouteARoute: + PathlessLayoutNestedLayoutRouteARoute, + PathlessLayoutNestedLayoutRouteBRoute: + PathlessLayoutNestedLayoutRouteBRoute, + } + +const PathlessLayoutNestedLayoutRouteWithChildren = + PathlessLayoutNestedLayoutRoute._addFileChildren( + PathlessLayoutNestedLayoutRouteChildren, + ) + +interface PathlessLayoutRouteChildren { + PathlessLayoutNestedLayoutRoute: typeof PathlessLayoutNestedLayoutRouteWithChildren +} + +const PathlessLayoutRouteChildren: PathlessLayoutRouteChildren = { + PathlessLayoutNestedLayoutRoute: PathlessLayoutNestedLayoutRouteWithChildren, +} + +const PathlessLayoutRouteWithChildren = PathlessLayoutRoute._addFileChildren( + PathlessLayoutRouteChildren, +) + +interface PostsRouteChildren { + PostsPostIdRoute: typeof PostsPostIdRoute + PostsIndexRoute: typeof PostsIndexRoute +} + +const PostsRouteChildren: PostsRouteChildren = { + PostsPostIdRoute: PostsPostIdRoute, + PostsIndexRoute: PostsIndexRoute, +} + +const PostsRouteWithChildren = PostsRoute._addFileChildren(PostsRouteChildren) + +interface UsersRouteChildren { + UsersUserIdRoute: typeof UsersUserIdRoute + UsersIndexRoute: typeof UsersIndexRoute +} + +const UsersRouteChildren: UsersRouteChildren = { + UsersUserIdRoute: UsersUserIdRoute, + UsersIndexRoute: UsersIndexRoute, +} + +const UsersRouteWithChildren = UsersRoute._addFileChildren(UsersRouteChildren) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '': typeof PathlessLayoutNestedLayoutRouteWithChildren + '/deferred': typeof DeferredRoute + '/posts': typeof PostsRouteWithChildren + '/redirect': typeof RedirectRoute + '/users': typeof UsersRouteWithChildren + '/posts/$postId': typeof PostsPostIdRoute + '/users/$userId': typeof UsersUserIdRoute + '/posts/': typeof PostsIndexRoute + '/users/': typeof UsersIndexRoute + '/route-a': typeof PathlessLayoutNestedLayoutRouteARoute + '/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute + '/posts/$postId/deep': typeof PostsPostIdDeepRoute +} + +export interface FileRoutesByTo { + '/': typeof IndexRoute + '': typeof PathlessLayoutNestedLayoutRouteWithChildren + '/deferred': typeof DeferredRoute + '/redirect': typeof RedirectRoute + '/posts/$postId': typeof PostsPostIdRoute + '/users/$userId': typeof UsersUserIdRoute + '/posts': typeof PostsIndexRoute + '/users': typeof UsersIndexRoute + '/route-a': typeof PathlessLayoutNestedLayoutRouteARoute + '/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute + '/posts/$postId/deep': typeof PostsPostIdDeepRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/': typeof IndexRoute + '/_pathlessLayout': typeof PathlessLayoutRouteWithChildren + '/deferred': typeof DeferredRoute + '/posts': typeof PostsRouteWithChildren + '/redirect': typeof RedirectRoute + '/users': typeof UsersRouteWithChildren + '/_pathlessLayout/_nested-layout': typeof PathlessLayoutNestedLayoutRouteWithChildren + '/posts/$postId': typeof PostsPostIdRoute + '/users/$userId': typeof UsersUserIdRoute + '/posts/': typeof PostsIndexRoute + '/users/': typeof UsersIndexRoute + '/_pathlessLayout/_nested-layout/route-a': typeof PathlessLayoutNestedLayoutRouteARoute + '/_pathlessLayout/_nested-layout/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute + '/posts_/$postId/deep': typeof PostsPostIdDeepRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/' + | '' + | '/deferred' + | '/posts' + | '/redirect' + | '/users' + | '/posts/$postId' + | '/users/$userId' + | '/posts/' + | '/users/' + | '/route-a' + | '/route-b' + | '/posts/$postId/deep' + fileRoutesByTo: FileRoutesByTo + to: + | '/' + | '' + | '/deferred' + | '/redirect' + | '/posts/$postId' + | '/users/$userId' + | '/posts' + | '/users' + | '/route-a' + | '/route-b' + | '/posts/$postId/deep' + id: + | '__root__' + | '/' + | '/_pathlessLayout' + | '/deferred' + | '/posts' + | '/redirect' + | '/users' + | '/_pathlessLayout/_nested-layout' + | '/posts/$postId' + | '/users/$userId' + | '/posts/' + | '/users/' + | '/_pathlessLayout/_nested-layout/route-a' + | '/_pathlessLayout/_nested-layout/route-b' + | '/posts_/$postId/deep' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + PathlessLayoutRoute: typeof PathlessLayoutRouteWithChildren + DeferredRoute: typeof DeferredRoute + PostsRoute: typeof PostsRouteWithChildren + RedirectRoute: typeof RedirectRoute + UsersRoute: typeof UsersRouteWithChildren + PostsPostIdDeepRoute: typeof PostsPostIdDeepRoute +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + PathlessLayoutRoute: PathlessLayoutRouteWithChildren, + DeferredRoute: DeferredRoute, + PostsRoute: PostsRouteWithChildren, + RedirectRoute: RedirectRoute, + UsersRoute: UsersRouteWithChildren, + PostsPostIdDeepRoute: PostsPostIdDeepRoute, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/", + "/_pathlessLayout", + "/deferred", + "/posts", + "/redirect", + "/users", + "/posts_/$postId/deep" + ] + }, + "/": { + "filePath": "index.tsx" + }, + "/_pathlessLayout": { + "filePath": "_pathlessLayout.tsx", + "children": [ + "/_pathlessLayout/_nested-layout" + ] + }, + "/deferred": { + "filePath": "deferred.tsx" + }, + "/posts": { + "filePath": "posts.tsx", + "children": [ + "/posts/$postId", + "/posts/" + ] + }, + "/redirect": { + "filePath": "redirect.tsx" + }, + "/users": { + "filePath": "users.tsx", + "children": [ + "/users/$userId", + "/users/" + ] + }, + "/_pathlessLayout/_nested-layout": { + "filePath": "_pathlessLayout/_nested-layout.tsx", + "parent": "/_pathlessLayout", + "children": [ + "/_pathlessLayout/_nested-layout/route-a", + "/_pathlessLayout/_nested-layout/route-b" + ] + }, + "/posts/$postId": { + "filePath": "posts.$postId.tsx", + "parent": "/posts" + }, + "/users/$userId": { + "filePath": "users.$userId.tsx", + "parent": "/users" + }, + "/posts/": { + "filePath": "posts.index.tsx", + "parent": "/posts" + }, + "/users/": { + "filePath": "users.index.tsx", + "parent": "/users" + }, + "/_pathlessLayout/_nested-layout/route-a": { + "filePath": "_pathlessLayout/_nested-layout/route-a.tsx", + "parent": "/_pathlessLayout/_nested-layout" + }, + "/_pathlessLayout/_nested-layout/route-b": { + "filePath": "_pathlessLayout/_nested-layout/route-b.tsx", + "parent": "/_pathlessLayout/_nested-layout" + }, + "/posts_/$postId/deep": { + "filePath": "posts_.$postId.deep.tsx" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/solid/start-basic-static/src/router.tsx b/examples/solid/start-basic-static/src/router.tsx new file mode 100644 index 0000000000..c45bed4758 --- /dev/null +++ b/examples/solid/start-basic-static/src/router.tsx @@ -0,0 +1,22 @@ +import { createRouter as createTanStackRouter } from '@tanstack/solid-router' +import { routeTree } from './routeTree.gen' +import { DefaultCatchBoundary } from './components/DefaultCatchBoundary' +import { NotFound } from './components/NotFound' + +export function createRouter() { + const router = createTanStackRouter({ + routeTree, + defaultPreload: 'intent', + defaultErrorComponent: DefaultCatchBoundary, + defaultNotFoundComponent: () => , + scrollRestoration: true, + }) + + return router +} + +declare module '@tanstack/solid-router' { + interface Register { + router: ReturnType + } +} diff --git a/examples/solid/start-basic-static/src/routes/__root.tsx b/examples/solid/start-basic-static/src/routes/__root.tsx new file mode 100644 index 0000000000..2b70666cbd --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/__root.tsx @@ -0,0 +1,139 @@ +import { + HeadContent, + Link, + Outlet, + Scripts, + createRootRoute, +} from '@tanstack/solid-router' +import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools' +import type * as Solid from 'solid-js' +import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary' +import { NotFound } from '~/components/NotFound' +import appCss from '~/styles/app.css?url' +import { seo } from '~/utils/seo' + +export const Route = createRootRoute({ + head: () => ({ + meta: [ + { + charset: 'utf-8', + }, + { + name: 'viewport', + content: 'width=device-width, initial-scale=1', + }, + ...seo({ + title: + 'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework', + description: `TanStack Start is a type-safe, client-first, full-stack React framework. `, + }), + ], + links: [ + { rel: 'stylesheet', href: appCss }, + { + rel: 'apple-touch-icon', + sizes: '180x180', + href: '/apple-touch-icon.png', + }, + { + rel: 'icon', + type: 'image/png', + sizes: '32x32', + href: '/favicon-32x32.png', + }, + { + rel: 'icon', + type: 'image/png', + sizes: '16x16', + href: '/favicon-16x16.png', + }, + { rel: 'manifest', href: '/site.webmanifest', color: '#fffff' }, + { rel: 'icon', href: '/favicon.ico' }, + ], + }), + errorComponent: (props) => { + return ( + + + + ) + }, + notFoundComponent: () => , + component: RootComponent, +}) + +function RootComponent() { + return ( + + + + ) +} + +function RootLayout({ children }: { children: Solid.JSX.Element }) { + return ( + + + + + +
+ + Home + {' '} + + Posts + {' '} + + Users + {' '} + + Pathless Layout + {' '} + + Deferred + {' '} + + This Route Does Not Exist + +
+
+ {children} + + + + + ) +} diff --git a/examples/solid/start-basic-static/src/routes/_pathlessLayout.tsx b/examples/solid/start-basic-static/src/routes/_pathlessLayout.tsx new file mode 100644 index 0000000000..9bb7ce1c98 --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/_pathlessLayout.tsx @@ -0,0 +1,16 @@ +import { Outlet } from '@tanstack/solid-router' + +export const Route = createFileRoute({ + component: PathlessLayoutComponent, +}) + +function PathlessLayoutComponent() { + return ( +
+
I'm a pathless layout
+
+ +
+
+ ) +} diff --git a/examples/solid/start-basic-static/src/routes/_pathlessLayout/_nested-layout.tsx b/examples/solid/start-basic-static/src/routes/_pathlessLayout/_nested-layout.tsx new file mode 100644 index 0000000000..03bcac9d47 --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/_pathlessLayout/_nested-layout.tsx @@ -0,0 +1,34 @@ +import { Link, Outlet } from '@tanstack/solid-router' + +export const Route = createFileRoute({ + component: LayoutComponent, +}) + +function LayoutComponent() { + return ( +
+
I'm a nested layout
+
+ + Go to route A + + + Go to route B + +
+
+ +
+
+ ) +} diff --git a/examples/solid/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/examples/solid/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-a.tsx new file mode 100644 index 0000000000..a0bd5240b7 --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-a.tsx @@ -0,0 +1,7 @@ +export const Route = createFileRoute({ + component: LayoutAComponent, +}) + +function LayoutAComponent() { + return
I'm A!
+} diff --git a/examples/solid/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/examples/solid/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-b.tsx new file mode 100644 index 0000000000..2864ec1f28 --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/_pathlessLayout/_nested-layout/route-b.tsx @@ -0,0 +1,7 @@ +export const Route = createFileRoute({ + component: LayoutBComponent, +}) + +function LayoutBComponent() { + return
I'm B!
+} diff --git a/examples/solid/start-basic-static/src/routes/deferred.tsx b/examples/solid/start-basic-static/src/routes/deferred.tsx new file mode 100644 index 0000000000..fa945306b9 --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/deferred.tsx @@ -0,0 +1,62 @@ +import { Await } from '@tanstack/solid-router' +import { createServerFn } from '@tanstack/solid-start' +import { Suspense, createSignal } from 'solid-js' + +const personServerFn = createServerFn({ method: 'GET', type: 'static' }) + .validator((d: string) => d) + .handler(({ data: name }) => { + return { name, randomNumber: Math.floor(Math.random() * 100) } + }) + +const slowServerFn = createServerFn({ method: 'GET', type: 'static' }) + .validator((d: string) => d) + .handler(async ({ data: name }) => { + await new Promise((r) => setTimeout(r, 1000)) + return { name, randomNumber: Math.floor(Math.random() * 100) } + }) + +export const Route = createFileRoute({ + loader: async () => { + return { + deferredStuff: new Promise((r) => + setTimeout(() => r('Hello deferred!'), 2000), + ), + deferredPerson: slowServerFn({ data: 'Tanner Linsley' }), + person: await personServerFn({ data: 'John Doe' }), + } + }, + component: Deferred, +}) + +function Deferred() { + const [count, setCount] = createSignal(0) + const loaderData = Route.useLoaderData() + + return ( +
+
+ {loaderData().person.name} - {loaderData().person.randomNumber} +
+ Loading person...
}> + ( +
+ {data.name} - {data.randomNumber} +
+ )} + /> + + Loading stuff...
}> +

{data}

} + /> + +
Count: {count()}
+
+ +
+
+ ) +} diff --git a/examples/solid/start-basic-static/src/routes/index.tsx b/examples/solid/start-basic-static/src/routes/index.tsx new file mode 100644 index 0000000000..2f35891abb --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/index.tsx @@ -0,0 +1,11 @@ +export const Route = createFileRoute({ + component: Home, +}) + +function Home() { + return ( +
+

Welcome Home!!!

+
+ ) +} diff --git a/examples/solid/start-basic-static/src/routes/posts.$postId.tsx b/examples/solid/start-basic-static/src/routes/posts.$postId.tsx new file mode 100644 index 0000000000..b33d1ae326 --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/posts.$postId.tsx @@ -0,0 +1,38 @@ +import { ErrorComponent, Link } from '@tanstack/solid-router' +import { fetchPost } from '../utils/posts' +import type { ErrorComponentProps } from '@tanstack/solid-router' +import { NotFound } from '~/components/NotFound' + +export const Route = createFileRoute({ + loader: ({ params: { postId } }) => fetchPost({ data: postId }), + errorComponent: PostErrorComponent, + component: PostComponent, + notFoundComponent: () => { + return Post not found + }, +}) + +export function PostErrorComponent({ error }: ErrorComponentProps) { + return +} + +function PostComponent() { + const post = Route.useLoaderData() + + return ( +
+

{post.title}

+
{post.body}
+ + Deep View + +
+ ) +} diff --git a/examples/solid/start-basic-static/src/routes/posts.index.tsx b/examples/solid/start-basic-static/src/routes/posts.index.tsx new file mode 100644 index 0000000000..13529228bb --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/posts.index.tsx @@ -0,0 +1,7 @@ +export const Route = createFileRoute({ + component: PostsIndexComponent, +}) + +function PostsIndexComponent() { + return
Select a post.
+} diff --git a/examples/solid/start-basic-static/src/routes/posts.tsx b/examples/solid/start-basic-static/src/routes/posts.tsx new file mode 100644 index 0000000000..4f0b47fa08 --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/posts.tsx @@ -0,0 +1,38 @@ +import { Link, Outlet } from '@tanstack/solid-router' +import { fetchPosts } from '../utils/posts' + +export const Route = createFileRoute({ + loader: async () => fetchPosts(), + component: PostsComponent, +}) + +function PostsComponent() { + const posts = Route.useLoaderData() + + return ( +
+
    + {[...posts(), { id: 'i-do-not-exist', title: 'Non-existent Post' }].map( + (post) => { + return ( +
  • + +
    {post.title.substring(0, 20)}
    + +
  • + ) + }, + )} +
+
+ +
+ ) +} diff --git a/examples/solid/start-basic-static/src/routes/posts_.$postId.deep.tsx b/examples/solid/start-basic-static/src/routes/posts_.$postId.deep.tsx new file mode 100644 index 0000000000..b36e86eb53 --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/posts_.$postId.deep.tsx @@ -0,0 +1,26 @@ +import { Link } from '@tanstack/solid-router' +import { fetchPost } from '../utils/posts' +import { PostErrorComponent } from './posts.$postId' + +export const Route = createFileRoute({ + loader: ({ params: { postId } }) => + fetchPost({ + data: postId, + }), + errorComponent: PostErrorComponent, + component: PostDeepComponent, +}) + +function PostDeepComponent() { + const post = Route.useLoaderData() + + return ( +
+ + ← All Posts + +

{post().title}

+
{post().body}
+
+ ) +} diff --git a/examples/solid/start-basic-static/src/routes/redirect.tsx b/examples/solid/start-basic-static/src/routes/redirect.tsx new file mode 100644 index 0000000000..d80d290638 --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/redirect.tsx @@ -0,0 +1,9 @@ +import { redirect } from '@tanstack/solid-router' + +export const Route = createFileRoute({ + beforeLoad: async () => { + throw redirect({ + to: '/posts', + }) + }, +}) diff --git a/examples/solid/start-basic-static/src/routes/users.$userId.tsx b/examples/solid/start-basic-static/src/routes/users.$userId.tsx new file mode 100644 index 0000000000..414436f8d5 --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/users.$userId.tsx @@ -0,0 +1,49 @@ +import { ErrorComponent } from '@tanstack/solid-router' +import axios from 'redaxios' +import { createServerFn } from '@tanstack/solid-start' +import type { ErrorComponentProps } from '@tanstack/solid-router' +import type { User } from '~/utils/users' +import { NotFound } from '~/components/NotFound' + +const fetchUser = createServerFn({ method: 'GET', type: 'static' }) + .validator((d: string) => d) + .handler(async ({ data: userId }) => { + return axios + .get('https://jsonplaceholder.typicode.com/users/' + userId) + .then((d) => ({ + id: d.data.id, + name: d.data.name, + email: d.data.email, + })) + .catch((e) => { + throw new Error('Failed to fetch user') + }) + }) + +export const Route = createFileRoute({ + loader: ({ params: { userId } }) => fetchUser({ data: userId }), + errorComponent: UserErrorComponent, + component: UserComponent, + notFoundComponent: () => { + return User not found + }, +}) + +export function UserErrorComponent({ error }: ErrorComponentProps) { + return +} + +function UserComponent() { + const user = Route.useLoaderData() + + if ('error' in user()) { + return User not found + } + + return ( +
+

{user().name}

+
{user().email}
+
+ ) +} diff --git a/examples/solid/start-basic-static/src/routes/users.index.tsx b/examples/solid/start-basic-static/src/routes/users.index.tsx new file mode 100644 index 0000000000..662e8b6c68 --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/users.index.tsx @@ -0,0 +1,7 @@ +export const Route = createFileRoute({ + component: UsersIndexComponent, +}) + +function UsersIndexComponent() { + return
Select a user.
+} diff --git a/examples/solid/start-basic-static/src/routes/users.tsx b/examples/solid/start-basic-static/src/routes/users.tsx new file mode 100644 index 0000000000..440d3c93a5 --- /dev/null +++ b/examples/solid/start-basic-static/src/routes/users.tsx @@ -0,0 +1,54 @@ +import { Link, Outlet } from '@tanstack/solid-router' +import axios from 'redaxios' +import { createServerFn } from '@tanstack/solid-start' +import type { User } from '../utils/users' + +const fetchUsers = createServerFn({ method: 'GET', type: 'static' }).handler( + async () => { + console.info('Fetching users...') + const res = await axios.get>( + 'https://jsonplaceholder.typicode.com/users', + ) + + return res.data + .slice(0, 10) + .map((u) => ({ id: u.id, name: u.name, email: u.email })) + }, +) + +export const Route = createFileRoute({ + loader: async () => fetchUsers(), + component: UsersComponent, +}) + +function UsersComponent() { + const users = Route.useLoaderData() + + return ( +
+
    + {[ + ...users(), + { id: 'i-do-not-exist', name: 'Non-existent User', email: '' }, + ].map((user) => { + return ( +
  • + +
    {user.name}
    + +
  • + ) + })} +
+
+ +
+ ) +} diff --git a/examples/solid/start-basic-static/src/styles/app.css b/examples/solid/start-basic-static/src/styles/app.css new file mode 100644 index 0000000000..d6426ccb72 --- /dev/null +++ b/examples/solid/start-basic-static/src/styles/app.css @@ -0,0 +1,14 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + html, + body { + @apply text-gray-900 bg-gray-50 dark:bg-gray-950 dark:text-gray-200; + } + + .using-mouse * { + outline: none !important; + } +} diff --git a/examples/solid/start-basic-static/src/tanstack-start.d.ts b/examples/solid/start-basic-static/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/solid/start-basic-static/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/solid/start-basic-static/src/utils/loggingMiddleware.tsx b/examples/solid/start-basic-static/src/utils/loggingMiddleware.tsx new file mode 100644 index 0000000000..c2362c834c --- /dev/null +++ b/examples/solid/start-basic-static/src/utils/loggingMiddleware.tsx @@ -0,0 +1,42 @@ +import { createMiddleware } from '@tanstack/solid-start' + +export const logMiddleware = createMiddleware({ type: 'function' }) + .middleware([ + createMiddleware({ type: 'function' }) + .client(async (ctx) => { + const clientTime = new Date() + + return await ctx.next({ + context: { + clientTime, + }, + sendContext: { + clientTime, + }, + }) + }) + .server(async (ctx) => { + const serverTime = new Date() + + return await ctx.next({ + sendContext: { + serverTime, + durationToServer: + serverTime.getTime() - ctx.context.clientTime.getTime(), + }, + }) + }), + ]) + .client(async (options) => { + const result = await options.next() + + const now = new Date() + + console.log('Client Req/Res:', { + duration: result.context.clientTime.getTime() - now.getTime(), + durationToServer: result.context.durationToServer, + durationFromServer: now.getTime() - result.context.serverTime.getTime(), + }) + + return result + }) diff --git a/examples/solid/start-basic-static/src/utils/posts.tsx b/examples/solid/start-basic-static/src/utils/posts.tsx new file mode 100644 index 0000000000..204230b7fe --- /dev/null +++ b/examples/solid/start-basic-static/src/utils/posts.tsx @@ -0,0 +1,37 @@ +import { createServerFn } from '@tanstack/solid-start' +import axios from 'redaxios' +import { notFound } from '@tanstack/solid-router' +import { logMiddleware } from './loggingMiddleware' + +export type PostType = { + id: string + title: string + body: string +} + +export const fetchPost = createServerFn({ method: 'GET', type: 'static' }) + .middleware([logMiddleware]) + .validator((d: string) => d) + .handler(async ({ data }) => { + console.info(`Fetching post with id ${data}...`) + const post = await axios + .get(`https://jsonplaceholder.typicode.com/posts/${data}`) + .catch((err) => { + if (err.status === 404) { + throw notFound() + } + throw err + }) + .then((r) => r.data) + + return post + }) + +export const fetchPosts = createServerFn({ method: 'GET', type: 'static' }) + .middleware([logMiddleware]) + .handler(async () => { + console.info('Fetching posts...') + return axios + .get>('https://jsonplaceholder.typicode.com/posts') + .then((r) => r.data.slice(0, 10)) + }) diff --git a/examples/solid/start-basic-static/src/utils/seo.ts b/examples/solid/start-basic-static/src/utils/seo.ts new file mode 100644 index 0000000000..d18ad84b74 --- /dev/null +++ b/examples/solid/start-basic-static/src/utils/seo.ts @@ -0,0 +1,33 @@ +export const seo = ({ + title, + description, + keywords, + image, +}: { + title: string + description?: string + image?: string + keywords?: string +}) => { + const tags = [ + { title }, + { name: 'description', content: description }, + { name: 'keywords', content: keywords }, + { name: 'twitter:title', content: title }, + { name: 'twitter:description', content: description }, + { name: 'twitter:creator', content: '@tannerlinsley' }, + { name: 'twitter:site', content: '@tannerlinsley' }, + { name: 'og:type', content: 'website' }, + { name: 'og:title', content: title }, + { name: 'og:description', content: description }, + ...(image + ? [ + { name: 'twitter:image', content: image }, + { name: 'twitter:card', content: 'summary_large_image' }, + { name: 'og:image', content: image }, + ] + : []), + ] + + return tags +} diff --git a/examples/solid/start-basic-static/src/utils/users.tsx b/examples/solid/start-basic-static/src/utils/users.tsx new file mode 100644 index 0000000000..b810f455fe --- /dev/null +++ b/examples/solid/start-basic-static/src/utils/users.tsx @@ -0,0 +1,7 @@ +export type User = { + id: number + name: string + email: string +} + +export const DEPLOY_URL = 'http://localhost:3000' diff --git a/examples/solid/start-basic-static/tailwind.config.cjs b/examples/solid/start-basic-static/tailwind.config.cjs new file mode 100644 index 0000000000..10c9224f8c --- /dev/null +++ b/examples/solid/start-basic-static/tailwind.config.cjs @@ -0,0 +1,4 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ['./src/**/*.{js,ts,jsx,tsx}'], +} diff --git a/examples/solid/start-basic-static/tsconfig.json b/examples/solid/start-basic-static/tsconfig.json new file mode 100644 index 0000000000..a40235b863 --- /dev/null +++ b/examples/solid/start-basic-static/tsconfig.json @@ -0,0 +1,23 @@ +{ + "include": ["**/*.ts", "**/*.tsx"], + "compilerOptions": { + "strict": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "isolatedModules": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "target": "ES2022", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "paths": { + "~/*": ["./src/*"] + }, + "noEmit": true + } +} diff --git a/examples/solid/start-basic-static/vite.config.ts b/examples/solid/start-basic-static/vite.config.ts new file mode 100644 index 0000000000..213bd9189e --- /dev/null +++ b/examples/solid/start-basic-static/vite.config.ts @@ -0,0 +1,19 @@ +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart({ + spa: { + enabled: true, + }, + }), + ], +}) diff --git a/examples/solid/start-basic/.tanstack-start/server-routes/routeTree.gen.ts b/examples/solid/start-basic/.tanstack-start/server-routes/routeTree.gen.ts new file mode 100644 index 0000000000..e36fccb479 --- /dev/null +++ b/examples/solid/start-basic/.tanstack-start/server-routes/routeTree.gen.ts @@ -0,0 +1,155 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import type { + FileRoutesByPath, + CreateServerFileRoute, +} from '@tanstack/solid-start/server' +import { + createServerRoute, + createServerFileRoute, +} from '@tanstack/solid-start/server' + +import { ServerRoute as ApiUsersRouteImport } from './../../src/routes/api/users' +import { ServerRoute as ApiUsersUserIdRouteImport } from './../../src/routes/api/users.$userId' + +// Create/Update Routes + +const rootRoute = createServerRoute() + +const ApiUsersRoute = ApiUsersRouteImport.update({ + id: '/api/users', + path: '/api/users', + getParentRoute: () => rootRoute, +} as any) + +const ApiUsersUserIdRoute = ApiUsersUserIdRouteImport.update({ + id: '/$userId', + path: '/$userId', + getParentRoute: () => ApiUsersRoute, +} as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/solid-start/server' { + interface FileRoutesByPath { + '/api/users': { + id: '/api/users' + path: '/api/users' + fullPath: '/api/users' + preLoaderRoute: typeof ApiUsersRouteImport + parentRoute: typeof rootRoute + } + '/api/users/$userId': { + id: '/api/users/$userId' + path: '/$userId' + fullPath: '/api/users/$userId' + preLoaderRoute: typeof ApiUsersUserIdRouteImport + parentRoute: typeof ApiUsersRouteImport + } + } +} + +// Add type-safety to the createFileRoute function across the route tree + +declare module './../../src/routes/api/users' { + const createServerFileRoute: CreateServerFileRoute< + FileRoutesByPath['/api/users']['parentRoute'], + FileRoutesByPath['/api/users']['id'], + FileRoutesByPath['/api/users']['path'], + FileRoutesByPath['/api/users']['fullPath'], + ApiUsersRouteChildren + > +} +declare module './../../src/routes/api/users.$userId' { + const createServerFileRoute: CreateServerFileRoute< + FileRoutesByPath['/api/users/$userId']['parentRoute'], + FileRoutesByPath['/api/users/$userId']['id'], + FileRoutesByPath['/api/users/$userId']['path'], + FileRoutesByPath['/api/users/$userId']['fullPath'], + unknown + > +} + +// Create and export the route tree + +interface ApiUsersRouteChildren { + ApiUsersUserIdRoute: typeof ApiUsersUserIdRoute +} + +const ApiUsersRouteChildren: ApiUsersRouteChildren = { + ApiUsersUserIdRoute: ApiUsersUserIdRoute, +} + +const ApiUsersRouteWithChildren = ApiUsersRoute._addFileChildren( + ApiUsersRouteChildren, +) + +export interface FileRoutesByFullPath { + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$userId': typeof ApiUsersUserIdRoute +} + +export interface FileRoutesByTo { + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$userId': typeof ApiUsersUserIdRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/api/users': typeof ApiUsersRouteWithChildren + '/api/users/$userId': typeof ApiUsersUserIdRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/api/users' | '/api/users/$userId' + fileRoutesByTo: FileRoutesByTo + to: '/api/users' | '/api/users/$userId' + id: '__root__' | '/api/users' | '/api/users/$userId' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + ApiUsersRoute: typeof ApiUsersRouteWithChildren +} + +const rootRouteChildren: RootRouteChildren = { + ApiUsersRoute: ApiUsersRouteWithChildren, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/api/users" + ] + }, + "/api/users": { + "filePath": "api/users.ts", + "children": [ + "/api/users/$userId" + ] + }, + "/api/users/$userId": { + "filePath": "api/users.$userId.ts", + "parent": "/api/users" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/examples/solid/start-basic/app.config.ts b/examples/solid/start-basic/app.config.ts deleted file mode 100644 index 2a06e3d3f0..0000000000 --- a/examples/solid/start-basic/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/solid-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/examples/solid/start-basic/package.json b/examples/solid/start-basic/package.json index 9503c2499a..2580875d57 100644 --- a/examples/solid/start-basic/package.json +++ b/examples/solid/start-basic/package.json @@ -4,19 +4,18 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { - "@tanstack/solid-router": "^1.120.3", - "@tanstack/solid-router-devtools": "^1.120.3", - "@tanstack/solid-start": "^1.120.3", + "@tanstack/solid-router": "^1.121.0-alpha.11", + "@tanstack/solid-router-devtools": "^1.121.0-alpha.11", + "@tanstack/solid-start": "^1.121.0-alpha.11", "solid-js": "^1.9.5", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vite": "6.1.4", - "vinxi": "0.5.3" + "vite": "^6.3.5" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/solid/start-basic/src/api.ts b/examples/solid/start-basic/src/api.ts deleted file mode 100644 index ed511bcd26..0000000000 --- a/examples/solid/start-basic/src/api.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { - createStartAPIHandler, - defaultAPIFileRouteHandler, -} from '@tanstack/solid-start/api' - -export default createStartAPIHandler(defaultAPIFileRouteHandler) diff --git a/examples/solid/start-basic/src/client.tsx b/examples/solid/start-basic/src/client.tsx deleted file mode 100644 index ba0f02fac0..0000000000 --- a/examples/solid/start-basic/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrate } from 'solid-js/web' -import { StartClient } from '@tanstack/solid-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrate(() => , document.body) diff --git a/examples/solid/start-basic/src/components/DefaultCatchBoundary.tsx b/examples/solid/start-basic/src/components/DefaultCatchBoundary.tsx index 0dff3919fd..bf759681a4 100644 --- a/examples/solid/start-basic/src/components/DefaultCatchBoundary.tsx +++ b/examples/solid/start-basic/src/components/DefaultCatchBoundary.tsx @@ -28,7 +28,7 @@ export function DefaultCatchBoundary({ error }: ErrorComponentProps) { > Try Again - {isRoot() ? ( + {isRoot ? ( rootRoute, } as any) -const RedirectRoute = RedirectImport.update({ +const RedirectRoute = RedirectRouteImport.update({ id: '/redirect', path: '/redirect', getParentRoute: () => rootRoute, } as any) -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const DeferredRoute = DeferredImport.update({ +const DeferredRoute = DeferredRouteImport.update({ id: '/deferred', path: '/deferred', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const UsersIndexRoute = UsersIndexImport.update({ +const UsersIndexRoute = UsersIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => UsersRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const UsersUserIdRoute = UsersUserIdImport.update({ +const UsersUserIdRoute = UsersUserIdRouteImport.update({ id: '/$userId', path: '/$userId', getParentRoute: () => UsersRoute, } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const PathlessLayoutNestedLayoutRoute = PathlessLayoutNestedLayoutImport.update( - { +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ id: '/_nested-layout', getParentRoute: () => PathlessLayoutRoute, - } as any, -) + } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/posts_/$postId/deep', path: '/posts/$postId/deep', getParentRoute: () => rootRoute, } as any) const PathlessLayoutNestedLayoutRouteBRoute = - PathlessLayoutNestedLayoutRouteBImport.update({ + PathlessLayoutNestedLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutNestedLayoutRoute, } as any) const PathlessLayoutNestedLayoutRouteARoute = - PathlessLayoutNestedLayoutRouteAImport.update({ + PathlessLayoutNestedLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutNestedLayoutRoute, @@ -122,103 +123,232 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/deferred': { id: '/deferred' path: '/deferred' fullPath: '/deferred' - preLoaderRoute: typeof DeferredImport + preLoaderRoute: typeof DeferredRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/redirect': { id: '/redirect' path: '/redirect' fullPath: '/redirect' - preLoaderRoute: typeof RedirectImport + preLoaderRoute: typeof RedirectRouteImport parentRoute: typeof rootRoute } '/users': { id: '/users' path: '/users' fullPath: '/users' - preLoaderRoute: typeof UsersImport + preLoaderRoute: typeof UsersRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout/_nested-layout': { id: '/_pathlessLayout/_nested-layout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutNestedLayoutImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/users/$userId': { id: '/users/$userId' path: '/$userId' fullPath: '/users/$userId' - preLoaderRoute: typeof UsersUserIdImport - parentRoute: typeof UsersImport + preLoaderRoute: typeof UsersUserIdRouteImport + parentRoute: typeof UsersRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/users/': { id: '/users/' path: '/' fullPath: '/users/' - preLoaderRoute: typeof UsersIndexImport - parentRoute: typeof UsersImport + preLoaderRoute: typeof UsersIndexRouteImport + parentRoute: typeof UsersRouteImport } '/_pathlessLayout/_nested-layout/route-a': { id: '/_pathlessLayout/_nested-layout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteAImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/_pathlessLayout/_nested-layout/route-b': { id: '/_pathlessLayout/_nested-layout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/posts_/$postId/deep': { id: '/posts_/$postId/deep' path: '/posts/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport + preLoaderRoute: typeof PostsPostIdDeepRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_pathlessLayout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout', + FileRoutesByPath['/_pathlessLayout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout']['id'], + FileRoutesByPath['/_pathlessLayout']['path'], + FileRoutesByPath['/_pathlessLayout']['fullPath'] + > +} +declare module './routes/deferred' { + const createFileRoute: CreateFileRoute< + '/deferred', + FileRoutesByPath['/deferred']['parentRoute'], + FileRoutesByPath['/deferred']['id'], + FileRoutesByPath['/deferred']['path'], + FileRoutesByPath['/deferred']['fullPath'] + > +} +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/redirect' { + const createFileRoute: CreateFileRoute< + '/redirect', + FileRoutesByPath['/redirect']['parentRoute'], + FileRoutesByPath['/redirect']['id'], + FileRoutesByPath['/redirect']['path'], + FileRoutesByPath['/redirect']['fullPath'] + > +} +declare module './routes/users' { + const createFileRoute: CreateFileRoute< + '/users', + FileRoutesByPath['/users']['parentRoute'], + FileRoutesByPath['/users']['id'], + FileRoutesByPath['/users']['path'], + FileRoutesByPath['/users']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout', + FileRoutesByPath['/_pathlessLayout/_nested-layout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/users.$userId' { + const createFileRoute: CreateFileRoute< + '/users/$userId', + FileRoutesByPath['/users/$userId']['parentRoute'], + FileRoutesByPath['/users/$userId']['id'], + FileRoutesByPath['/users/$userId']['path'], + FileRoutesByPath['/users/$userId']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/users.index' { + const createFileRoute: CreateFileRoute< + '/users/', + FileRoutesByPath['/users/']['parentRoute'], + FileRoutesByPath['/users/']['id'], + FileRoutesByPath['/users/']['path'], + FileRoutesByPath['/users/']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-a' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-a', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-b' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-b', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['fullPath'] + > +} +declare module './routes/posts_.$postId.deep' { + const createFileRoute: CreateFileRoute< + '/posts_/$postId/deep', + FileRoutesByPath['/posts_/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > +} + // Create and export the route tree interface PathlessLayoutNestedLayoutRouteChildren { diff --git a/examples/solid/start-basic/src/routes/__root.tsx b/examples/solid/start-basic/src/routes/__root.tsx index a9380d3209..374a4fb944 100644 --- a/examples/solid/start-basic/src/routes/__root.tsx +++ b/examples/solid/start-basic/src/routes/__root.tsx @@ -1,6 +1,13 @@ -import { Link, Outlet, createRootRoute } from '@tanstack/solid-router' - -import { TanStackRouterDevtoolsInProd } from '@tanstack/solid-router-devtools' +import { + HeadContent, + Link, + Outlet, + Scripts, + createRootRoute, +} from '@tanstack/solid-router' +import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools' +import type * as Solid from 'solid-js' +import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary' import { NotFound } from '~/components/NotFound' import appCss from '~/styles/app.css?url' import { seo } from '~/utils/seo' @@ -8,6 +15,9 @@ import { seo } from '~/utils/seo' export const Route = createRootRoute({ head: () => ({ meta: [ + { + charset: 'utf-8', + }, { name: 'viewport', content: 'width=device-width, initial-scale=1', @@ -41,14 +51,29 @@ export const Route = createRootRoute({ { rel: 'icon', href: '/favicon.ico' }, ], }), - errorComponent: (props) =>

{props.error.stack}

, + errorComponent: (props) => { + return ( + + + + ) + }, notFoundComponent: () => , component: RootComponent, }) function RootComponent() { + return ( + + + + ) +} + +function RootDocument({ children }: { children: Solid.JSX.Element }) { return ( <> +
{' '} - Deferred + Pathless Layout {' '} - redirect + Deferred {' '}
- - +
+ {children} + + ) } diff --git a/examples/solid/start-basic/src/routes/_pathlessLayout.tsx b/examples/solid/start-basic/src/routes/_pathlessLayout.tsx index af197bc038..c549175638 100644 --- a/examples/solid/start-basic/src/routes/_pathlessLayout.tsx +++ b/examples/solid/start-basic/src/routes/_pathlessLayout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/_pathlessLayout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx b/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx index 24e4b2545b..03bcac9d47 100644 --- a/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx +++ b/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx index a22902a271..a0bd5240b7 100644 --- a/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +++ b/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx @@ -1,10 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')( - { - component: LayoutAComponent, - }, -) +export const Route = createFileRoute({ + component: LayoutAComponent, +}) function LayoutAComponent() { return
I'm A!
diff --git a/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx index 36231d2153..2864ec1f28 100644 --- a/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +++ b/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx @@ -1,10 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')( - { - component: LayoutBComponent, - }, -) +export const Route = createFileRoute({ + component: LayoutBComponent, +}) function LayoutBComponent() { return
I'm B!
diff --git a/examples/solid/start-basic/src/routes/api/users.$id.ts b/examples/solid/start-basic/src/routes/api/users.$id.ts deleted file mode 100644 index b1786f6a30..0000000000 --- a/examples/solid/start-basic/src/routes/api/users.$id.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { json } from '@tanstack/solid-start' -import { createAPIFileRoute } from '@tanstack/solid-start/api' -import axios from 'redaxios' -import type { User } from '../../utils/users' - -export const APIRoute = createAPIFileRoute('/api/users/$id')({ - GET: async ({ request, params }) => { - console.info(`Fetching users by id=${params.id}... @`, request.url) - try { - const res = await axios.get( - 'https://jsonplaceholder.typicode.com/users/' + params.id, - ) - - return json({ - id: res.data.id, - name: res.data.name, - email: res.data.email, - }) - } catch (e) { - console.error(e) - return json({ error: 'User not found' }, { status: 404 }) - } - }, -}) diff --git a/examples/solid/start-basic/src/routes/api/users.$userId.ts b/examples/solid/start-basic/src/routes/api/users.$userId.ts new file mode 100644 index 0000000000..69d966d982 --- /dev/null +++ b/examples/solid/start-basic/src/routes/api/users.$userId.ts @@ -0,0 +1,27 @@ +import { json } from '@tanstack/solid-start' +import type { User } from '~/utils/users' + +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ params, request }) => { + console.info(`Fetching users by id=${params.userId}... @`, request.url) + try { + const res = await fetch( + 'https://jsonplaceholder.typicode.com/users/' + params.userId, + ) + if (!res.ok) { + throw new Error('Failed to fetch user') + } + + const user = (await res.json()) as User + + return json({ + id: user.id, + name: user.name, + email: user.email, + }) + } catch (e) { + console.error(e) + return json({ error: 'User not found' }, { status: 404 }) + } + }, +}) diff --git a/examples/solid/start-basic/src/routes/api/users.ts b/examples/solid/start-basic/src/routes/api/users.ts index c10bcfc94a..c0a6a1a6a2 100644 --- a/examples/solid/start-basic/src/routes/api/users.ts +++ b/examples/solid/start-basic/src/routes/api/users.ts @@ -1,17 +1,58 @@ -import { json } from '@tanstack/solid-start' -import { createAPIFileRoute } from '@tanstack/solid-start/api' -import axios from 'redaxios' -import type { User } from '../../utils/users' +import { createMiddleware, json } from '@tanstack/solid-start' +import type { User } from '~/utils/users' -export const APIRoute = createAPIFileRoute('/api/users')({ - GET: async ({ request }) => { - console.info('Fetching users... @', request.url) - const res = await axios.get>( - 'https://jsonplaceholder.typicode.com/users', - ) - - const list = res.data.slice(0, 10) +const userLoggerMiddleware = createMiddleware({ type: 'request' }).server( + async ({ next, request }) => { + console.info('In: /users') + const result = await next() + result.response.headers.set('x-users', 'true') + console.info('Out: /users') + return result + }, +) - return json(list.map((u) => ({ id: u.id, name: u.name, email: u.email }))) +const testParentMiddleware = createMiddleware({ type: 'request' }).server( + async ({ next, request }) => { + console.info('In: testParentMiddleware') + const result = await next() + result.response.headers.set('x-test-parent', 'true') + console.info('Out: testParentMiddleware') + return result }, -}) +) + +const testMiddleware = createMiddleware({ type: 'request' }) + .middleware([testParentMiddleware]) + .server(async ({ next, request }) => { + console.info('In: testMiddleware') + const result = await next() + result.response.headers.set('x-test', 'true') + + // if (Math.random() > 0.5) { + // throw new Response(null, { + // status: 302, + // headers: { Location: 'https://www.google.com' }, + // }) + // } + + console.info('Out: testMiddleware') + return result + }) + +export const ServerRoute = createServerFileRoute() + .middleware([testMiddleware, userLoggerMiddleware, testParentMiddleware]) + .methods({ + GET: async ({ request }) => { + console.info('Fetching users... @', request.url) + const res = await fetch('https://jsonplaceholder.typicode.com/users') + if (!res.ok) { + throw new Error('Failed to fetch users') + } + + const data = (await res.json()) as Array + + const list = data.slice(0, 10) + + return json(list.map((u) => ({ id: u.id, name: u.name, email: u.email }))) + }, + }) diff --git a/examples/solid/start-basic/src/routes/deferred.tsx b/examples/solid/start-basic/src/routes/deferred.tsx index 1860f3af9a..c510571e5d 100644 --- a/examples/solid/start-basic/src/routes/deferred.tsx +++ b/examples/solid/start-basic/src/routes/deferred.tsx @@ -1,6 +1,6 @@ -import { Await, createFileRoute } from '@tanstack/solid-router' +import { Await } from '@tanstack/solid-router' import { createServerFn } from '@tanstack/solid-start' -import { createSignal, Suspense } from 'solid-js' +import { Suspense, createSignal } from 'solid-js' const personServerFn = createServerFn({ method: 'GET' }) .validator((d: string) => d) @@ -15,7 +15,7 @@ const slowServerFn = createServerFn({ method: 'GET' }) return { name, randomNumber: Math.floor(Math.random() * 100) } }) -export const Route = createFileRoute('/deferred')({ +export const Route = createFileRoute({ loader: async () => { return { deferredStuff: new Promise((r) => diff --git a/examples/solid/start-basic/src/routes/index.tsx b/examples/solid/start-basic/src/routes/index.tsx index a128aeca0e..2f35891abb 100644 --- a/examples/solid/start-basic/src/routes/index.tsx +++ b/examples/solid/start-basic/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/examples/solid/start-basic/src/routes/posts.$postId.tsx b/examples/solid/start-basic/src/routes/posts.$postId.tsx index d13735a4db..7d06791adb 100644 --- a/examples/solid/start-basic/src/routes/posts.$postId.tsx +++ b/examples/solid/start-basic/src/routes/posts.$postId.tsx @@ -1,9 +1,9 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' import { fetchPost } from '../utils/posts' import { NotFound } from '~/components/NotFound' import { PostErrorComponent } from '~/components/PostError' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, diff --git a/examples/solid/start-basic/src/routes/posts.index.tsx b/examples/solid/start-basic/src/routes/posts.index.tsx index 33d0386c19..13529228bb 100644 --- a/examples/solid/start-basic/src/routes/posts.index.tsx +++ b/examples/solid/start-basic/src/routes/posts.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/examples/solid/start-basic/src/routes/posts.tsx b/examples/solid/start-basic/src/routes/posts.tsx index 326372478f..4f0b47fa08 100644 --- a/examples/solid/start-basic/src/routes/posts.tsx +++ b/examples/solid/start-basic/src/routes/posts.tsx @@ -1,7 +1,7 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import { fetchPosts } from '../utils/posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: async () => fetchPosts(), component: PostsComponent, }) diff --git a/examples/solid/start-basic/src/routes/posts_.$postId.deep.tsx b/examples/solid/start-basic/src/routes/posts_.$postId.deep.tsx index 7c52bc19eb..b71b51e8cc 100644 --- a/examples/solid/start-basic/src/routes/posts_.$postId.deep.tsx +++ b/examples/solid/start-basic/src/routes/posts_.$postId.deep.tsx @@ -1,8 +1,8 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' import { fetchPost } from '../utils/posts' import { PostErrorComponent } from '~/components/PostError' -export const Route = createFileRoute('/posts_/$postId/deep')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost({ data: postId, diff --git a/examples/solid/start-basic/src/routes/redirect.tsx b/examples/solid/start-basic/src/routes/redirect.tsx index ca017f0635..d80d290638 100644 --- a/examples/solid/start-basic/src/routes/redirect.tsx +++ b/examples/solid/start-basic/src/routes/redirect.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, redirect } from '@tanstack/solid-router' +import { redirect } from '@tanstack/solid-router' -export const Route = createFileRoute('/redirect')({ +export const Route = createFileRoute({ beforeLoad: async () => { throw redirect({ to: '/posts', diff --git a/examples/solid/start-basic/src/routes/users.$userId.tsx b/examples/solid/start-basic/src/routes/users.$userId.tsx index a2d99fbf6b..9bdb09d835 100644 --- a/examples/solid/start-basic/src/routes/users.$userId.tsx +++ b/examples/solid/start-basic/src/routes/users.$userId.tsx @@ -1,18 +1,20 @@ -import { createFileRoute } from '@tanstack/solid-router' -import axios from 'redaxios' -import type { User } from '~/utils/users' -import { DEPLOY_URL } from '~/utils/users' -import { NotFound } from '~/components/NotFound' -import { UserErrorComponent } from '~/components/UserError' +import { NotFound } from 'src/components/NotFound' +import { UserErrorComponent } from 'src/components/UserError' -export const Route = createFileRoute('/users/$userId')({ +export const Route = createFileRoute({ loader: async ({ params: { userId } }) => { - return await axios - .get(DEPLOY_URL + '/api/users/' + userId) - .then((r) => r.data) - .catch(() => { - throw new Error('Failed to fetch user') - }) + try { + const res = await fetch('/api/users/' + userId) + if (!res.ok) { + throw new Error('Unexpected status code') + } + + const data = await res.json() + + return data + } catch { + throw new Error('Failed to fetch user') + } }, errorComponent: UserErrorComponent, component: UserComponent, @@ -28,6 +30,14 @@ function UserComponent() {

{user().name}

{user().email}
+
) } diff --git a/examples/solid/start-basic/src/routes/users.index.tsx b/examples/solid/start-basic/src/routes/users.index.tsx index bbc96801a9..f30b0712b9 100644 --- a/examples/solid/start-basic/src/routes/users.index.tsx +++ b/examples/solid/start-basic/src/routes/users.index.tsx @@ -1,9 +1,14 @@ -import { createFileRoute } from '@tanstack/solid-router' - -export const Route = createFileRoute('/users/')({ +export const Route = createFileRoute({ component: UsersIndexComponent, }) function UsersIndexComponent() { - return
Select a user.
+ return ( +
+ Select a user or{' '} + + view as JSON + +
+ ) } diff --git a/examples/solid/start-basic/src/routes/users.tsx b/examples/solid/start-basic/src/routes/users.tsx index 2caca046e0..c3a2a1fe15 100644 --- a/examples/solid/start-basic/src/routes/users.tsx +++ b/examples/solid/start-basic/src/routes/users.tsx @@ -1,16 +1,17 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' -import axios from 'redaxios' -import { DEPLOY_URL } from '../utils/users' +import { Link, Outlet } from '@tanstack/solid-router' import type { User } from '../utils/users' -export const Route = createFileRoute('/users')({ +export const Route = createFileRoute({ loader: async () => { - return await axios - .get>(DEPLOY_URL + '/api/users') - .then((r) => r.data) - .catch(() => { - throw new Error('Failed to fetch users') - }) + const res = await fetch('/api/users') + + if (!res.ok) { + throw new Error('Unexpected status code') + } + + const data = (await res.json()) as Array + + return data }, component: UsersComponent, }) diff --git a/examples/solid/start-basic/src/ssr.tsx b/examples/solid/start-basic/src/ssr.tsx deleted file mode 100644 index 6d10bea05f..0000000000 --- a/examples/solid/start-basic/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/solid-start/server' -import { getRouterManifest } from '@tanstack/solid-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/solid/start-basic/src/tanstack-start.d.ts b/examples/solid/start-basic/src/tanstack-start.d.ts new file mode 100644 index 0000000000..3adaf59556 --- /dev/null +++ b/examples/solid/start-basic/src/tanstack-start.d.ts @@ -0,0 +1,2 @@ +/// +import '../.tanstack-start/server-routes/routeTree.gen' diff --git a/examples/solid/start-basic/src/utils/loggingMiddleware.tsx b/examples/solid/start-basic/src/utils/loggingMiddleware.tsx index 928fedfd25..fae87c5965 100644 --- a/examples/solid/start-basic/src/utils/loggingMiddleware.tsx +++ b/examples/solid/start-basic/src/utils/loggingMiddleware.tsx @@ -1,6 +1,6 @@ import { createMiddleware } from '@tanstack/solid-start' -const preLogMiddleware = createMiddleware() +const preLogMiddleware = createMiddleware({ type: 'function' }) .client(async (ctx) => { const clientTime = new Date() @@ -25,7 +25,7 @@ const preLogMiddleware = createMiddleware() }) }) -export const logMiddleware = createMiddleware() +export const logMiddleware = createMiddleware({ type: 'function' }) .middleware([preLogMiddleware]) .client(async (ctx) => { const res = await ctx.next() diff --git a/examples/solid/start-basic/src/utils/posts.tsx b/examples/solid/start-basic/src/utils/posts.tsx index 96eaa78afc..e29706d38c 100644 --- a/examples/solid/start-basic/src/utils/posts.tsx +++ b/examples/solid/start-basic/src/utils/posts.tsx @@ -8,7 +8,7 @@ export type PostType = { body: string } -export const fetchPost = createServerFn({ method: 'GET' }) +export const fetchPost = createServerFn({ method: 'GET', type: 'static' }) .validator((d: string) => d) .handler(async ({ data }) => { console.info(`Fetching post with id ${data}...`) @@ -26,11 +26,12 @@ export const fetchPost = createServerFn({ method: 'GET' }) return post }) -export const fetchPosts = createServerFn({ method: 'GET' }).handler( - async () => { - console.info('Fetching posts...') - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) - }, -) +export const fetchPosts = createServerFn({ + method: 'GET', + type: 'static', +}).handler(async () => { + console.info('Fetching posts...') + return axios + .get>('https://jsonplaceholder.typicode.com/posts') + .then((r) => r.data.slice(0, 10)) +}) diff --git a/examples/solid/start-basic/src/utils/users.tsx b/examples/solid/start-basic/src/utils/users.tsx index b810f455fe..7ba645b383 100644 --- a/examples/solid/start-basic/src/utils/users.tsx +++ b/examples/solid/start-basic/src/utils/users.tsx @@ -3,5 +3,3 @@ export type User = { name: string email: string } - -export const DEPLOY_URL = 'http://localhost:3000' diff --git a/examples/solid/start-basic/vite.config.ts b/examples/solid/start-basic/vite.config.ts new file mode 100644 index 0000000000..3af67d62ad --- /dev/null +++ b/examples/solid/start-basic/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart({}), + ], +}) diff --git a/package.json b/package.json index 9ac5606a3a..9798cfeaba 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "rimraf": "^6.0.1", "tinyglobby": "^0.2.12", "typescript": "^5.8.2", - "vite": "6.1.4", + "vite": "6.3.5", "vitest": "^3.0.6", "typescript53": "npm:typescript@5.3", "typescript54": "npm:typescript@5.4", @@ -107,12 +107,10 @@ "@tanstack/solid-start-plugin": "workspace:*", "@tanstack/solid-start-router-manifest": "workspace:*", "@tanstack/solid-start-server": "workspace:*", - "@tanstack/start-api-routes": "workspace:*", "@tanstack/start-server-functions-fetcher": "workspace:*", - "@tanstack/start-server-functions-handler": "workspace:*", "@tanstack/start-server-functions-client": "workspace:*", - "@tanstack/start-server-functions-ssr": "workspace:*", "@tanstack/start-server-functions-server": "workspace:*", + "@tanstack/start-plugin-core": "workspace:*", "@tanstack/start-client-core": "workspace:*", "@tanstack/start-server-core": "workspace:*", "@tanstack/eslint-plugin-router": "workspace:*", diff --git a/packages/arktype-adapter/package.json b/packages/arktype-adapter/package.json index ebe26da7e3..56c99f6f71 100644 --- a/packages/arktype-adapter/package.json +++ b/packages/arktype-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/arktype-adapter", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/directive-functions-plugin/package.json b/packages/directive-functions-plugin/package.json index 7b07f0e0d4..c857c27d07 100644 --- a/packages/directive-functions-plugin/package.json +++ b/packages/directive-functions-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/directive-functions-plugin", - "version": "1.119.2", + "version": "1.121.0-alpha.2", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -74,14 +74,16 @@ "@babel/types": "^7.26.8", "@tanstack/router-utils": "workspace:^", "babel-dead-code-elimination": "^1.0.10", - "dedent": "^1.5.3", - "tiny-invariant": "^1.3.3", - "vite": "6.1.4" + "tiny-invariant": "^1.3.3" }, "devDependencies": { "@types/babel__code-frame": "^7.0.6", "@types/babel__core": "^7.20.5", "@types/babel__template": "^7.4.4", - "@types/babel__traverse": "^7.20.6" + "@types/babel__traverse": "^7.20.6", + "vite": "^6.0.0" + }, + "peerDependencies": { + "vite": ">=6.0.0" } } diff --git a/packages/directive-functions-plugin/src/compilers.ts b/packages/directive-functions-plugin/src/compilers.ts index 463f5e879e..43830231b9 100644 --- a/packages/directive-functions-plugin/src/compilers.ts +++ b/packages/directive-functions-plugin/src/compilers.ts @@ -40,6 +40,8 @@ export type CompileDirectivesOpts = ParseAstOptions & { }) => string replacer: ReplacerFn // devSplitImporter: string + filename: string + root: string } function buildDirectiveSplitParam(opts: CompileDirectivesOpts) { @@ -230,6 +232,8 @@ export function findDirectives( directiveLabel: string replacer?: ReplacerFn directiveSplitParam: string + filename: string + root: string }, ): Record { const directiveFnsById: Record = {} diff --git a/packages/directive-functions-plugin/src/index.ts b/packages/directive-functions-plugin/src/index.ts index 25ed1df746..d0fd8aee06 100644 --- a/packages/directive-functions-plugin/src/index.ts +++ b/packages/directive-functions-plugin/src/index.ts @@ -15,23 +15,28 @@ export type { ReplacerFn, } from './compilers' -export type DirectiveFunctionsViteOptions = Pick< +export type DirectiveFunctionsViteEnvOptions = Pick< CompileDirectivesOpts, - 'directive' | 'directiveLabel' | 'getRuntimeCode' | 'replacer' - // | 'devSplitImporter' + 'getRuntimeCode' | 'replacer' > & { envLabel: string } +export type DirectiveFunctionsViteOptions = Pick< + CompileDirectivesOpts, + 'directive' | 'directiveLabel' +> & + DirectiveFunctionsViteEnvOptions & { + onDirectiveFnsById?: (directiveFnsById: Record) => void + } + const createDirectiveRx = (directive: string) => new RegExp(`"${directive}"|'${directive}'`, 'gm') export function TanStackDirectiveFunctionsPlugin( - opts: DirectiveFunctionsViteOptions & { - onDirectiveFnsById?: (directiveFnsById: Record) => void - }, + opts: DirectiveFunctionsViteOptions, ): Plugin { - let ROOT: string = process.cwd() + let root: string = process.cwd() const directiveRx = createDirectiveRx(opts.directive) @@ -39,36 +44,123 @@ export function TanStackDirectiveFunctionsPlugin( name: 'tanstack-start-directive-vite-plugin', enforce: 'pre', configResolved: (config) => { - ROOT = config.root + root = config.root }, transform(code, id) { - const url = pathToFileURL(id) - url.searchParams.delete('v') - id = fileURLToPath(url).replace(/\\/g, '/') + return transformCode({ ...opts, code, id, directiveRx, root }) + }, + } +} - if (!code.match(directiveRx)) { - return null - } +export type DirectiveFunctionsVitePluginEnvOptions = Pick< + CompileDirectivesOpts, + 'directive' | 'directiveLabel' +> & { + environments: { + client: DirectiveFunctionsViteEnvOptions & { envName?: string } + server: DirectiveFunctionsViteEnvOptions & { envName?: string } + } + onDirectiveFnsById?: (directiveFnsById: Record) => void +} - if (debug) console.info(`${opts.envLabel}: Compiling Directives: `, id) +export function TanStackDirectiveFunctionsPluginEnv( + opts: DirectiveFunctionsVitePluginEnvOptions, +): Plugin { + opts = { + ...opts, + environments: { + client: { + envName: 'client', + ...opts.environments.client, + }, + server: { + envName: 'server', + ...opts.environments.server, + }, + }, + } - const { compiledResult, directiveFnsById } = compileDirectives({ + let root: string = process.cwd() + + const directiveRx = createDirectiveRx(opts.directive) + + return { + name: 'tanstack-start-directive-vite-plugin', + enforce: 'pre', + buildStart() { + root = this.environment.config.root + }, + // applyToEnvironment(env) { + // return [ + // opts.environments.client.envName, + // opts.environments.server.envName, + // ].includes(env.name) + // }, + transform(code, id) { + const envOptions = [ + opts.environments.client, + opts.environments.server, + ].find((e) => e.envName === this.environment.name) + + if (!envOptions) { + throw new Error(`Environment ${this.environment.name} not found`) + } + + return transformCode({ ...opts, + ...envOptions, code, - root: ROOT, - filename: id, - // globalThis.app currently refers to Vinxi's app instance. In the future, it can just be the - // vite dev server instance we get from Nitro. + id, + directiveRx, + root, }) + }, + } +} - opts.onDirectiveFnsById?.(directiveFnsById) +function transformCode({ + code, + id, + directiveRx, + envLabel, + directive, + directiveLabel, + getRuntimeCode, + replacer, + onDirectiveFnsById, + root, +}: DirectiveFunctionsViteOptions & { + code: string + id: string + directiveRx: RegExp + root: string +}) { + const url = pathToFileURL(id) + url.searchParams.delete('v') + id = fileURLToPath(url).replace(/\\/g, '/') - if (debug) { - logDiff(code, compiledResult.code) - console.log('Output:\n', compiledResult.code + '\n\n') - } + if (!code.match(directiveRx)) { + return null + } - return compiledResult - }, + if (debug) console.info(`${envLabel}: Compiling Directives: `, id) + + const { compiledResult, directiveFnsById } = compileDirectives({ + directive, + directiveLabel, + getRuntimeCode, + replacer, + code, + root, + filename: id, + }) + + onDirectiveFnsById?.(directiveFnsById) + + if (debug) { + logDiff(code, compiledResult.code) + console.log('Output:\n', compiledResult.code + '\n\n') } + + return compiledResult } diff --git a/packages/directive-functions-plugin/tests/compiler.test.ts b/packages/directive-functions-plugin/tests/compiler.test.ts index a2c7fd3fc5..e405a7411e 100644 --- a/packages/directive-functions-plugin/tests/compiler.test.ts +++ b/packages/directive-functions-plugin/tests/compiler.test.ts @@ -713,8 +713,6 @@ describe('server function compilation', () => { .extractedFilename, }) - console.log(ssr.directiveFnsById) - expect(client.compiledResult.code).toMatchInlineSnapshot(` "'use server'; diff --git a/packages/eslint-plugin-router/package.json b/packages/eslint-plugin-router/package.json index 39c59420bd..34ca334a7e 100644 --- a/packages/eslint-plugin-router/package.json +++ b/packages/eslint-plugin-router/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/eslint-plugin-router", - "version": "1.115.0", + "version": "1.121.0-alpha.1", "description": "ESLint plugin for TanStack Router", "author": "Manuel Schiller", "license": "MIT", diff --git a/packages/history/package.json b/packages/history/package.json index 2943dc0247..ae12d350d3 100644 --- a/packages/history/package.json +++ b/packages/history/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/history", - "version": "1.115.0", + "version": "1.121.0-alpha.1", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/react-router-devtools/package.json b/packages/react-router-devtools/package.json index 940def08b5..8f70f10dd8 100644 --- a/packages/react-router-devtools/package.json +++ b/packages/react-router-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-router-devtools", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/react-router-with-query/package.json b/packages/react-router-with-query/package.json index fbfa01431f..d841497993 100644 --- a/packages/react-router-with-query/package.json +++ b/packages/react-router-with-query/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-router-with-query", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/react-router-with-query/src/index.tsx b/packages/react-router-with-query/src/index.tsx index e26bcf2975..7858816513 100644 --- a/packages/react-router-with-query/src/index.tsx +++ b/packages/react-router-with-query/src/index.tsx @@ -117,12 +117,8 @@ export function routerWithQueryClient( ...ogMutationCacheConfig, onError: (error, _variables, _context, _mutation) => { if (isRedirect(error)) { - return router.navigate( - router.resolveRedirect({ - ...error, - _fromLocation: router.state.location, - }), - ) + error.options._fromLocation = router.state.location + return router.navigate(router.resolveRedirect(error).options) } return ogMutationCacheConfig.onError?.( @@ -139,12 +135,8 @@ export function routerWithQueryClient( ...ogQueryCacheConfig, onError: (error, _query) => { if (isRedirect(error)) { - return router.navigate( - router.resolveRedirect({ - ...error, - _fromLocation: router.state.location, - }), - ) + error.options._fromLocation = router.state.location + return router.navigate(router.resolveRedirect(error).options) } return ogQueryCacheConfig.onError?.(error, _query) diff --git a/packages/react-router/package.json b/packages/react-router/package.json index caac296dc9..d824933002 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-router", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/react-router/src/HeadContent.tsx b/packages/react-router/src/HeadContent.tsx index 638dee8acc..b0856e5d49 100644 --- a/packages/react-router/src/HeadContent.tsx +++ b/packages/react-router/src/HeadContent.tsx @@ -58,8 +58,8 @@ export const useTags = () => { }, [routeMeta]) const links = useRouterState({ - select: (state) => - state.matches + select: (state) => { + const constructed = state.matches .map((match) => match.links!) .filter(Boolean) .flat(1) @@ -68,7 +68,30 @@ export const useTags = () => { attrs: { ...link, }, - })) as Array, + })) satisfies Array + + const manifest = router.ssr?.manifest + + // These are the assets extracted from the ViteManifest + // using the `startManifestPlugin` + const assets = state.matches + .map((match) => manifest?.routes[match.routeId]?.assets ?? []) + .filter(Boolean) + .flat(1) + .filter((asset) => asset.tag === 'link') + .map( + (asset) => + ({ + tag: 'link', + attrs: { + ...asset.attrs, + suppressHydrationWarning: true, + }, + }) satisfies RouterManagedTag, + ) + + return [...constructed, ...assets] + }, structuralSharing: true as any, }) diff --git a/packages/react-router/src/Match.tsx b/packages/react-router/src/Match.tsx index 79dd4ed01a..bf549f362b 100644 --- a/packages/react-router/src/Match.tsx +++ b/packages/react-router/src/Match.tsx @@ -306,6 +306,17 @@ export const Outlet = React.memo(function OutletImpl() { }, }) + const pendingElement = router.options.defaultPendingComponent ? ( + + ) : null + + if (router.isShell) + return ( + + + + ) + if (parentGlobalNotFound) { return renderRouteNotFound(router, route, undefined) } @@ -316,10 +327,6 @@ export const Outlet = React.memo(function OutletImpl() { const nextMatch = - const pendingElement = router.options.defaultPendingComponent ? ( - - ) : null - if (matchId === rootRouteId) { return ( {nextMatch} @@ -328,3 +335,7 @@ export const Outlet = React.memo(function OutletImpl() { return nextMatch }) + +function ShellInner(): React.ReactElement { + throw new Error('ShellBoundaryError') +} diff --git a/packages/react-router/src/Matches.tsx b/packages/react-router/src/Matches.tsx index d5a0638ad3..bc96173a21 100644 --- a/packages/react-router/src/Matches.tsx +++ b/packages/react-router/src/Matches.tsx @@ -15,6 +15,7 @@ import type { ReactNode } from './route' import type { AnyRouter, DeepPartial, + Expand, MakeOptionalPathParams, MakeOptionalSearchParams, MakeRouteMatchUnion, @@ -123,7 +124,9 @@ export function useMatchRoute() { const TMaskTo extends string = '', >( opts: UseMatchRouteOptions, - ): false | ResolveRoute['types']['allParams'] => { + ): + | false + | Expand['types']['allParams']> => { const { pending, caseSensitive, fuzzy, includeSearch, ...rest } = opts return router.matchRoute(rest as any, { diff --git a/packages/react-router/src/RouterProvider.tsx b/packages/react-router/src/RouterProvider.tsx index 92e882fef5..9c845df096 100644 --- a/packages/react-router/src/RouterProvider.tsx +++ b/packages/react-router/src/RouterProvider.tsx @@ -17,15 +17,17 @@ export function RouterContextProvider< }: RouterProps & { children: React.ReactNode }) { - // Allow the router to update options on the router instance - router.update({ - ...router.options, - ...rest, - context: { - ...router.options.context, - ...rest.context, - }, - } as any) + if (Object.keys(rest).length > 0) { + // Allow the router to update options on the router instance + router.update({ + ...router.options, + ...rest, + context: { + ...router.options.context, + ...rest.context, + }, + } as any) + } const routerContext = getRouterContext() diff --git a/packages/react-router/src/Scripts.tsx b/packages/react-router/src/Scripts.tsx index 2c28537164..bc2b84c6d0 100644 --- a/packages/react-router/src/Scripts.tsx +++ b/packages/react-router/src/Scripts.tsx @@ -50,6 +50,7 @@ export const Scripts = () => { children, })), }), + structuralSharing: true as any, }) const allScripts = [...scripts, ...assetScripts] as Array diff --git a/packages/react-router/src/ScrollRestoration.tsx b/packages/react-router/src/ScrollRestoration.tsx index 063d93914f..71d472723d 100644 --- a/packages/react-router/src/ScrollRestoration.tsx +++ b/packages/react-router/src/ScrollRestoration.tsx @@ -64,6 +64,6 @@ export function useElementScrollRestoration( } const restoreKey = getKey(router.latestLocation) - const byKey = scrollRestorationCache.state[restoreKey] + const byKey = scrollRestorationCache?.state[restoreKey] return byKey?.[elementSelector] } diff --git a/packages/react-router/src/fileRoute.ts b/packages/react-router/src/fileRoute.ts index d645cc840d..0b77e986e7 100644 --- a/packages/react-router/src/fileRoute.ts +++ b/packages/react-router/src/fileRoute.ts @@ -28,6 +28,7 @@ import type { RouteIds, RouteLoaderFn, UpdatableRouteOptions, + UseNavigateResult, } from '@tanstack/router-core' import type { UseLoaderDepsRoute } from './useLoaderDeps' import type { UseLoaderDataRoute } from './useLoaderData' @@ -41,8 +42,13 @@ export function createFileRoute< TFullPath extends RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'], >( - path: TFilePath, + path?: TFilePath, ): FileRoute['createRoute'] { + if (typeof path === 'object') { + return new FileRoute(path, { + silent: true, + }).createRoute(path) as any + } return new FileRoute(path, { silent: true, }).createRoute @@ -63,7 +69,7 @@ export class FileRoute< silent?: boolean constructor( - public path: TFilePath, + public path?: TFilePath, _opts?: { silent: boolean }, ) { this.silent = _opts?.silent @@ -159,6 +165,18 @@ export function FileRouteLoader< return (loaderFn) => loaderFn as any } +declare module '@tanstack/router-core' { + export interface LazyRoute { + useMatch: UseMatchRoute + useRouteContext: UseRouteContextRoute + useSearch: UseSearchRoute + useParams: UseParamsRoute + useLoaderDeps: UseLoaderDepsRoute + useLoaderData: UseLoaderDataRoute + useNavigate: () => UseNavigateResult + } +} + export class LazyRoute { options: { id: string @@ -214,7 +232,7 @@ export class LazyRoute { return useLoaderData({ ...opts, from: this.options.id } as any) } - useNavigate = () => { + useNavigate = (): UseNavigateResult => { const router = useRouter() return useNavigate({ from: router.routesById[this.options.id].fullPath }) } @@ -236,6 +254,10 @@ export function createLazyRoute< export function createLazyFileRoute< TFilePath extends keyof FileRoutesByPath, TRoute extends FileRoutesByPath[TFilePath]['preLoaderRoute'], ->(id: TFilePath) { +>(id: TFilePath): (opts: LazyRouteOptions) => LazyRoute { + if (typeof id === 'object') { + return new LazyRoute(id) as any + } + return (opts: LazyRouteOptions) => new LazyRoute({ id, ...opts }) } diff --git a/packages/react-router/src/index.tsx b/packages/react-router/src/index.tsx index b848fc7210..c662c21fc0 100644 --- a/packages/react-router/src/index.tsx +++ b/packages/react-router/src/index.tsx @@ -48,7 +48,6 @@ export type { DeferredPromiseState, DeferredPromise, ParsedLocation, - ParsePathParams, RemoveTrailingSlashes, RemoveLeadingSlashes, ActiveOptions, @@ -57,6 +56,8 @@ export type { RootRouteId, AnyPathParams, ResolveParams, + ResolveOptionalParams, + ResolveRequiredParams, SearchSchemaInput, AnyContext, RouteContext, @@ -78,8 +79,6 @@ export type { TrimPath, TrimPathLeft, TrimPathRight, - ParseSplatParams, - SplatParams, StringifyParamsFn, ParamsOptions, InferAllParams, @@ -126,6 +125,7 @@ export type { RouteById, RootRouteOptions, SerializerExtensions, + CreateFileRoute, } from '@tanstack/router-core' export type * from './serializer' @@ -237,6 +237,7 @@ export type { RouteConstraints, RouteMask, MatchRouteOptions, + CreateLazyFileRoute, } from '@tanstack/router-core' export type { UseLinkPropsOptions, diff --git a/packages/react-router/src/link.tsx b/packages/react-router/src/link.tsx index 3023a10288..58a5ed6862 100644 --- a/packages/react-router/src/link.tsx +++ b/packages/react-router/src/link.tsx @@ -16,7 +16,7 @@ import { useLayoutEffect, } from './utils' -import { useMatches } from './Matches' +import { useMatch } from './useMatch' import type { AnyRouter, Constrain, @@ -105,26 +105,28 @@ export function useLinkProps< structuralSharing: true as any, }) - // when `from` is not supplied, use the leaf route of the current matches as the `from` location - // so relative routing works as expected - const from = useMatches({ - select: (matches) => options.from ?? matches[matches.length - 1]?.fullPath, + const nearestFrom = useMatch({ + strict: false, + select: (match) => match.fullPath, }) + + const from = options.from ?? nearestFrom + // Use it as the default `from` location - const _options = React.useMemo(() => ({ ...options, from }), [options, from]) + options = { ...options, from } const next = React.useMemo( - () => router.buildLocation(_options as any), + () => router.buildLocation(options as any), // eslint-disable-next-line react-hooks/exhaustive-deps - [router, _options, currentSearch], + [router, options, currentSearch], ) const preload = React.useMemo(() => { - if (_options.reloadDocument) { + if (options.reloadDocument) { return false } return userPreload ?? router.options.defaultPreload - }, [router.options.defaultPreload, userPreload, _options.reloadDocument]) + }, [router.options.defaultPreload, userPreload, options.reloadDocument]) const preloadDelay = userPreloadDelay ?? router.options.defaultPreloadDelay ?? 0 @@ -175,11 +177,11 @@ export function useLinkProps< }) const doPreload = React.useCallback(() => { - router.preloadRoute(_options as any).catch((err) => { + router.preloadRoute(options as any).catch((err) => { console.warn(err) console.warn(preloadWarning) }) - }, [_options, router]) + }, [options, router]) const preloadViewportIoCallback = React.useCallback( (entry: IntersectionObserverEntry | undefined) => { @@ -249,14 +251,14 @@ export function useLinkProps< // All is well? Navigate! // N.B. we don't call `router.commitLocation(next) here because we want to run `validateSearch` before committing return router.navigate({ - ..._options, + ...options, replace, resetScroll, hashScrollIntoView, startTransition, viewTransition, ignoreBlocker, - } as any) + }) } } @@ -279,10 +281,14 @@ export function useLinkProps< return } - eventTarget.preloadTimeout = setTimeout(() => { - eventTarget.preloadTimeout = null + if (!preloadDelay) { doPreload() - }, preloadDelay) + } else { + eventTarget.preloadTimeout = setTimeout(() => { + eventTarget.preloadTimeout = null + doPreload() + }, preloadDelay) + } } } diff --git a/packages/react-router/src/router.ts b/packages/react-router/src/router.ts index 16b25cdcc9..3680337ba6 100644 --- a/packages/react-router/src/router.ts +++ b/packages/react-router/src/router.ts @@ -1,4 +1,5 @@ import { RouterCore } from '@tanstack/router-core' +import { createFileRoute, createLazyFileRoute } from './fileRoute' import type { RouterHistory } from '@tanstack/history' import type { AnyRoute, @@ -105,3 +106,11 @@ export class Router< super(options) } } + +if (typeof globalThis !== 'undefined') { + ;(globalThis as any).createFileRoute = createFileRoute + ;(globalThis as any).createLazyFileRoute = createLazyFileRoute +} else if (typeof window !== 'undefined') { + ;(window as any).createFileRoute = createFileRoute + ;(window as any).createFileRoute = createLazyFileRoute +} diff --git a/packages/react-router/src/useBlocker.tsx b/packages/react-router/src/useBlocker.tsx index 1757dee80d..84a8eba9db 100644 --- a/packages/react-router/src/useBlocker.tsx +++ b/packages/react-router/src/useBlocker.tsx @@ -177,7 +177,10 @@ export function useBlocker( location: HistoryLocation, ): AnyShouldBlockFnLocation { const parsedLocation = router.parseLocation(undefined, location) - const matchedRoutes = router.getMatchedRoutes(parsedLocation) + const matchedRoutes = router.getMatchedRoutes( + parsedLocation.pathname, + undefined, + ) if (matchedRoutes.foundRoute === undefined) { throw new Error(`No route found for location ${location.href}`) } diff --git a/packages/react-router/src/useNavigate.tsx b/packages/react-router/src/useNavigate.tsx index 64fdeb470a..1fcef97967 100644 --- a/packages/react-router/src/useNavigate.tsx +++ b/packages/react-router/src/useNavigate.tsx @@ -1,5 +1,6 @@ import * as React from 'react' import { useRouter } from './useRouter' +import { useMatch } from './useMatch' import type { AnyRouter, FromPathOption, @@ -14,15 +15,28 @@ export function useNavigate< >(_defaultOpts?: { from?: FromPathOption }): UseNavigateResult { - const { navigate } = useRouter() + const { navigate, state } = useRouter() + + // Just get the index of the current match to avoid rerenders + // as much as possible + const matchIndex = useMatch({ + strict: false, + select: (match) => match.index, + }) return React.useCallback( (options: NavigateOptions) => { + const from = + options.from ?? + _defaultOpts?.from ?? + state.matches[matchIndex]!.fullPath + return navigate({ - from: _defaultOpts?.from, ...options, + from, }) }, + // eslint-disable-next-line react-hooks/exhaustive-deps [_defaultOpts?.from, navigate], ) as UseNavigateResult } @@ -35,6 +49,7 @@ export function Navigate< const TMaskTo extends string = '', >(props: NavigateOptions): null { const router = useRouter() + const navigate = useNavigate() const previousPropsRef = React.useRef | null>(null) React.useEffect(() => { if (previousPropsRef.current !== props) { - router.navigate({ - ...props, - }) + navigate(props) previousPropsRef.current = props } - }, [router, props]) + }, [router, props, navigate]) return null } diff --git a/packages/react-router/tests/ClientOnly.test.tsx b/packages/react-router/tests/ClientOnly.test.tsx index b238d4e349..4bfe863d0b 100644 --- a/packages/react-router/tests/ClientOnly.test.tsx +++ b/packages/react-router/tests/ClientOnly.test.tsx @@ -1,7 +1,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest' import React from 'react' import ReactDOMServer from 'react-dom/server' -import { cleanup, render, screen } from '@testing-library/react' +import { act, cleanup, render, screen } from '@testing-library/react' import { RouterProvider, createMemoryHistory, @@ -10,16 +10,14 @@ import { createRouter, } from '../src' import { ClientOnly } from '../src/ClientOnly' -import type { RouterHistory } from '../src' afterEach(() => { vi.resetAllMocks() cleanup() }) -function createTestRouter(initialHistory?: RouterHistory) { - const history = - initialHistory ?? createMemoryHistory({ initialEntries: ['/'] }) +function createTestRouter(opts: { isServer: boolean }) { + const history = createMemoryHistory({ initialEntries: ['/'] }) const rootRoute = createRootRoute({}) @@ -35,9 +33,18 @@ function createTestRouter(initialHistory?: RouterHistory) {
), }) + const otherRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/other', + component: () => ( +
+

Other Route

+
+ ), + }) - const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree, history }) + const routeTree = rootRoute.addChildren([indexRoute, otherRoute]) + const router = createRouter({ routeTree, history, ...opts }) return { router, @@ -47,7 +54,7 @@ function createTestRouter(initialHistory?: RouterHistory) { describe('ClientOnly', () => { it('should render fallback during SSR', async () => { - const { router } = createTestRouter() + const { router } = createTestRouter({ isServer: true }) await router.load() // Initial render (SSR) @@ -59,7 +66,7 @@ describe('ClientOnly', () => { }) it('should render client content after hydration', async () => { - const { router } = createTestRouter() + const { router } = createTestRouter({ isServer: false }) await router.load() // Mock useSyncExternalStore to simulate hydration @@ -67,12 +74,12 @@ describe('ClientOnly', () => { render() - expect(screen.getByText('Client Only Content')).toBeInTheDocument() + expect(await screen.findByTestId('client-only-content')).toBeInTheDocument() expect(screen.queryByText('Loading...')).not.toBeInTheDocument() }) it('should handle navigation with client-only content', async () => { - const { router } = createTestRouter() + const { router } = createTestRouter({ isServer: false }) await router.load() // Simulate hydration @@ -81,11 +88,15 @@ describe('ClientOnly', () => { // Re-render after hydration render() + expect(await screen.findByTestId('client-only-content')).toBeInTheDocument() + // Navigate to a different route and back - await router.navigate({ to: '/other' }) - await router.navigate({ to: '/' }) + await act(() => router.navigate({ to: '/other' })) + expect(await screen.findByTestId('other-route')).toBeInTheDocument() + + await act(() => router.navigate({ to: '/' })) // Content should still be visible after navigation - expect(screen.getByText('Client Only Content')).toBeInTheDocument() + expect(await screen.findByTestId('client-only-content')).toBeInTheDocument() }) }) diff --git a/packages/react-router/tests/Scripts.test.tsx b/packages/react-router/tests/Scripts.test.tsx index 13a9f0571c..315b3e528e 100644 --- a/packages/react-router/tests/Scripts.test.tsx +++ b/packages/react-router/tests/Scripts.test.tsx @@ -1,9 +1,10 @@ import { describe, expect, test } from 'vitest' -import { render } from '@testing-library/react' +import { act, render, screen } from '@testing-library/react' import ReactDOMServer from 'react-dom/server' import { HeadContent, + Outlet, RouterProvider, createMemoryHistory, createRootRoute, @@ -15,7 +16,6 @@ import { Scripts } from '../src/Scripts' describe('ssr scripts', () => { test('it works', async () => { const rootRoute = createRootRoute({ - // loader: () => new Promise((r) => setTimeout(r, 1)), head: () => { return { scripts: [ @@ -29,14 +29,19 @@ describe('ssr scripts', () => { } }, component: () => { - return + return ( +
+
root
+ + +
+ ) }, }) const indexRoute = createRoute({ path: '/', getParentRoute: () => rootRoute, - // loader: () => new Promise((r) => setTimeout(r, 2)), head: () => { return { scripts: [ @@ -53,10 +58,9 @@ describe('ssr scripts', () => { initialEntries: ['/'], }), routeTree: rootRoute.addChildren([indexRoute]), + isServer: true, }) - router.isServer = true - await router.load() expect(router.state.matches.map((d) => d.headScripts).flat(1)).toEqual([ @@ -73,7 +77,13 @@ describe('ssr scripts', () => { undefined, // 'script2.js' opted out by certain conditions, such as `NODE_ENV=production`. ], component: () => { - return + return ( +
+
root
+ + +
+ ) }, }) @@ -81,6 +91,9 @@ describe('ssr scripts', () => { path: '/', getParentRoute: () => rootRoute, scripts: () => [{ src: 'script3.js' }], + component: () => { + return
index
+ }, }) const router = createRouter({ @@ -88,10 +101,9 @@ describe('ssr scripts', () => { initialEntries: ['/'], }), routeTree: rootRoute.addChildren([indexRoute]), + isServer: true, }) - router.isServer = true - await router.load() expect(router.state.matches.map((d) => d.scripts).flat(1)).toEqual([ @@ -100,10 +112,14 @@ describe('ssr scripts', () => { { src: 'script3.js' }, ]) - const { container } = render() + const { container } = await act(() => + render(), + ) + expect(await screen.findByTestId('root')).toBeInTheDocument() + expect(await screen.findByTestId('index')).toBeInTheDocument() expect(container.innerHTML).toEqual( - ``, + `
root
index
`, ) }) }) @@ -123,7 +139,7 @@ describe('ssr HeadContent', () => { }, { name: 'description', - content: loaderData.description, + content: loaderData?.description, }, { name: 'image', @@ -160,7 +176,7 @@ describe('ssr HeadContent', () => { }, { name: 'description', - content: loaderData.description, + content: loaderData?.description, }, { name: 'last-modified', @@ -180,10 +196,9 @@ describe('ssr HeadContent', () => { initialEntries: ['/'], }), routeTree: rootRoute.addChildren([indexRoute]), + isServer: true, }) - router.isServer = true - await router.load() expect(router.state.matches.map((d) => d.meta).flat(1)).toEqual([ @@ -202,7 +217,7 @@ describe('ssr HeadContent', () => { , ) expect(html).toEqual( - `Index`, + `Index`, ) }) }) diff --git a/packages/react-router/tests/blocker.test.tsx b/packages/react-router/tests/blocker.test.tsx index 545a99699a..60d1e8a821 100644 --- a/packages/react-router/tests/blocker.test.tsx +++ b/packages/react-router/tests/blocker.test.tsx @@ -1,11 +1,12 @@ import React from 'react' import '@testing-library/jest-dom/vitest' -import { afterEach, describe, expect, test, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { cleanup, fireEvent, render, screen } from '@testing-library/react' import combinate from 'combinate' import { Link, RouterProvider, + createBrowserHistory, createRootRoute, createRoute, createRouter, @@ -13,9 +14,17 @@ import { useBlocker, useNavigate, } from '../src' -import type { ShouldBlockFn } from '../src' +import type { RouterHistory, ShouldBlockFn } from '../src' + +let history: RouterHistory + +beforeEach(() => { + history = createBrowserHistory() + expect(window.location.pathname).toBe('/') +}) afterEach(() => { + history.destroy() window.history.replaceState(null, 'root', '/') vi.resetAllMocks() cleanup() @@ -91,6 +100,7 @@ async function setup({ blockerFn, disabled, ignoreBlocker }: BlockerTestOpts) { fooRoute, barRoute, ]), + history, }) render() diff --git a/packages/react-router/tests/errorComponent.test.tsx b/packages/react-router/tests/errorComponent.test.tsx index fd6a5fa8ca..2c0062a9ac 100644 --- a/packages/react-router/tests/errorComponent.test.tsx +++ b/packages/react-router/tests/errorComponent.test.tsx @@ -1,14 +1,15 @@ -import { afterEach, describe, expect, test, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { cleanup, fireEvent, render, screen } from '@testing-library/react' import { Link, RouterProvider, + createBrowserHistory, createRootRoute, createRoute, createRouter, } from '../src' -import type { ErrorComponentProps } from '../src' +import type { ErrorComponentProps, RouterHistory } from '../src' function MyErrorComponent(props: ErrorComponentProps) { return
Error: {props.error.message}
@@ -23,7 +24,15 @@ function throwFn() { throw new Error('error thrown') } +let history: RouterHistory + +beforeEach(() => { + history = createBrowserHistory() + expect(window.location.pathname).toBe('/') +}) + afterEach(() => { + history.destroy() vi.resetAllMocks() window.history.replaceState(null, 'root', '/') cleanup() @@ -71,6 +80,7 @@ describe.each([{ preload: false }, { preload: 'intent' }] as const)( const router = createRouter({ routeTree, defaultPreload: options.preload, + history, }) render() @@ -89,7 +99,9 @@ describe.each([{ preload: false }, { preload: 'intent' }] as const)( undefined, { timeout: 1500 }, ) - expect(screen.findByText('About route content')).rejects.toThrow() + await expect( + screen.findByText('About route content'), + ).rejects.toThrow() expect(errorComponent).toBeInTheDocument() }, ) @@ -114,6 +126,7 @@ describe.each([{ preload: false }, { preload: 'intent' }] as const)( const router = createRouter({ routeTree, defaultPreload: options.preload, + history, }) render() @@ -123,7 +136,9 @@ describe.each([{ preload: false }, { preload: 'intent' }] as const)( undefined, { timeout: 750 }, ) - expect(screen.findByText('Index route content')).rejects.toThrow() + await expect( + screen.findByText('Index route content'), + ).rejects.toThrow() expect(errorComponent).toBeInTheDocument() }, ) diff --git a/packages/react-router/tests/index.test.tsx b/packages/react-router/tests/index.test.tsx deleted file mode 100644 index 657db70915..0000000000 --- a/packages/react-router/tests/index.test.tsx +++ /dev/null @@ -1,564 +0,0 @@ -import { expect, test } from 'vitest' - -// keeping this dummy test in since in the future -// we may want to grab the commented out tests from here - -test('index true=true', () => { - expect(true).toBe(true) -}) -// import { render } from '@testing-library/react' - -// import React from 'react' - -// import { -// Outlet, -// RouterProvider, -// cleanPath, -// createMemoryHistory, -// createRootRoute, -// createRoute, -// createRouter, -// // Location, -// matchPathname, -// // ParsedLocation, -// parsePathname, -// redirect, -// // Route, -// // createMemoryHistory, -// resolvePath, -// // Segment, -// trimPath, -// trimPathLeft, -// } from '../src' - -// import { createTimer, sleep } from './utils' - -// function RouterInstance(opts?: { initialEntries?: string[] }) { -// return new RouterInstance({ -// routes: [], -// history: createMemoryHistory({ -// initialEntries: opts?.initialEntries ?? ['/'], -// }), -// }) -// } - -// function createLocation(location: Partial): ParsedLocation { -// return { -// pathname: '', -// href: '', -// search: {}, -// searchStr: '', -// state: {}, -// hash: '', -// ...location, -// } -// } - -// describe('Router', () => { -// test('mounts to /', async () => { -// const router = RouterInstance() - -// const routes = [ -// { -// path: '/', -// }, -// ] - -// router.update({ -// routes, -// }) - -// const promise = router.mount() -// expect(router.store.pendingMatches[0].id).toBe('/') - -// await promise -// expect(router.state.matches[0].id).toBe('/') -// }) - -// test('mounts to /a', async () => { -// const router = RouterInstance({ initialEntries: ['/a'] }) -// const routes: Route[] = [ -// { -// path: '/', -// }, -// { -// path: '/a', -// }, -// ] - -// router.update({ -// routes, -// }) - -// let promise = router.mount() - -// expect(router.store.pendingMatches[0].id).toBe('/a') -// await promise -// expect(router.state.matches[0].id).toBe('/a') -// }) - -// test('mounts to /a/b', async () => { -// const router = RouterInstance({ -// initialEntries: ['/a/b'], -// }) - -// const routes: Route[] = [ -// { -// path: '/', -// }, -// { -// path: '/a', -// children: [ -// { -// path: '/b', -// }, -// ], -// }, -// ] - -// router.update({ -// routes, -// }) - -// let promise = router.mount() - -// expect(router.store.pendingMatches[1].id).toBe('/a/b') -// await promise -// expect(router.state.matches[1].id).toBe('/a/b') -// }) - -// test('navigates to /a', async () => { -// const router = RouterInstance() -// const routes: Route[] = [ -// { -// path: '/', -// }, -// { -// path: 'a', -// }, -// ] - -// router.update({ -// routes, -// }) - -// let promise = router.mount() - -// expect(router.store.pendingMatches[0].id).toBe('/') - -// await promise -// expect(router.state.matches[0].id).toBe('/') - -// promise = router.navigate({ to: 'a' }) -// expect(router.state.matches[0].id).toBe('/') -// expect(router.store.pendingMatches[0].id).toBe('a') - -// await promise -// expect(router.state.matches[0].id).toBe('a') -// expect(router.store.pending).toBe(undefined) -// }) - -// test('navigates to /a to /a/b', async () => { -// const router = RouterInstance() -// const routes: Route[] = [ -// { -// path: '/', -// }, -// { -// path: 'a', -// children: [ -// { -// path: 'b', -// }, -// ], -// }, -// ] - -// router.update({ -// routes, -// }) - -// await router.mount() -// expect(router.state.location.href).toBe('/') - -// let promise = router.navigate({ to: 'a' }) -// expect(router.store.pendingLocation.href).toBe('/a') -// await promise -// expect(router.state.location.href).toBe('/a') - -// promise = router.navigate({ to: './b' }) -// expect(router.store.pendingLocation.href).toBe('/a/b') -// await promise -// expect(router.state.location.href).toBe('/a/b') - -// expect(router.store.pending).toBe(undefined) -// }) - -// test('async navigates to /a/b', async () => { -// const router = RouterInstance() -// const routes: Route[] = [ -// { -// path: '/', -// }, -// { -// path: 'a', -// loader: () => sleep(10).then((d) => ({ a: true })), -// children: [ -// { -// path: 'b', -// loader: () => sleep(10).then((d) => ({ b: true })), -// }, -// ], -// }, -// ] - -// const timer = createTimer() - -// router.update({ -// routes, -// }) - -// router.mount() - -// timer.start() -// await router.navigate({ to: 'a/b' }) -// expect(router.store.loaderData).toEqual({ -// a: true, -// b: true, -// }) -// expect(timer.getTime()).toBeLessThan(30) -// }) - -// test('async navigates with import + loader', async () => { -// const router = RouterInstance() -// const routes: Route[] = [ -// { -// path: '/', -// }, -// { -// path: 'a', -// import: async () => { -// await sleep(10) -// return { -// loader: () => sleep(10).then((d) => ({ a: true })), -// } -// }, -// children: [ -// { -// path: 'b', -// import: async () => { -// await sleep(10) -// return { -// loader: () => -// sleep(10).then((d) => ({ -// b: true, -// })), -// } -// }, -// }, -// ], -// }, -// ] - -// const timer = createTimer() - -// router.update({ -// routes, -// }) - -// router.mount() - -// timer.start() -// await router.navigate({ to: 'a/b' }) -// expect(router.store.loaderData).toEqual({ -// a: true, -// b: true, -// }) -// expect(timer.getTime()).toBeLessThan(28) -// }) - -// test('async navigates with import + elements + loader', async () => { -// const router = RouterInstance() -// const routes: Route[] = [ -// { -// path: '/', -// }, -// { -// path: 'a', -// import: async () => { -// await sleep(10) -// return { -// element: async () => { -// await sleep(20) -// return 'element' -// }, -// loader: () => sleep(30).then((d) => ({ a: true })), -// } -// }, -// children: [ -// { -// path: 'b', -// import: async () => { -// await sleep(10) -// return { -// element: async () => { -// await sleep(20) -// return 'element' -// }, -// loader: () => -// sleep(30).then((d) => ({ -// b: true, -// })), -// } -// }, -// }, -// ], -// }, -// ] - -// const timer = createTimer() - -// router.update({ -// routes, -// }) - -// router.mount() - -// await router.navigate({ to: 'a/b' }) -// expect(router.store.loaderData).toEqual({ -// a: true, -// b: true, -// }) -// expect(timer.getTime()).toBeLessThan(55) -// }) - -// test('async navigates with pending state', async () => { -// const router = RouterInstance() -// const routes: Route[] = [ -// { -// path: '/', -// }, -// { -// path: 'a', -// pendingMs: 10, -// loader: () => sleep(20), -// children: [ -// { -// path: 'b', -// pendingMs: 30, -// loader: () => sleep(40), -// }, -// ], -// }, -// ] - -// router.update({ -// routes, -// }) - -// await router.mount() - -// const timer = createTimer() -// await router.navigate({ to: 'a/b' }) -// expect(timer.getTime()).toBeLessThan(46) -// }) -// }) - -// describe('matchRoute', () => { -// describe('fuzzy', () => { -// ;( -// [ -// [ -// '/', -// { -// to: '/', -// fuzzy: true, -// }, -// {}, -// ], -// [ -// '/a', -// { -// to: '/', -// fuzzy: true, -// }, -// {}, -// ], -// [ -// '/a', -// { -// to: '/$', -// fuzzy: true, -// }, -// { '*': 'a' }, -// ], -// [ -// '/a/b', -// { -// to: '/$', -// fuzzy: true, -// }, -// { '*': 'a/b' }, -// ], -// [ -// '/a/b/c', -// { -// to: '/$', -// fuzzy: true, -// }, -// { '*': 'a/b/c' }, -// ], -// [ -// '/a/b/c', -// { -// to: '/', -// fuzzy: true, -// }, -// {}, -// ], -// [ -// '/a/b', -// { -// to: '/a/b/', -// fuzzy: true, -// }, -// {}, -// ], -// ] as const -// ).forEach(([a, b, eq]) => { -// test(`${a} == ${b.to}`, () => { -// expect(matchPathname('', a, b)).toEqual(eq) -// }) -// }) -// }) - -// describe('exact', () => { -// ;( -// [ -// [ -// '/a/b/c', -// { -// to: '/', -// }, -// undefined, -// ], -// [ -// '/a/b/c', -// { -// to: '/a/b', -// }, -// undefined, -// ], -// [ -// '/a/b/c', -// { -// to: '/a/b/c', -// }, -// {}, -// ], -// ] as const -// ).forEach(([a, b, eq]) => { -// test(`${a} == ${b.to}`, () => { -// expect(matchPathname('', a, b)).toEqual(eq) -// }) -// }) -// }) - -// describe('basepath', () => { -// ;( -// [ -// [ -// '/base', -// '/base', -// { -// to: '/', -// }, -// {}, -// ], -// [ -// '/base', -// '/base/a', -// { -// to: '/a', -// }, -// {}, -// ], -// [ -// '/base', -// '/base/a/b/c', -// { -// to: '/a/b/c', -// }, -// {}, -// ], -// [ -// '/base', -// '/base/posts', -// { -// fuzzy: true, -// to: '/', -// }, -// {}, -// ], -// [ -// '/base', -// '/base/a', -// { -// to: '/b', -// }, -// undefined, -// ], -// ] as const -// ).forEach(([a, b, c, eq]) => { -// test(`${b} == ${a} + ${c.to}`, () => { -// expect(matchPathname(a, b, c)).toEqual(eq) -// }) -// }) -// }) - -// describe('params', () => { -// ;( -// [ -// [ -// '/a/b', -// { -// to: '/a/$b', -// }, -// { b: 'b' }, -// ], -// [ -// '/a/b/c', -// { -// to: '/a/$b/$c', -// }, -// { b: 'b', c: 'c' }, -// ], -// [ -// '/a/b/c', -// { -// to: '/$a/$b/$c', -// }, -// { a: 'a', b: 'b', c: 'c' }, -// ], -// [ -// '/a/b/c', -// { -// to: '/$a/$', -// }, -// { a: 'a', '*': 'b/c' }, -// ], -// [ -// '/a/b/c', -// { -// to: '/a/$b/c', -// }, -// { b: 'b' }, -// ], -// ] as const -// ).forEach(([a, b, eq]) => { -// test(`${a} == ${b.to}`, () => { -// expect(matchPathname('', a, b)).toEqual(eq) -// }) -// }) -// }) -// }) diff --git a/packages/react-router/tests/link.test.tsx b/packages/react-router/tests/link.test.tsx index 65ebcbe66c..fe5672f7af 100644 --- a/packages/react-router/tests/link.test.tsx +++ b/packages/react-router/tests/link.test.tsx @@ -16,6 +16,7 @@ import { Link, Outlet, RouterProvider, + createBrowserHistory, createLink, createMemoryHistory, createRootRoute, @@ -38,9 +39,11 @@ import { getSearchParamsFromURI, sleep, } from './utils' +import type { RouterHistory } from '../src' const ioObserveMock = vi.fn() const ioDisconnectMock = vi.fn() +let history: RouterHistory beforeEach(() => { const io = getIntersectionObserverMock({ @@ -48,10 +51,13 @@ beforeEach(() => { disconnect: ioDisconnectMock, }) vi.stubGlobal('IntersectionObserver', io) - window.history.replaceState(null, 'root', '/') + history = createBrowserHistory() + expect(window.location.pathname).toBe('/') }) afterEach(() => { + history.destroy() + window.history.replaceState(null, 'root', '/') vi.resetAllMocks() cleanup() }) @@ -99,6 +105,7 @@ describe('Link', () => { const memoedRouter = React.useMemo(() => { const router = createRouter({ routeTree: memoedRouteTree, + history, }) return router @@ -148,6 +155,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -196,6 +204,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -269,6 +278,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute]), + history, }) render() @@ -345,7 +355,7 @@ describe('Link', () => { expect(indexFooBarLink).not.toHaveAttribute('data-status', 'active') // navigate to /?foo=bar - fireEvent.click(indexFooBarLink) + await act(() => fireEvent.click(indexFooBarLink)) expect(indexExactLink).toHaveClass('inactive') expect(indexExactLink).not.toHaveClass('active') @@ -441,6 +451,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -484,13 +495,14 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() const postsLink = await screen.findByRole('link', { name: 'Posts' }) - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const postsHeading = await screen.findByRole('heading', { name: 'Posts' }) expect(postsHeading).toBeInTheDocument() @@ -544,6 +556,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, basepath: '/app', }) @@ -551,7 +564,7 @@ describe('Link', () => { const postsLink = await screen.findByRole('link', { name: 'Posts' }) - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const postsHeading = await screen.findByRole('heading', { name: 'Posts' }) expect(postsHeading).toBeInTheDocument() @@ -609,6 +622,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -617,7 +631,7 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts?page=0') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const postsHeading = await screen.findByRole('heading', { name: 'Posts' }) expect(postsHeading).toBeInTheDocument() @@ -680,6 +694,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -688,7 +703,7 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts?page=invalid') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) await waitFor(() => expect(onError).toHaveBeenCalledOnce()) @@ -747,6 +762,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -755,7 +771,7 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts?page=2') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const pageFour = await screen.findByText('Page: 4') expect(pageFour).toBeInTheDocument() @@ -814,6 +830,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -822,7 +839,7 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts?page=2') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const errorText = await screen.findByText('Something went wrong!') expect(errorText).toBeInTheDocument() @@ -880,13 +897,14 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() const postsLink = await screen.findByRole('link', { name: 'Posts' }) - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const postsErrorText = await screen.findByText('PostsError') expect(postsErrorText).toBeInTheDocument() @@ -895,9 +913,9 @@ describe('Link', () => { expect(postsOnError).toHaveBeenCalledWith(error) const indexLink = await screen.findByRole('link', { name: 'Index' }) - fireEvent.click(indexLink) + await act(() => fireEvent.click(indexLink)) - expect(screen.findByText('IndexError')).rejects.toThrow() + await expect(screen.findByText('IndexError')).rejects.toThrow() expect(indexOnError).not.toHaveBeenCalledOnce() }) @@ -941,13 +959,14 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute, authRoute]), + history, }) render() const postsLink = await screen.findByRole('link', { name: 'Posts' }) - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const authText = await screen.findByText('Auth!') expect(authText).toBeInTheDocument() @@ -995,13 +1014,14 @@ describe('Link', () => { const router = createRouter({ context: { userId: 'userId' }, routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() const postsLink = await screen.findByRole('link', { name: 'Posts' }) - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const userId = await screen.findByText('UserId: userId') expect(userId).toBeInTheDocument() @@ -1041,13 +1061,14 @@ describe('Link', () => { const router = createRouter({ context: { userId: 'userId' }, routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() const postsLink = await screen.findByRole('link', { name: 'Posts' }) - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const errorText = await screen.findByText('Oops! Something went wrong!') expect(errorText).toBeInTheDocument() @@ -1089,13 +1110,14 @@ describe('Link', () => { const router = createRouter({ context: { userId: 'userId' }, routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() const postsLink = await screen.findByRole('link', { name: 'Posts' }) - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const errorText = await screen.findByText('Oops! Something went wrong!') expect(errorText).toBeInTheDocument() @@ -1151,13 +1173,14 @@ describe('Link', () => { indexRoute, postsRoute.addChildren([postRoute]), ]), + history, }) render() const postLink = await screen.findByRole('link', { name: 'Post' }) - fireEvent.click(postLink) + await act(() => fireEvent.click(postLink)) const errorText = await screen.findByText('Oops! Something went wrong!') expect(errorText).toBeInTheDocument() @@ -1183,6 +1206,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute]), + history, }) render() @@ -1243,6 +1267,7 @@ describe('Link', () => { indexRoute, postsRoute.addChildren([postRoute]), ]), + history, }) render() @@ -1253,7 +1278,7 @@ describe('Link', () => { expect(postLink).toHaveAttribute('href', '/posts/id1') - fireEvent.click(postLink) + await act(() => fireEvent.click(postLink)) const paramText = await screen.findByText('Params: id1') expect(paramText).toBeInTheDocument() @@ -1330,6 +1355,7 @@ describe('Link', () => { indexRoute, postsRoute.addChildren([postsIndexRoute, postRoute]), ]), + history, }) render() @@ -1338,7 +1364,7 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const postsText = await screen.findByText('Posts Index') expect(postsText).toBeInTheDocument() @@ -1349,7 +1375,7 @@ describe('Link', () => { expect(postLink).toHaveAttribute('href', '/posts/id1') - fireEvent.click(postLink) + await act(() => fireEvent.click(postLink)) const paramText = await screen.findByText('Params: id1') expect(paramText).toBeInTheDocument() @@ -1428,6 +1454,7 @@ describe('Link', () => { indexRoute, postsRoute.addChildren([postsIndexRoute, postRoute]), ]), + history, }) render() @@ -1436,7 +1463,7 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const postsIndexText = await screen.findByText('Posts Index') expect(postsIndexText).toBeInTheDocument() @@ -1447,7 +1474,7 @@ describe('Link', () => { expect(postLink).toHaveAttribute('href', '/posts/id1') - fireEvent.click(postLink) + await act(() => fireEvent.click(postLink)) const paramText = await screen.findByText('Params: id1') expect(paramText).toBeInTheDocument() @@ -1556,6 +1583,7 @@ describe('Link', () => { ]), ]), ]), + history, }) render() @@ -1564,7 +1592,7 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts/id1/details') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const paramsText1 = await screen.findByText('Params: id1') expect(paramsText1).toBeInTheDocument() @@ -1577,7 +1605,7 @@ describe('Link', () => { expect(informationLink).toHaveAttribute('href', '/posts/id1/info') - fireEvent.click(informationLink) + await act(() => fireEvent.click(informationLink)) const informationText = await screen.findByText('Information') expect(informationText).toBeInTheDocument() @@ -1693,6 +1721,7 @@ describe('Link', () => { ]), ]), ]), + history, }) render() @@ -1701,7 +1730,7 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts/id1/details') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const paramsText1 = await screen.findByText('Params: id1') expect(paramsText1).toBeInTheDocument() @@ -1714,7 +1743,7 @@ describe('Link', () => { expect(informationLink).toHaveAttribute('href', '/posts/id1/info') - fireEvent.click(informationLink) + await act(() => fireEvent.click(informationLink)) const informationText = await screen.findByText('Information') expect(informationText).toBeInTheDocument() @@ -1830,6 +1859,7 @@ describe('Link', () => { ]), ]), ]), + history, }) render() @@ -1838,7 +1868,7 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts/id1/details') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const paramsText1 = await screen.findByText('Params: id1') expect(paramsText1).toBeInTheDocument() @@ -1851,7 +1881,7 @@ describe('Link', () => { expect(informationLink).toHaveAttribute('href', '/posts/id1/info') - fireEvent.click(informationLink) + await act(() => fireEvent.click(informationLink)) const informationText = await screen.findByText('Information') expect(informationText).toBeInTheDocument() @@ -1955,6 +1985,7 @@ describe('Link', () => { postsRoute.addChildren([postRoute.addChildren([detailsRoute])]), ]), ]), + history, }) render() @@ -1963,7 +1994,7 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts/id1/details') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const paramsText1 = await screen.findByText('Params: id1') expect(paramsText1).toBeInTheDocument() @@ -1976,7 +2007,7 @@ describe('Link', () => { expect(rootLink).toHaveAttribute('href', '/') - fireEvent.click(rootLink) + await act(() => fireEvent.click(rootLink)) const indexText = await screen.findByText('Index') expect(indexText).toBeInTheDocument() @@ -2099,6 +2130,7 @@ describe('Link', () => { ]), ]), ]), + history, }) render() @@ -2107,7 +2139,7 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts/id1/details?page=2') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const paramsText1 = await screen.findByText('Params: id1') expect(paramsText1).toBeInTheDocument() @@ -2123,7 +2155,7 @@ describe('Link', () => { '/posts/id1/info?page=2&more=true', ) - fireEvent.click(informationLink) + await act(() => fireEvent.click(informationLink)) const informationText = await screen.findByText('Information') expect(informationText).toBeInTheDocument() @@ -2239,6 +2271,7 @@ describe('Link', () => { ]), ]), ]), + history, }) render() @@ -2247,7 +2280,7 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts/id1/details') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const paramsText1 = await screen.findByText('Params: id1') expect(paramsText1).toBeInTheDocument() @@ -2260,7 +2293,7 @@ describe('Link', () => { expect(postLink).toHaveAttribute('href', '/posts/id1') - fireEvent.click(postLink) + await act(() => fireEvent.click(postLink)) const postsText = await screen.findByText('Posts') expect(postsText).toBeInTheDocument() @@ -2383,6 +2416,7 @@ describe('Link', () => { ]), ]), ]), + history, }) render() @@ -2391,7 +2425,7 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts/id1/details') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const paramsText1 = await screen.findByText('Params: id1') expect(paramsText1).toBeInTheDocument() @@ -2404,7 +2438,7 @@ describe('Link', () => { expect(postLink).toHaveAttribute('href', '/posts/id1') - fireEvent.click(postLink) + await act(() => fireEvent.click(postLink)) const postsText = await screen.findByText('Posts') expect(postsText).toBeInTheDocument() @@ -2415,6 +2449,8 @@ describe('Link', () => { }) test('when navigating from /invoices to ./invoiceId and the current route is /posts/$postId/details', async () => { + const consoleWarnSpy = vi.spyOn(console, 'warn') + const rootRoute = createRootRoute() const indexRoute = createRoute({ @@ -2540,20 +2576,24 @@ describe('Link', () => { ]), ]), ]), + history, }) render() - const postsLink = await screen.findByRole('link', { name: 'To first post' }) + const postsLink = await screen.findByRole('link', { + name: 'To first post', + }) expect(postsLink).toHaveAttribute('href', '/posts/id1/details') - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) - const invoicesErrorText = await screen.findByText( - 'Invariant failed: Could not find match for from: /invoices', + expect(consoleWarnSpy).toHaveBeenCalledWith( + 'Could not find match for from: /invoices', ) - expect(invoicesErrorText).toBeInTheDocument() + + consoleWarnSpy.mockRestore() }) test('when navigating to /posts/$postId/info which is declaratively masked as /posts/$postId', async () => { @@ -2633,6 +2673,7 @@ describe('Link', () => { const router = createRouter({ routeTree, routeMasks: [routeMask], + history, }) render() @@ -2720,6 +2761,7 @@ describe('Link', () => { const router = createRouter({ routeTree, + history, }) render() @@ -2838,6 +2880,7 @@ describe('Link', () => { const router = createRouter({ routeTree, defaultPreload: 'intent', + history, }) render() @@ -2848,13 +2891,13 @@ describe('Link', () => { expect(postLink).toHaveAttribute('href', '/posts/id1') - fireEvent.mouseOver(postLink) + await act(() => fireEvent.mouseOver(postLink)) await waitFor(() => expect(loaderFn).toHaveBeenCalled()) await waitFor(() => expect(search).toHaveBeenCalledWith({ postPage: 0 })) - fireEvent.click(postLink) + await act(() => fireEvent.click(postLink)) const loginText = await screen.findByText('Login!') expect(loginText).toBeInTheDocument() @@ -2926,7 +2969,7 @@ describe('Link', () => { }) const LoginComponent = () => { - return <>Login! + return
Login!
} const loginRoute = createRoute({ @@ -2944,6 +2987,7 @@ describe('Link', () => { const router = createRouter({ routeTree, + history, }) render() @@ -2954,10 +2998,9 @@ describe('Link', () => { expect(postLink).toHaveAttribute('href', '/posts/id1') - fireEvent.click(postLink) + await act(() => fireEvent.click(postLink)) - const loginText = await screen.findByText('Login!') - expect(loginText).toBeInTheDocument() + expect(await screen.findByTestId('login')).toBeInTheDocument() expect(ErrorComponent).not.toHaveBeenCalled() }) @@ -3044,6 +3087,7 @@ describe('Link', () => { const router = createRouter({ routeTree, + history, }) render() @@ -3054,7 +3098,7 @@ describe('Link', () => { expect(postLink).toHaveAttribute('href', '/posts/id1') - fireEvent.click(postLink) + await act(() => fireEvent.click(postLink)) const loginText = await screen.findByText('Login!') expect(loginText).toBeInTheDocument() @@ -3139,6 +3183,7 @@ describe('Link', () => { const router = createRouter({ routeTree, defaultPreload: 'intent', + history, }) render() @@ -3149,11 +3194,11 @@ describe('Link', () => { expect(postLink).toHaveAttribute('href', '/posts/id1') - fireEvent.mouseOver(postLink) + await act(() => fireEvent.mouseOver(postLink)) await waitFor(() => expect(search).toHaveBeenCalledWith({ postPage: 0 })) - fireEvent.click(postLink) + await act(() => fireEvent.click(postLink)) const loginText = await screen.findByText('Login!') expect(loginText).toBeInTheDocument() @@ -3175,7 +3220,11 @@ describe('Link', () => { return ( <>

Index

- + To first post @@ -3240,6 +3289,7 @@ describe('Link', () => { const router = createRouter({ routeTree, defaultPreload: 'intent', + history, }) render() @@ -3250,11 +3300,11 @@ describe('Link', () => { expect(postLink).toHaveAttribute('href', '/posts/id1') - fireEvent.mouseOver(postLink) + await act(() => fireEvent.mouseOver(postLink)) await waitFor(() => expect(search).toHaveBeenCalledWith({ postPage: 0 })) - fireEvent.click(postLink) + await act(() => fireEvent.click(postLink)) const loginText = await screen.findByText('Login!') expect(loginText).toBeInTheDocument() @@ -3332,13 +3382,14 @@ describe('Link', () => { const router = createRouter({ routeTree, + history, }) render() const postsLink = await screen.findByRole('link', { name: 'Go to posts' }) - fireEvent.click(postsLink) + await act(() => fireEvent.click(postsLink)) const fromPostsLink = await screen.findByRole('link', { name: 'From posts', @@ -3350,7 +3401,7 @@ describe('Link', () => { name: 'To invoices', }) - fireEvent.click(toInvoicesLink) + await act(() => fireEvent.click(toInvoicesLink)) const fromInvoicesLink = await screen.findByRole('link', { name: 'From invoices', @@ -3364,7 +3415,7 @@ describe('Link', () => { name: 'To posts', }) - fireEvent.click(toPostsLink) + await act(() => fireEvent.click(toPostsLink)) const onPostsText = await screen.findByText('On Posts') expect(onPostsText).toBeInTheDocument() @@ -3402,7 +3453,7 @@ describe('Link', () => { }) const routeTree = rootRoute.addChildren([indexRoute, postRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() @@ -3464,7 +3515,7 @@ describe('Link', () => { }) const routeTree = rootRoute.addChildren([indexRoute, postRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() @@ -3528,7 +3579,7 @@ describe('Link', () => { }) const routeTree = rootRoute.addChildren([indexRoute, postRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() @@ -3597,7 +3648,7 @@ describe('Link', () => { }) const routeTree = rootRoute.addChildren([indexRoute, postRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() @@ -3633,6 +3684,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute]), defaultPreload: preload, + history, }) render() @@ -3665,6 +3717,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute]), defaultPreload: preload, + history, }) render() @@ -3692,6 +3745,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute]), defaultPreload: 'viewport', + history, }) render() @@ -3736,6 +3790,7 @@ describe('Link', () => { const router = createRouter({ routeTree: rootRoute.addChildren([aboutRoute, indexRoute]), defaultPreload: 'render', + history, }) render() @@ -3776,6 +3831,7 @@ describe('Link', () => { defaultPreload: 'intent', defaultPendingMs: 200, defaultPendingComponent: () =>

Loading...

, + history, }) render() @@ -3889,6 +3945,7 @@ describe('Link', () => { const router = createRouter({ routeTree, defaultPreload: 'intent', + history, }) render() @@ -3940,6 +3997,7 @@ describe('createLink', () => { }) const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute]), + history, }) render() @@ -3969,6 +4027,7 @@ describe('createLink', () => { }) const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute]), + history, }) render() @@ -4048,6 +4107,7 @@ describe('createLink', () => { }) const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -4309,6 +4369,7 @@ describe('search middleware', () => { postsRoute.addChildren([postsNewRoute]), invoicesRoute, ]), + history, }) window.history.replaceState(null, 'root', '/?root=abc') @@ -4400,6 +4461,7 @@ describe('search middleware', () => { indexRoute, postsRoute.addChildren([postRoute]), ]), + history, }) render() @@ -4410,3 +4472,348 @@ describe('search middleware', () => { }) }) }) + +describe('relative links', () => { + const setupRouter = () => { + const rootRoute = createRootRoute() + const indexRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/', + component: () => { + return

Index Route

+ }, + }) + const aRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'a', + component: () => { + return ( + <> +

A Route

+ + + ) + }, + }) + + const bRoute = createRoute({ + getParentRoute: () => aRoute, + path: 'b', + component: () => { + return ( + <> +

B Route

+ Link to Parent + + ) + }, + }) + + const paramRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'param/$param', + component: () => { + return ( + <> +

Param Route

+ Link to ./a + + Link to c + + + Link to ../c + + + + ) + }, + }) + + const paramARoute = createRoute({ + getParentRoute: () => paramRoute, + path: 'a', + component: () => { + return ( + <> +

Param A Route

+ Link to .. from /param/foo/a + + + ) + }, + }) + + const paramBRoute = createRoute({ + getParentRoute: () => paramARoute, + path: 'b', + component: () => { + return ( + <> +

Param B Route

+ Link to Parent + + Link to Parent with param:bar + + ({ ...prev, param: 'bar' })} + > + Link to Parent with param:bar functional + + + ) + }, + }) + + const paramCRoute = createRoute({ + getParentRoute: () => paramARoute, + path: 'c', + component: () => { + return

Param C Route

+ }, + }) + + const splatRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'splat/$', + component: () => { + return ( + <> +

Splat Route

+ + Unsafe link to .. + + + Unsafe link to . + + + Unsafe link to ./child + + + ) + }, + }) + + return createRouter({ + routeTree: rootRoute.addChildren([ + indexRoute, + aRoute.addChildren([bRoute]), + paramRoute.addChildren([ + paramARoute.addChildren([paramBRoute, paramCRoute]), + ]), + splatRoute, + ]), + history, + }) + } + + test('should navigate to the parent route', async () => { + const router = setupRouter() + + render() + + // Navigate to /a/b + await act(async () => { + history.push('/a/b') + }) + + // Inspect the link to go up a parent + const parentLink = await screen.findByText('Link to Parent') + expect(parentLink.getAttribute('href')).toBe('/a') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(parentLink) + }) + + expect(window.location.pathname).toBe('/a') + }) + + test('should navigate to the parent route and keep params', async () => { + const router = setupRouter() + + render() + + // Navigate to /param/oldParamValue/a/b + await act(async () => { + history.push('/param/foo/a/b') + }) + + // Inspect the link to go up a parent and keep the params + const parentLink = await screen.findByText('Link to Parent') + expect(parentLink.getAttribute('href')).toBe('/param/foo/a') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(parentLink) + }) + + expect(window.location.pathname).toBe('/param/foo/a') + }) + + test('should navigate to the parent route and change params', async () => { + const router = setupRouter() + + render() + + // Navigate to /param/oldParamValue/a/b + await act(async () => { + history.push('/param/foo/a/b') + }) + + // Inspect the link to go up a parent and keep the params + const parentLink = await screen.findByText('Link to Parent with param:bar') + expect(parentLink.getAttribute('href')).toBe('/param/bar/a') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(parentLink) + }) + + expect(window.location.pathname).toBe('/param/bar/a') + }) + + test('should navigate to a relative link based on render location', async () => { + const router = setupRouter() + + render() + + await act(async () => { + history.push('/param/foo/a/b') + }) + + // Inspect the relative link to ./a + const relativeLink = await screen.findByText('Link to ./a') + expect(relativeLink.getAttribute('href')).toBe('/param/foo/a') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(relativeLink) + }) + + expect(window.location.pathname).toBe('/param/foo/a') + }) + + test('should navigate to a parent link based on render location', async () => { + const router = setupRouter() + + render() + + await act(async () => { + history.push('/param/foo/a/b') + }) + + // Inspect the relative link to ./a + const relativeLink = await screen.findByText('Link to .. from /param/foo/a') + expect(relativeLink.getAttribute('href')).toBe('/param/foo') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(relativeLink) + }) + + expect(window.location.pathname).toBe('/param/foo') + }) + + test('should navigate to a child link based on pathname', async () => { + const router = setupRouter() + + render() + + await act(async () => { + history.push('/param/foo/a/b') + }) + + // Inspect the relative link to ./a + const relativeLink = await screen.findByText('Link to c') + expect(relativeLink.getAttribute('href')).toBe('/param/foo/a/b/c') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(relativeLink) + }) + + expect(window.location.pathname).toBe('/param/foo/a/b/c') + }) + + test('should navigate to a relative link based on pathname', async () => { + const router = setupRouter() + + render() + + await act(async () => { + history.push('/param/foo/a/b') + }) + + // Inspect the relative link to ./a + const relativeLink = await screen.findByText('Link to ../c') + expect(relativeLink.getAttribute('href')).toBe('/param/foo/a/c') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(relativeLink) + }) + + expect(window.location.pathname).toBe('/param/foo/a/c') + }) + + test('should navigate to parent inside of splat route based on pathname', async () => { + const router = setupRouter() + + render() + + await act(async () => { + history.push('/splat/a/b/c/d') + }) + + const relativeLink = await screen.findByText('Unsafe link to ..') + expect(relativeLink.getAttribute('href')).toBe('/splat/a/b/c') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(relativeLink) + }) + + expect(window.location.pathname).toBe('/splat/a/b/c') + }) + + test('should navigate to same route inside of splat route based on pathname', async () => { + const router = setupRouter() + + render() + + await act(async () => { + history.push('/splat/a/b/c') + }) + + const relativeLink = await screen.findByText('Unsafe link to .') + expect(relativeLink.getAttribute('href')).toBe('/splat/a/b/c') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(relativeLink) + }) + + expect(window.location.pathname).toBe('/splat/a/b/c') + }) + + test('should navigate to child route inside of splat route based on pathname', async () => { + const router = setupRouter() + + render() + + await act(async () => { + history.push('/splat/a/b/c') + }) + + const relativeLink = await screen.findByText('Unsafe link to ./child') + expect(relativeLink.getAttribute('href')).toBe('/splat/a/b/c/child') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(relativeLink) + }) + + expect(window.location.pathname).toBe('/splat/a/b/c/child') + }) +}) diff --git a/packages/react-router/tests/loaders.test.tsx b/packages/react-router/tests/loaders.test.tsx index 85a9dc15f9..ab1e671fad 100644 --- a/packages/react-router/tests/loaders.test.tsx +++ b/packages/react-router/tests/loaders.test.tsx @@ -6,21 +6,31 @@ import { screen, } from '@testing-library/react' -import { afterEach, describe, expect, test, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { z } from 'zod' import { Link, Outlet, RouterProvider, + createBrowserHistory, createRootRoute, createRoute, createRouter, } from '../src' import { sleep } from './utils' +import type { RouterHistory } from '../src' + +let history: RouterHistory + +beforeEach(() => { + history = createBrowserHistory() + expect(window.location.pathname).toBe('/') +}) afterEach(() => { + history.destroy() vi.resetAllMocks() window.history.replaceState(null, 'root', '/') cleanup() @@ -45,7 +55,7 @@ describe('loaders are being called', () => { component: () =>
Index page
, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() @@ -96,7 +106,7 @@ describe('loaders are being called', () => { nestedRoute.addChildren([fooRoute]), indexRoute, ]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() @@ -152,7 +162,7 @@ describe('loaders parentMatchPromise', () => { nestedRoute.addChildren([fooRoute]), indexRoute, ]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() @@ -190,7 +200,7 @@ test('reproducer for #2031', async () => { }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() @@ -220,6 +230,7 @@ test('reproducer for #2053', async () => { const router = createRouter({ routeTree, + history, }) render() @@ -244,6 +255,7 @@ test('reproducer for #2198 - throw error from beforeLoad upon initial load', asy const routeTree = rootRoute.addChildren([indexRoute]) const router = createRouter({ routeTree, + history, defaultErrorComponent: () => { return
defaultErrorComponent
}, @@ -271,6 +283,7 @@ test('throw error from loader upon initial load', async () => { const routeTree = rootRoute.addChildren([indexRoute]) const router = createRouter({ routeTree, + history, defaultErrorComponent: () => { return
defaultErrorComponent
}, @@ -309,6 +322,7 @@ test('throw error from beforeLoad when navigating to route', async () => { const routeTree = rootRoute.addChildren([indexRoute, fooRoute]) const router = createRouter({ routeTree, + history, defaultErrorComponent: () => { return
defaultErrorComponent
}, diff --git a/packages/react-router/tests/navigate.test.tsx b/packages/react-router/tests/navigate.test.tsx index b0175eb26b..033b9702db 100644 --- a/packages/react-router/tests/navigate.test.tsx +++ b/packages/react-router/tests/navigate.test.tsx @@ -566,4 +566,21 @@ describe('relative navigation', () => { expect(router.state.location.pathname).toBe('/posts/tkdodo') }) + + it('should navigate to a parent route with .. from unsafe relative path', async () => { + const { router } = createTestRouter( + createMemoryHistory({ initialEntries: ['/posts/tanner/child'] }), + ) + + await router.load() + + expect(router.state.location.pathname).toBe('/posts/tanner/child') + + await router.navigate({ + to: '..', + unsafeRelative: 'path', + }) + + expect(router.state.location.pathname).toBe('/posts/tanner') + }) }) diff --git a/packages/react-router/tests/redirect.test.tsx b/packages/react-router/tests/redirect.test.tsx index 91f0196841..56d0d80049 100644 --- a/packages/react-router/tests/redirect.test.tsx +++ b/packages/react-router/tests/redirect.test.tsx @@ -6,11 +6,13 @@ import { screen, } from '@testing-library/react' -import { afterEach, describe, expect, test, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' +import invariant from 'tiny-invariant' import { Link, RouterProvider, + createBrowserHistory, createMemoryHistory, createRootRoute, createRoute, @@ -20,8 +22,17 @@ import { } from '../src' import { sleep } from './utils' +import type { RouterHistory } from '../src' + +let history: RouterHistory + +beforeEach(() => { + history = createBrowserHistory() + expect(window.location.pathname).toBe('/') +}) afterEach(() => { + history.destroy() vi.clearAllMocks() vi.resetAllMocks() window.history.replaceState(null, 'root', '/') @@ -80,7 +91,7 @@ describe('redirect', () => { aboutRoute, indexRoute, ]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() @@ -157,7 +168,7 @@ describe('redirect', () => { aboutRoute, indexRoute, ]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() @@ -235,7 +246,7 @@ describe('redirect', () => { indexRoute, finalRoute, ]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() @@ -280,11 +291,18 @@ describe('redirect', () => { routeTree: rootRoute.addChildren([indexRoute, aboutRoute]), // Mock server mode isServer: true, + history: createMemoryHistory({ + initialEntries: ['/'], + }), }) await router.load() - expect(router.state.redirect).toEqual({ + expect(router.state.redirect).toBeDefined() + expect(router.state.redirect).toBeInstanceOf(Response) + invariant(router.state.redirect) + + expect(router.state.redirect.options).toEqual({ _fromLocation: expect.objectContaining({ hash: '', href: '/', @@ -293,12 +311,7 @@ describe('redirect', () => { searchStr: '', }), to: '/about', - headers: {}, - reloadDocument: false, href: '/about', - isRedirect: true, - routeId: '/', - routerCode: 'BEFORE_LOAD', statusCode: 307, }) }) @@ -329,27 +342,33 @@ describe('redirect', () => { initialEntries: ['/'], }), routeTree: rootRoute.addChildren([indexRoute, aboutRoute]), + // Mock server mode + isServer: true, }) - // Mock server mode - router.isServer = true - await router.load() - expect(router.state.redirect).toEqual({ - _fromLocation: expect.objectContaining({ + const currentRedirect = router.state.redirect + + expect(currentRedirect).toBeDefined() + expect(currentRedirect).toBeInstanceOf(Response) + invariant(currentRedirect) + expect(currentRedirect.status).toEqual(307) + expect(currentRedirect.headers.get('Location')).toEqual('/about') + expect(currentRedirect.options).toEqual({ + _fromLocation: { hash: '', href: '/', pathname: '/', search: {}, searchStr: '', - }), - to: '/about', - headers: {}, + state: { + __TSR_index: 0, + key: currentRedirect.options._fromLocation!.state.key, + }, + }, href: '/about', - isRedirect: true, - reloadDocument: false, - routeId: '/', + to: '/about', statusCode: 307, }) }) diff --git a/packages/react-router/tests/route.test-d.tsx b/packages/react-router/tests/route.test-d.tsx index 2183cf4af7..ed2ece1bc9 100644 --- a/packages/react-router/tests/route.test-d.tsx +++ b/packages/react-router/tests/route.test-d.tsx @@ -643,6 +643,8 @@ test('when creating a child route with a param and splat param from the root rou routeTree: rootRoute.addChildren([invoicesRoute]), }) + const params = invoicesRoute.useParams() + expectTypeOf(invoicesRoute.useParams()).toEqualTypeOf<{ invoiceId: string _splat?: string @@ -1776,3 +1778,149 @@ test('when creating a child route with an explicit search input', () => { .parameter(0) .toEqualTypeOf<{ page: string }>() }) + +test('when creating a route with a prefix and suffix', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'prefix{$postId}suffix', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf<{ + postId: string + }>() +}) + +test('when creating a route with a optional prefix and suffix', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'prefix{-$postId}suffix', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf<{ + postId?: string + }>() +}) + +test('when creating a route with a splat prefix and suffix', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'prefix{$}suffix', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf<{ + _splat?: string + }>() +}) + +test('when creating a route with a splat, optional param and required param', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'docs/$docId/$/{-$detailId}/{$myFile}.pdf', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf<{ + docId: string + _splat?: string + myFile: string + detailId?: string + }>() +}) + +test('when creating a route with a boundary splat, optional param and required param', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'docs/$docId/before{$}after/detail{-$detailId}/file-{$myFile}.pdf', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf<{ + docId: string + _splat?: string + myFile: string + detailId?: string + }>() +}) + +test('when creating a route with a nested boundary splat, optional param and required param', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'docs/$docId/before{$}after/{-detail{$detailId}suffix}/file-{$myFile}.pdf', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf<{ + docId: string + _splat?: string + myFile: string + detailId?: string + }>() +}) + +test('when creating a route with a nested boundary splat, optional param, required param and escaping', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'docs/$docId/before{$}after/{-detail{$detailId}suffix}[.$test]/file-{$myFile}[.]pdf/escape-param[$postId]', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf<{ + docId: string + _splat?: string + myFile: string + detailId?: string + }>() +}) + +test('when creating a route with escaped path param', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '[$postId]', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf<{}>() +}) diff --git a/packages/react-router/tests/route.test.tsx b/packages/react-router/tests/route.test.tsx index 9c6fbbfc0e..ba30768dea 100644 --- a/packages/react-router/tests/route.test.tsx +++ b/packages/react-router/tests/route.test.tsx @@ -1,16 +1,27 @@ import React from 'react' -import { afterEach, describe, expect, it, test, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, it, test, vi } from 'vitest' import { cleanup, render, screen } from '@testing-library/react' import { RouterProvider, + createBrowserHistory, createRootRoute, createRoute, createRouter, getRouteApi, + notFound, } from '../src' +import type { RouterHistory } from '../src' + +let history: RouterHistory + +beforeEach(() => { + history = createBrowserHistory() + expect(window.location.pathname).toBe('/') +}) afterEach(() => { + history.destroy() vi.resetAllMocks() window.history.replaceState(null, 'root', '/') cleanup() @@ -162,7 +173,7 @@ describe('onEnter event', () => { }, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree, context: { foo: 'bar' } }) + const router = createRouter({ routeTree, context: { foo: 'bar' }, history }) await router.load() @@ -183,7 +194,7 @@ describe('onEnter event', () => { }, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree, context: { foo: 'bar' } }) + const router = createRouter({ routeTree, context: { foo: 'bar' }, history }) render() @@ -215,7 +226,7 @@ describe('route.head', () => { component: () =>
Index
, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() const indexElem = await screen.findByText('Index') expect(indexElem).toBeInTheDocument() @@ -255,7 +266,7 @@ describe('route.head', () => { component: () =>
Index
, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() const indexElem = await screen.findByText('Index') expect(indexElem).toBeInTheDocument() @@ -272,6 +283,85 @@ describe('route.head', () => { ]) }) + test('meta is set when loader throws notFound', async () => { + const rootRoute = createRootRoute({ + head: () => ({ + meta: [ + { title: 'Root' }, + { + charSet: 'utf-8', + }, + ], + }), + }) + const indexRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/', + head: () => ({ + meta: [{ title: 'Index' }], + }), + loader: async () => { + throw notFound() + }, + component: () =>
Index
, + }) + const routeTree = rootRoute.addChildren([indexRoute]) + const router = createRouter({ routeTree }) + render() + expect(await screen.findByText('Not Found')).toBeInTheDocument() + + const metaState = router.state.matches.map((m) => m.meta) + expect(metaState).toEqual([ + [ + { title: 'Root' }, + { + charSet: 'utf-8', + }, + ], + [{ title: 'Index' }], + ]) + }) + + test('meta is set when loader throws an error', async () => { + const rootRoute = createRootRoute({ + head: () => ({ + meta: [ + { title: 'Root' }, + { + charSet: 'utf-8', + }, + ], + }), + }) + const indexRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/', + head: () => ({ + meta: [{ title: 'Index' }], + }), + loader: async () => { + throw new Error('Fly, you fools!') + }, + component: () =>
Index
, + }) + const routeTree = rootRoute.addChildren([indexRoute]) + const router = createRouter({ routeTree }) + render() + + expect(await screen.findByText('Fly, you fools!')).toBeInTheDocument() + + const metaState = router.state.matches.map((m) => m.meta) + expect(metaState).toEqual([ + [ + { title: 'Root' }, + { + charSet: 'utf-8', + }, + ], + [{ title: 'Index' }], + ]) + }) + test('scripts', async () => { const rootRoute = createRootRoute({ head: () => ({ @@ -287,7 +377,7 @@ describe('route.head', () => { component: () =>
Index
, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() const indexElem = await screen.findByText('Index') expect(indexElem).toBeInTheDocument() @@ -317,7 +407,7 @@ describe('route.head', () => { component: () =>
Index
, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() const indexElem = await screen.findByText('Index') expect(indexElem).toBeInTheDocument() @@ -344,7 +434,7 @@ describe('route.head', () => { component: () =>
Index
, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() const indexElem = await screen.findByText('Index') expect(indexElem).toBeInTheDocument() @@ -374,7 +464,7 @@ describe('route.head', () => { component: () =>
Index
, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render() const indexElem = await screen.findByText('Index') expect(indexElem).toBeInTheDocument() diff --git a/packages/react-router/tests/routeContext.test.tsx b/packages/react-router/tests/routeContext.test.tsx index c62decee7f..7a38a272d9 100644 --- a/packages/react-router/tests/routeContext.test.tsx +++ b/packages/react-router/tests/routeContext.test.tsx @@ -122,7 +122,6 @@ describe('context function', () => { await clickButton('detail-1') await findByText('Detail page: 1') - console.log(mockContextFn.mock.calls) expect(mockContextFn).toHaveBeenCalledOnce() expect(mockContextFn).toHaveBeenCalledWith({ id: 1 }) mockContextFn.mockClear() @@ -1457,7 +1456,7 @@ describe('beforeLoad in the route definition', () => { } await check(1) - await router.invalidate() + await act(async () => await router.invalidate()) await check(2) }) }) diff --git a/packages/react-router/tests/router.test.tsx b/packages/react-router/tests/router.test.tsx index 1a295a3b0b..0b720dd58d 100644 --- a/packages/react-router/tests/router.test.tsx +++ b/packages/react-router/tests/router.test.tsx @@ -13,6 +13,7 @@ import { Outlet, RouterProvider, SearchParamError, + createBrowserHistory, createMemoryHistory, createRootRoute, createRoute, @@ -24,14 +25,23 @@ import type { AnyRoute, AnyRouter, MakeRemountDepsOptionsUnion, + RouterHistory, RouterOptions, ValidatorFn, ValidatorObj, } from '../src' +let history: RouterHistory +beforeEach(() => { + history = createBrowserHistory() + expect(window.location.pathname).toBe('/') +}) + afterEach(() => { - vi.resetAllMocks() + history.destroy() window.history.replaceState(null, 'root', '/') + vi.clearAllMocks() + vi.resetAllMocks() cleanup() }) @@ -48,7 +58,10 @@ export function validateSearchParams< expect(router.state.location.search).toEqual(expected) } -function createTestRouter(options?: RouterOptions) { +function createTestRouter( + options: RouterOptions & + Required, 'history'>>, +) { const rootRoute = createRootRoute({ validateSearch: z.object({ root: z.string().optional() }), component: () => { @@ -975,6 +988,7 @@ describe('router rendering stability', () => { const router = createRouter({ routeTree, defaultRemountDeps: opts?.remountDeps.default, + history: createMemoryHistory({ initialEntries: ['/'] }), }) await act(() => render()) @@ -1196,6 +1210,15 @@ describe('invalidate', () => { }) describe('search params in URL', () => { + let history: RouterHistory + beforeEach(() => { + history = createBrowserHistory() + expect(window.location.pathname).toBe('/') + }) + afterEach(() => { + history.destroy() + window.history.replaceState(null, 'root', '/') + }) const testCases = [ { route: '/', search: { root: 'world' } }, { route: '/', search: { root: 'world', unknown: 'asdf' } }, @@ -1212,7 +1235,7 @@ describe('search params in URL', () => { it.each(testCases)( 'at $route with search params $search', async ({ route, search }) => { - const { router } = createTestRouter({ search: { strict } }) + const { router } = createTestRouter({ search: { strict }, history }) window.history.replaceState( null, '', @@ -1238,7 +1261,7 @@ describe('search params in URL', () => { describe('removes unknown search params in the URL when search.strict=true', () => { it.each(testCases)('%j', async ({ route, search }) => { - const { router } = createTestRouter({ search: { strict: true } }) + const { router } = createTestRouter({ search: { strict: true }, history }) window.history.replaceState( null, '', @@ -1264,7 +1287,7 @@ describe('search params in URL', () => { describe.each([false, true, undefined])('default search params', (strict) => { let router: AnyRouter beforeEach(() => { - const result = createTestRouter({ search: { strict } }) + const result = createTestRouter({ search: { strict }, history }) router = result.router }) @@ -1584,6 +1607,7 @@ const createHistoryRouter = () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) return { router } @@ -1716,7 +1740,13 @@ it('does not push to history if url and state are the same', async () => { }) describe('does not strip search params if search validation fails', () => { + let history: RouterHistory + + beforeEach(() => { + history = createBrowserHistory() + }) afterEach(() => { + history.destroy() window.history.replaceState(null, 'root', '/') cleanup() }) @@ -1751,7 +1781,7 @@ describe('does not strip search params if search validation fails', () => { const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) return router } diff --git a/packages/react-router/tests/searchMiddleware.test.tsx b/packages/react-router/tests/searchMiddleware.test.tsx index 36b4ebb58e..6629dab085 100644 --- a/packages/react-router/tests/searchMiddleware.test.tsx +++ b/packages/react-router/tests/searchMiddleware.test.tsx @@ -1,9 +1,10 @@ -import { afterEach, describe, expect, it, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { cleanup, fireEvent, render, screen } from '@testing-library/react' import { Link, RouterProvider, + createBrowserHistory, createRootRoute, createRoute, createRouter, @@ -11,12 +12,21 @@ import { stripSearchParams, } from '../src' import { getSearchParamsFromURI } from './utils' -import type { AnyRouter } from '../src' +import type { AnyRouter, RouterHistory } from '../src' import type { SearchMiddleware } from '@tanstack/router-core' +let history: RouterHistory + +beforeEach(() => { + history = createBrowserHistory() + expect(window.location.pathname).toBe('/') +}) + afterEach(() => { - vi.resetAllMocks() + history.destroy() window.history.replaceState(null, 'root', '/') + vi.clearAllMocks() + vi.resetAllMocks() cleanup() }) @@ -70,6 +80,7 @@ function setupTest(opts: { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) window.history.replaceState( null, diff --git a/packages/react-router/tests/useBlocker.test.tsx b/packages/react-router/tests/useBlocker.test.tsx index 01dc7cf548..3b780775bd 100644 --- a/packages/react-router/tests/useBlocker.test.tsx +++ b/packages/react-router/tests/useBlocker.test.tsx @@ -1,20 +1,32 @@ import React from 'react' import '@testing-library/jest-dom/vitest' -import { afterEach, describe, expect, test, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { cleanup, fireEvent, render, screen } from '@testing-library/react' import { z } from 'zod' import { RouterProvider, + createBrowserHistory, createRootRoute, createRoute, createRouter, useBlocker, useNavigate, } from '../src' +import type { RouterHistory } from '../src' + +let history: RouterHistory + +beforeEach(() => { + history = createBrowserHistory() + expect(window.location.pathname).toBe('/') +}) afterEach(() => { + history.destroy() window.history.replaceState(null, 'root', '/') + vi.clearAllMocks() + vi.resetAllMocks() cleanup() }) @@ -56,6 +68,7 @@ describe('useBlocker', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -108,6 +121,7 @@ describe('useBlocker', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -160,6 +174,7 @@ describe('useBlocker', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -216,6 +231,7 @@ describe('useBlocker', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -302,6 +318,7 @@ describe('useBlocker', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -394,6 +411,7 @@ describe('useBlocker', () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute, invoicesRoute]), + history, }) type Router = typeof router diff --git a/packages/react-router/tests/useMatch.test.tsx b/packages/react-router/tests/useMatch.test.tsx index 67f68e3011..9bf809f666 100644 --- a/packages/react-router/tests/useMatch.test.tsx +++ b/packages/react-router/tests/useMatch.test.tsx @@ -39,6 +39,8 @@ describe('useMatch', () => { ), }) + history = history || createMemoryHistory({ initialEntries: ['/'] }) + const postsRoute = createRoute({ getParentRoute: () => rootRoute, path: '/posts', diff --git a/packages/react-router/tests/useNavigate.test.tsx b/packages/react-router/tests/useNavigate.test.tsx index 7449de1918..95d5742ea3 100644 --- a/packages/react-router/tests/useNavigate.test.tsx +++ b/packages/react-router/tests/useNavigate.test.tsx @@ -1,6 +1,6 @@ -import React from 'react' +import React, { act } from 'react' import '@testing-library/jest-dom/vitest' -import { afterEach, describe, expect, test, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { cleanup, configure, @@ -14,6 +14,7 @@ import { Navigate, Outlet, RouterProvider, + createBrowserHistory, createRootRoute, createRoute, createRouteMask, @@ -22,9 +23,20 @@ import { useNavigate, useParams, } from '../src' +import type { RouterHistory } from '../src' + +let history: RouterHistory + +beforeEach(() => { + history = createBrowserHistory() + expect(window.location.pathname).toBe('/') +}) afterEach(() => { + history.destroy() window.history.replaceState(null, 'root', '/') + vi.clearAllMocks() + vi.resetAllMocks() cleanup() }) @@ -62,6 +74,7 @@ test('when navigating to /posts', async () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) render() @@ -275,6 +288,7 @@ test('when navigating from /posts to ../posts/$postId', async () => { indexRoute, postsRoute.addChildren([postsIndexRoute, postRoute]), ]), + history, }) render() @@ -412,6 +426,7 @@ test('when navigating from /posts/$postId to /posts/$postId/info and the current ]), ]), ]), + history, }) render() @@ -555,6 +570,7 @@ test('when navigating from /posts/$postId to ./info and the current route is /po ]), ]), ]), + history, }) render() @@ -698,6 +714,7 @@ test('when navigating from /posts/$postId to ../$postId and the current route is ]), ]), ]), + history, }) render() @@ -849,6 +866,7 @@ test('when navigating from /posts/$postId with an index to ../$postId and the cu ]), ]), ]), + history, }) render() @@ -1029,8 +1047,11 @@ test('when navigating from /invoices to ./invoiceId and the current route is /po ]), ]), ]), + history, }) + const consoleWarn = vi.spyOn(console, 'warn').mockImplementation(() => {}) + render() const postsButton = await screen.findByRole('button', { @@ -1045,7 +1066,11 @@ test('when navigating from /invoices to ./invoiceId and the current route is /po fireEvent.click(invoicesButton) - expect(await screen.findByText('Something went wrong!')).toBeInTheDocument() + expect(consoleWarn).toHaveBeenCalledWith( + 'Could not find match for from: /invoices', + ) + + consoleWarn.mockRestore() }) test('when navigating to /posts/$postId/info which is masked as /posts/$postId', async () => { @@ -1132,6 +1157,7 @@ test('when navigating to /posts/$postId/info which is masked as /posts/$postId', const router = createRouter({ routeTree, routeMasks: [routeMask], + history, }) render() @@ -1226,6 +1252,7 @@ test('when navigating to /posts/$postId/info which is imperatively masked as /po const router = createRouter({ routeTree, + history, }) render() @@ -1283,6 +1310,7 @@ test('when setting search params with 2 parallel navigate calls', async () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute]), + history, }) render() @@ -1327,6 +1355,7 @@ test(' navigates only once in ', async () => { const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute, postsRoute]), + history, }) const navigateSpy = vi.spyOn(router, 'navigate') @@ -1486,3 +1515,237 @@ describe('when on /posts/$postId and navigating to ../ with default `from` /post test('Route', () => runTest('Route')) test('RouteApi', () => runTest('RouteApi')) }) + +describe('relative useNavigate', () => { + const setupRouter = () => { + const rootRoute = createRootRoute() + const indexRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/', + component: () => { + return

Index Route

+ }, + }) + const aRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'a', + component: () => { + return ( + <> +

A Route

+ + + ) + }, + }) + + const bRoute = createRoute({ + getParentRoute: () => aRoute, + path: 'b', + component: function BRoute() { + const navigate = useNavigate() + return ( + <> +

B Route

+ + + ) + }, + }) + + const paramRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'param/$param', + component: function ParamRoute() { + const navigate = useNavigate() + return ( + <> +

Param Route

+ + + + + ) + }, + }) + + const paramARoute = createRoute({ + getParentRoute: () => paramRoute, + path: 'a', + component: function ParamARoute() { + const navigate = useNavigate() + return ( + <> +

Param A Route

+ + + + ) + }, + }) + + const paramBRoute = createRoute({ + getParentRoute: () => paramARoute, + path: 'b', + component: function ParamBRoute() { + const navigate = useNavigate() + return ( + <> +

Param B Route

+ + + + + ) + }, + }) + + return createRouter({ + routeTree: rootRoute.addChildren([ + indexRoute, + aRoute.addChildren([bRoute]), + paramRoute.addChildren([paramARoute, paramBRoute]), + ]), + history, + }) + } + + test('should navigate to the parent route', async () => { + const router = setupRouter() + + render() + + // Navigate to /a/b + await act(async () => { + history.push('/a/b') + }) + + // Inspect the link to go up a parent + const parentLink = await screen.findByText('Link to Parent') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(parentLink) + }) + + expect(window.location.pathname).toBe('/a') + }) + + test('should navigate to the parent route and keep params', async () => { + const router = setupRouter() + + render() + + // Navigate to /param/oldParamValue/a/b + await act(async () => { + history.push('/param/foo/a/b') + }) + + // Inspect the link to go up a parent and keep the params + const parentLink = await screen.findByText('Link to Parent') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(parentLink) + }) + + expect(window.location.pathname).toBe('/param/foo/a') + }) + + test('should navigate to the parent route and change params', async () => { + const router = setupRouter() + + render() + + // Navigate to /param/oldParamValue/a/b + await act(async () => { + history.push('/param/foo/a/b') + }) + + // Inspect the link to go up a parent and keep the params + const parentLink = await screen.findByText('Link to Parent with param:bar') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(parentLink) + }) + + expect(window.location.pathname).toBe('/param/bar/a') + }) + + test('should navigate to a relative link based on render location', async () => { + const router = setupRouter() + + render() + + await act(async () => { + history.push('/param/foo/a/b') + }) + + // Inspect the relative link to ./a + const relativeLink = await screen.findByText('Link to ./a') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(relativeLink) + }) + + expect(window.location.pathname).toBe('/param/foo/a') + }) + + test('should navigate to a parent link based on render location', async () => { + const router = setupRouter() + + render() + + await act(async () => { + history.push('/param/foo/a/b') + }) + + // Inspect the relative link to ./a + const relativeLink = await screen.findByText('Link to .. from /param/foo/a') + + // Click the link and ensure the new location + await act(async () => { + fireEvent.click(relativeLink) + }) + + expect(window.location.pathname).toBe('/param/foo') + }) + + test('should navigate to same route with different params', async () => { + const router = setupRouter() + + render() + + await act(async () => { + history.push('/param/foo/a/b') + }) + + const parentLink = await screen.findByText('Link to . with param:bar') + + await act(async () => { + fireEvent.click(parentLink) + }) + + expect(window.location.pathname).toBe('/param/bar/a/b') + }) +}) diff --git a/packages/react-start-client/README.md b/packages/react-start-client/README.md index bb009b0c87..ba94d88108 100644 --- a/packages/react-start-client/README.md +++ b/packages/react-start-client/README.md @@ -1,33 +1,9 @@ -> 🤫 we're cooking up something special! - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! +# TanStack React Start - Client - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - +This package is not meant to be used directly. It is a dependency of [`@tanstack/react-start`](https://www.npmjs.com/package/@tanstack/react-start). -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) +TanStack React Start is a fullstack-framework made for SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router). -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! +Head over to [tanstack.com/start](https://tanstack.com/start) for more information about getting started. diff --git a/packages/react-start-client/package.json b/packages/react-start-client/package.json index a83ed07e55..5680a185b4 100644 --- a/packages/react-start-client/package.json +++ b/packages/react-start-client/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-start-client", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -69,8 +69,7 @@ "cookie-es": "^1.2.2", "jsesc": "^3.1.0", "tiny-invariant": "^1.3.3", - "tiny-warning": "^1.0.3", - "vinxi": "^0.5.3" + "tiny-warning": "^1.0.3" }, "devDependencies": { "@testing-library/react": "^16.2.0", diff --git a/packages/react-start-client/src/index.tsx b/packages/react-start-client/src/index.tsx index 6b9c30ee8f..3aebc26282 100644 --- a/packages/react-start-client/src/index.tsx +++ b/packages/react-start-client/src/index.tsx @@ -1,6 +1,15 @@ -/// -export { mergeHeaders } from '@tanstack/start-client-core' -export { startSerializer } from '@tanstack/start-client-core' +export { + mergeHeaders, + startSerializer, + createIsomorphicFn, + createServerFn, + createMiddleware, + registerGlobalMiddleware, + globalMiddleware, + serverOnly, + clientOnly, + json, +} from '@tanstack/start-client-core' export { type DehydratedRouter, type ClientExtractedBaseEntry, @@ -10,16 +19,10 @@ export { type ClientExtractedPromise, type ClientExtractedStream, type ResolvePromiseState, -} from '@tanstack/start-client-core' -export { - createIsomorphicFn, type IsomorphicFn, type ServerOnlyFn, type ClientOnlyFn, type IsomorphicFnBase, -} from '@tanstack/start-client-core' -export { createServerFn } from '@tanstack/start-client-core' -export { type ServerFn as FetchFn, type ServerFnCtx as FetchFnCtx, type CompiledFetcherFnOptions, @@ -31,43 +34,33 @@ export { type ServerFn, type ServerFnCtx, type ServerFnResponseType, -} from '@tanstack/start-client-core' -export { type JsonResponse } from '@tanstack/start-client-core' -export { - createMiddleware, + type JsonResponse, type IntersectAllValidatorInputs, type IntersectAllValidatorOutputs, - type MiddlewareServerFn, - type AnyMiddleware, - type MiddlewareOptions, - type MiddlewareWithTypes, - type MiddlewareValidator, - type MiddlewareServer, - type MiddlewareAfterClient, - type MiddlewareAfterMiddleware, - type MiddlewareAfterServer, - type Middleware, - type MiddlewareClientFnOptions, - type MiddlewareClientFnResult, - type MiddlewareClientNextFn, - type ClientResultWithContext, + type FunctionMiddlewareServerFn, + type AnyFunctionMiddleware, + type FunctionMiddlewareOptions, + type FunctionMiddlewareWithTypes, + type FunctionMiddlewareValidator, + type FunctionMiddlewareServer, + type FunctionMiddlewareAfterClient, + type FunctionMiddlewareAfterServer, + type FunctionMiddleware, + type FunctionMiddlewareClientFnOptions, + type FunctionMiddlewareClientFnResult, + type FunctionMiddlewareClientNextFn, + type FunctionClientResultWithContext, type AssignAllClientContextBeforeNext, type AssignAllMiddleware, type AssignAllServerContext, - type MiddlewareAfterValidator, - type MiddlewareClientFn, - type MiddlewareServerFnResult, - type MiddlewareClient, - type MiddlewareServerFnOptions, - type MiddlewareServerNextFn, - type ServerResultWithContext, -} from '@tanstack/start-client-core' -export { - registerGlobalMiddleware, - globalMiddleware, + type FunctionMiddlewareAfterValidator, + type FunctionMiddlewareClientFn, + type FunctionMiddlewareServerFnResult, + type FunctionMiddlewareClient, + type FunctionMiddlewareServerFnOptions, + type FunctionMiddlewareServerNextFn, + type FunctionServerResultWithContext, } from '@tanstack/start-client-core' -export { serverOnly, clientOnly } from '@tanstack/start-client-core' -export { json } from '@tanstack/start-client-core' export { Meta } from './Meta' export { Scripts } from './Scripts' export { StartClient } from './StartClient' diff --git a/packages/react-start-client/src/renderRSC.tsx b/packages/react-start-client/src/renderRSC.tsx index 6201bfa476..4832f074b6 100644 --- a/packages/react-start-client/src/renderRSC.tsx +++ b/packages/react-start-client/src/renderRSC.tsx @@ -1,6 +1,4 @@ // TODO: RSCs -// // @ts-expect-error -// import * as reactDom from '@vinxi/react-server-dom/client' import { isValidElement } from 'react' import invariant from 'tiny-invariant' import type React from 'react' diff --git a/packages/react-start-client/src/useServerFn.ts b/packages/react-start-client/src/useServerFn.ts index c046bcb9ed..971b3a6685 100644 --- a/packages/react-start-client/src/useServerFn.ts +++ b/packages/react-start-client/src/useServerFn.ts @@ -17,12 +17,8 @@ export function useServerFn) => Promise>( return res } catch (err) { if (isRedirect(err)) { - const resolvedRedirect = router.resolveRedirect({ - ...err, - _fromLocation: router.state.location, - }) - - return router.navigate(resolvedRedirect) + err.options._fromLocation = router.state.location + return router.navigate(router.resolveRedirect(err).options) } throw err diff --git a/packages/react-start-config/README.md b/packages/react-start-config/README.md deleted file mode 100644 index bb009b0c87..0000000000 --- a/packages/react-start-config/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/react-start-config/eslint.config.js b/packages/react-start-config/eslint.config.js deleted file mode 100644 index 931f0ec774..0000000000 --- a/packages/react-start-config/eslint.config.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check - -import pluginReact from '@eslint-react/eslint-plugin' -import pluginReactHooks from 'eslint-plugin-react-hooks' -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - ...pluginReact.configs.recommended, - files: ['**/*.{ts,tsx}'], - }, - { - plugins: { - 'react-hooks': pluginReactHooks, - }, - rules: { - '@eslint-react/no-unstable-context-value': 'off', - '@eslint-react/no-unstable-default-props': 'off', - '@eslint-react/dom/no-missing-button-type': 'off', - 'react-hooks/exhaustive-deps': 'error', - 'react-hooks/rules-of-hooks': 'error', - }, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/react-start-config/package.json b/packages/react-start-config/package.json deleted file mode 100644 index 23efef7bfd..0000000000 --- a/packages/react-start-config/package.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "@tanstack/react-start-config", - "version": "1.120.3", - "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/react-start-config" - }, - "homepage": "https://tanstack.com/start", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "keywords": [ - "react", - "location", - "router", - "routing", - "async", - "async router", - "typescript" - ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "build": "tsc", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0;vitest", - "test:eslint": "eslint ./src", - "test:types": "exit 0; vitest" - }, - "type": "module", - "types": "dist/esm/index.d.ts", - "exports": { - ".": { - "import": { - "types": "./dist/esm/index.d.ts", - "default": "./dist/esm/index.js" - } - }, - "./package.json": "./package.json" - }, - "sideEffects": false, - "files": [ - "dist", - "src" - ], - "engines": { - "node": ">=12" - }, - "dependencies": { - "@tanstack/router-core": "workspace:^", - "@tanstack/router-generator": "workspace:^", - "@tanstack/router-plugin": "workspace:^", - "@tanstack/server-functions-plugin": "workspace:^", - "@tanstack/react-start-plugin": "workspace:^", - "@tanstack/start-server-functions-handler": "workspace:^", - "@vitejs/plugin-react": "^4.3.4", - "import-meta-resolve": "^4.1.0", - "nitropack": "^2.10.4", - "ofetch": "^1.4.1", - "vite": "^6.1.0", - "vinxi": "0.5.3", - "zod": "^3.24.2" - }, - "peerDependencies": { - "react": ">=18.0.0 || >=19.0.0", - "react-dom": ">=18.0.0 || >=19.0.0", - "vite": "^6.0.0" - } -} diff --git a/packages/react-start-config/src/index.ts b/packages/react-start-config/src/index.ts deleted file mode 100644 index ac30bf2140..0000000000 --- a/packages/react-start-config/src/index.ts +++ /dev/null @@ -1,663 +0,0 @@ -import path from 'node:path' -import { existsSync, readFileSync } from 'node:fs' -import { readFile } from 'node:fs/promises' -import { fileURLToPath } from 'node:url' -import viteReact from '@vitejs/plugin-react' -import { resolve } from 'import-meta-resolve' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' -import { getConfig } from '@tanstack/router-generator' -import { createApp } from 'vinxi' -import { config } from 'vinxi/plugins/config' -// // @ts-expect-error -// import { serverComponents } from '@vinxi/server-components/plugin' -import { createTanStackServerFnPlugin } from '@tanstack/server-functions-plugin' -import { createTanStackStartPlugin } from '@tanstack/react-start-plugin' -import { createFetch } from 'ofetch' -import { createNitro } from 'nitropack' -import { tanstackStartVinxiFileRouter } from './vinxi-file-router.js' -import { - checkDeploymentPresetInput, - getUserViteConfig, - inlineConfigSchema, - serverSchema, -} from './schema.js' -import type { configSchema } from '@tanstack/router-generator' -import type { z } from 'zod' -import type { - TanStackStartInputConfig, - TanStackStartOutputConfig, -} from './schema.js' -import type { App as VinxiApp } from 'vinxi' -import type { Manifest } from '@tanstack/router-core' -import type * as vite from 'vite' - -export type { - TanStackStartInputConfig, - TanStackStartOutputConfig, -} from './schema.js' - -function setTsrDefaults(config: TanStackStartOutputConfig['tsr']) { - // Normally these are `./src/___`, but we're using `./app/___` for Start stuff - const appDirectory = config?.appDirectory ?? './app' - return { - ...config, - appDirectory: config?.appDirectory ?? appDirectory, - routesDirectory: - config?.routesDirectory ?? path.join(appDirectory, 'routes'), - generatedRouteTree: - config?.generatedRouteTree ?? path.join(appDirectory, 'routeTree.gen.ts'), - } -} - -function mergeSsrOptions(options: Array) { - let ssrOptions: vite.SSROptions = {} - let noExternal: vite.SSROptions['noExternal'] = [] - for (const option of options) { - if (!option) { - continue - } - - if (option.noExternal) { - if (option.noExternal === true) { - noExternal = true - } else if (noExternal !== true) { - if (Array.isArray(option.noExternal)) { - noExternal.push(...option.noExternal) - } else { - noExternal.push(option.noExternal) - } - } - } - - ssrOptions = { - ...ssrOptions, - ...option, - noExternal, - } - } - - return ssrOptions -} - -export async function defineConfig( - inlineConfig: TanStackStartInputConfig = {}, -): Promise { - const opts = inlineConfigSchema.parse(inlineConfig) - - const { preset: configDeploymentPreset, ...serverOptions } = - serverSchema.parse(opts.server || {}) - - const deploymentPreset = checkDeploymentPresetInput(configDeploymentPreset) - const tsr = setTsrDefaults(opts.tsr) - const tsrConfig = getConfig(tsr) - - const appDirectory = tsr.appDirectory - const publicDir = opts.routers?.public?.dir || './public' - - const publicBase = opts.routers?.public?.base || '/' - const clientBase = opts.routers?.client?.base || '/_build' - const apiBase = opts.tsr?.apiBase || '/api' - const serverBase = opts.routers?.server?.base || '/_server' - - const apiMiddleware = opts.routers?.api?.middleware || undefined - const serverMiddleware = opts.routers?.server?.middleware || undefined - const ssrMiddleware = opts.routers?.ssr?.middleware || undefined - - const clientEntry = - opts.routers?.client?.entry || path.join(appDirectory, 'client.tsx') - const ssrEntry = - opts.routers?.ssr?.entry || path.join(appDirectory, 'ssr.tsx') - const apiEntry = opts.routers?.api?.entry || path.join(appDirectory, 'api.ts') - const globalMiddlewareEntry = - opts.routers?.server?.globalMiddlewareEntry || - path.join(appDirectory, 'global-middleware.ts') - const apiEntryExists = existsSync(apiEntry) - - const viteConfig = getUserViteConfig(opts.vite) - - const TanStackServerFnsPlugin = createTanStackServerFnPlugin({ - // This is the ID that will be available to look up and import - // our server function manifest and resolve its module - manifestVirtualImportId: 'tsr:server-fn-manifest', - client: { - getRuntimeCode: () => - `import { createClientRpc } from '@tanstack/react-start/server-functions-client'`, - replacer: (opts) => - `createClientRpc('${opts.functionId}', '${serverBase}')`, - }, - ssr: { - getRuntimeCode: () => - `import { createSsrRpc } from '@tanstack/react-start/server-functions-ssr'`, - replacer: (opts) => `createSsrRpc('${opts.functionId}', '${serverBase}')`, - }, - server: { - getRuntimeCode: () => - `import { createServerRpc } from '@tanstack/react-start/server-functions-server'`, - replacer: (opts) => - `createServerRpc('${opts.functionId}', '${serverBase}', ${opts.fn})`, - }, - }) - - const TanStackStartPlugin = createTanStackStartPlugin({ - globalMiddlewareEntry, - }) - - // Create a dummy nitro app to get the resolved public output path - const dummyNitroApp = await createNitro({ - preset: deploymentPreset, - compatibilityDate: '2024-12-01', - }) - - const nitroOutputPublicDir = dummyNitroApp.options.output.publicDir - await dummyNitroApp.close() - - let vinxiApp = createApp({ - server: { - ...serverOptions, - preset: deploymentPreset, - experimental: { - ...serverOptions.experimental, - asyncContext: true, - }, - }, - routers: [ - { - name: 'public', - type: 'static', - dir: publicDir, - base: publicBase, - }, - { - name: 'client', - type: 'client', - target: 'browser', - handler: clientEntry, - base: clientBase, - // @ts-expect-error - build: { - sourcemap: true, - }, - plugins: () => { - const routerType = 'client' - const clientViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-client', { - ...viteConfig.userConfig, - ...clientViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(clientViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - clientViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(clientViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: true, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.client, - TanStackServerFnsPlugin.client, - ...(viteConfig.plugins || []), - ...(clientViteConfig.plugins || []), - viteReact(opts.react), - // TODO: RSCS - enable this - // serverComponents.client(), - ] - }, - }, - { - name: 'ssr', - type: 'http', - target: 'server', - handler: ssrEntry, - middleware: ssrMiddleware, - // @ts-expect-error - link: { - client: 'client', - }, - plugins: () => { - const routerType = 'ssr' - const ssrViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-ssr', { - ...viteConfig.userConfig, - ...ssrViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(ssrViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - ssrViteConfig.userConfig.ssr, - { - noExternal, - external: ['@vinxi/react-server-dom/client'], - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(ssrViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.ssr, - TanStackServerFnsPlugin.ssr, - tsrRoutesManifest({ - tsrConfig, - clientBase, - }), - ...(getUserViteConfig(opts.vite).plugins || []), - ...(getUserViteConfig(opts.routers?.ssr?.vite).plugins || []), - viteReact(opts.react), - ] - }, - }, - { - name: 'server', - type: 'http', - target: 'server', - base: serverBase, - middleware: serverMiddleware, - // TODO: RSCS - enable this - // worker: true, - handler: importToProjectRelative( - '@tanstack/start-server-functions-handler', - ), - plugins: () => { - const routerType = 'server' - const serverViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-server', { - ...viteConfig.userConfig, - ...serverViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(serverViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv('TSS_SERVER_FN_BASE', serverBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - serverViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(serverViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.server, - TanStackServerFnsPlugin.server, - // TODO: RSCS - remove this - // resolve: { - // conditions: [], - // }, - // TODO: RSCs - add this - // serverComponents.serverActions({ - // resolve: { - // conditions: [ - // 'react-server', - // // 'node', - // 'import', - // process.env.NODE_ENV, - // ], - // }, - // runtime: '@vinxi/react-server-dom/runtime', - // transpileDeps: ['react', 'react-dom', '@vinxi/react-server-dom'], - // }), - ...(viteConfig.plugins || []), - ...(serverViteConfig.plugins || []), - ] - }, - }, - ], - }) - - const noExternal = [ - '@tanstack/start', - '@tanstack/react-start', - '@tanstack/react-start/server', - '@tanstack/react-start-client', - '@tanstack/react-start-server', - '@tanstack/start-server-functions-fetcher', - '@tanstack/start-server-functions-handler', - '@tanstack/start-server-functions-client', - '@tanstack/start-server-functions-ssr', - '@tanstack/start-server-functions-server', - '@tanstack/react-start-router-manifest', - '@tanstack/react-start-config', - '@tanstack/start-api-routes', - '@tanstack/server-functions-plugin', - 'tsr:routes-manifest', - 'tsr:server-fn-manifest', - ] - - // If API routes handler exists, add a router for it - if (apiEntryExists) { - vinxiApp = vinxiApp.addRouter({ - name: 'api', - type: 'http', - target: 'server', - base: apiBase, - handler: apiEntry, - middleware: apiMiddleware, - routes: tanstackStartVinxiFileRouter({ tsrConfig, apiBase }), - plugins: () => { - const viteConfig = getUserViteConfig(opts.vite) - const apiViteConfig = getUserViteConfig(opts.routers?.api?.vite) - - return [ - config('tsr-vite-config-api', { - ...viteConfig.userConfig, - ...apiViteConfig.userConfig, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - apiViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(apiViteConfig.userConfig.optimizeDeps || {}), - }, - define: { - ...(viteConfig.userConfig.define || {}), - ...(apiViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv('TSS_OUTPUT_PUBLIC_DIR', nitroOutputPublicDir), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - ...(viteConfig.plugins || []), - ...(apiViteConfig.plugins || []), - ] - }, - }) - } - - // Because Vinxi doesn't use the normal nitro dev server, it doesn't - // supply $fetch during dev. We need to hook into the dev server creation, - // nab the proper utils from the custom nitro instance that is used - // during dev and supply the $fetch to app. - // Hopefully and likely, this will just get removed when we move to - // Nitro directly. - vinxiApp.hooks.hook('app:dev:nitro:config', (devServer) => { - vinxiApp.hooks.hook( - 'app:dev:server:created', - ({ devApp: { localFetch } }) => { - const $fetch = createFetch({ - fetch: localFetch, - defaults: { - baseURL: devServer.nitro.options.runtimeConfig.app.baseURL, - }, - }) - - // @ts-expect-error - globalThis.$fetch = $fetch - }, - ) - }) - - return vinxiApp -} - -function importToProjectRelative(p: string) { - const resolved = fileURLToPath(resolve(p, import.meta.url)) - - const relative = path.relative(process.cwd(), resolved) - - return relative -} - -function tsrRoutesManifest(opts: { - tsrConfig: z.infer - clientBase: string -}): vite.Plugin { - let config: vite.ResolvedConfig - - return { - name: 'tsr-routes-manifest', - configResolved(resolvedConfig) { - config = resolvedConfig - }, - resolveId(id) { - if (id === 'tsr:routes-manifest') { - return id - } - return - }, - async load(id) { - if (id === 'tsr:routes-manifest') { - // If we're in development, return a dummy manifest - - if (config.command === 'serve') { - return `export default () => ({ - routes: {} - })` - } - - const clientViteManifestPath = path.resolve( - config.build.outDir, - `../client/${opts.clientBase}/.vite/manifest.json`, - ) - - type ViteManifest = Record< - string, - { - file: string - isEntry: boolean - imports: Array - } - > - - let manifest: ViteManifest - try { - manifest = JSON.parse(await readFile(clientViteManifestPath, 'utf-8')) - } catch (err) { - console.error(err) - throw new Error( - `Could not find the production client vite manifest at '${clientViteManifestPath}'!`, - ) - } - - const routeTreePath = path.resolve(opts.tsrConfig.generatedRouteTree) - - let routeTreeContent: string - try { - routeTreeContent = readFileSync(routeTreePath, 'utf-8') - } catch (err) { - console.error(err) - throw new Error( - `Could not find the generated route tree at '${routeTreePath}'!`, - ) - } - - // Extract the routesManifest JSON from the route tree file. - // It's located between the /* ROUTE_MANIFEST_START and ROUTE_MANIFEST_END */ comment block. - - const routerManifest = JSON.parse( - routeTreeContent.match( - /\/\* ROUTE_MANIFEST_START([\s\S]*?)ROUTE_MANIFEST_END \*\//, - )?.[1] || '{ routes: {} }', - ) as Manifest - - const routes = routerManifest.routes - - let entryFile: - | { - file: string - imports: Array - } - | undefined - - const filesByRouteFilePath: ViteManifest = Object.fromEntries( - Object.entries(manifest).map(([k, v]) => { - if (v.isEntry) { - entryFile = v - } - - const rPath = k.split('?')[0] - - return [rPath, v] - }, {}), - ) - - // Add preloads to the routes from the vite manifest - Object.entries(routes).forEach(([k, v]) => { - const file = - filesByRouteFilePath[ - path.join(opts.tsrConfig.routesDirectory, v.filePath as string) - ] - - if (file) { - const preloads = file.imports.map((d) => - path.join(opts.clientBase, manifest[d]!.file), - ) - - preloads.unshift(path.join(opts.clientBase, file.file)) - - routes[k] = { - ...v, - preloads, - } - } - }) - - if (entryFile) { - routes.__root__!.preloads = [ - path.join(opts.clientBase, entryFile.file), - ...entryFile.imports.map((d) => - path.join(opts.clientBase, manifest[d]!.file), - ), - ] - } - - const recurseRoute = ( - route: { - preloads?: Array - children?: Array - }, - seenPreloads = {} as Record, - ) => { - route.preloads = route.preloads?.filter((preload) => { - if (seenPreloads[preload]) { - return false - } - seenPreloads[preload] = true - return true - }) - - if (route.children) { - route.children.forEach((child) => { - const childRoute = routes[child]! - recurseRoute(childRoute, { ...seenPreloads }) - }) - } - } - - // @ts-expect-error - recurseRoute(routes.__root__) - - const routesManifest = { - routes, - } - - if (process.env.TSR_VITE_DEBUG) { - console.info( - 'Routes Manifest: \n' + JSON.stringify(routesManifest, null, 2), - ) - } - - return `export default () => (${JSON.stringify(routesManifest)})` - } - return - }, - } -} - -function injectDefineEnv( - key: TKey, - value: TValue, -): { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } { - return { - [`process.env.${key}`]: JSON.stringify(value), - [`import.meta.env.${key}`]: JSON.stringify(value), - } as { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } -} diff --git a/packages/react-start-config/src/schema.ts b/packages/react-start-config/src/schema.ts deleted file mode 100644 index 4529483793..0000000000 --- a/packages/react-start-config/src/schema.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { configSchema } from '@tanstack/router-generator' -import { z } from 'zod' -import type { PluginOption } from 'vite' -import type { AppOptions as VinxiAppOptions } from 'vinxi' -import type { NitroOptions } from 'nitropack' -import type { Options as ViteReactOptions } from '@vitejs/plugin-react' -import type { CustomizableConfig } from 'vinxi/dist/types/lib/vite-dev' - -type StartUserViteConfig = CustomizableConfig | (() => CustomizableConfig) - -export function getUserViteConfig(config?: StartUserViteConfig): { - plugins: Array | undefined - userConfig: CustomizableConfig -} { - const { plugins, ...userConfig } = - typeof config === 'function' ? config() : { ...config } - return { plugins, userConfig } -} - -/** - * Not all the deployment presets are fully functional or tested. - * @see https://github.com/TanStack/router/pull/2002 - */ -const vinxiDeploymentPresets = [ - 'alwaysdata', // untested - 'aws-amplify', // untested - 'aws-lambda', // untested - 'azure', // untested - 'azure-functions', // untested - 'base-worker', // untested - 'bun', // ✅ working - 'cleavr', // untested - 'cli', // untested - 'cloudflare', // untested - 'cloudflare-module', // untested - 'cloudflare-pages', // ✅ working - 'cloudflare-pages-static', // untested - 'deno', // untested - 'deno-deploy', // untested - 'deno-server', // untested - 'digital-ocean', // untested - 'edgio', // untested - 'firebase', // untested - 'flight-control', // untested - 'github-pages', // untested - 'heroku', // untested - 'iis', // untested - 'iis-handler', // untested - 'iis-node', // untested - 'koyeb', // untested - 'layer0', // untested - 'netlify', // ✅ working - 'netlify-builder', // untested - 'netlify-edge', // untested - 'netlify-static', // untested - 'nitro-dev', // untested - 'nitro-prerender', // untested - 'node', // partially working - 'node-cluster', // untested - 'node-server', // ✅ working - 'platform-sh', // untested - 'service-worker', // untested - 'static', // 🟧 partially working - 'stormkit', // untested - 'vercel', // ✅ working - 'vercel-edge', // untested - 'vercel-static', // untested - 'winterjs', // untested - 'zeabur', // untested - 'zeabur-static', // untested -] as const - -type DeploymentPreset = (typeof vinxiDeploymentPresets)[number] | (string & {}) - -const testedDeploymentPresets: Array = [ - 'bun', - 'netlify', - 'vercel', - 'cloudflare-pages', - 'node-server', -] - -export function checkDeploymentPresetInput( - preset?: string, -): DeploymentPreset | undefined { - if (preset) { - if (!vinxiDeploymentPresets.includes(preset as any)) { - console.warn( - `Invalid deployment preset "${preset}". Available presets are: ${vinxiDeploymentPresets - .map((p) => `"${p}"`) - .join(', ')}.`, - ) - } - - if (!testedDeploymentPresets.includes(preset as any)) { - console.warn( - `The deployment preset '${preset}' is not fully supported yet and may not work as expected.`, - ) - } - } - - return preset -} - -type HTTPSOptions = { - cert?: string - key?: string - pfx?: string - passphrase?: string - validityDays?: number - domains?: Array -} - -type ServerOptions_ = VinxiAppOptions['server'] & { - https?: boolean | HTTPSOptions -} - -type ServerOptions = { - [K in keyof ServerOptions_]: ServerOptions_[K] -} - -export const serverSchema = z - .object({ - routeRules: z.custom().optional(), - preset: z.custom().optional(), - static: z.boolean().optional(), - prerender: z - .object({ - routes: z.array(z.string()), - ignore: z - .array( - z.custom< - string | RegExp | ((path: string) => undefined | null | boolean) - >(), - ) - .optional(), - crawlLinks: z.boolean().optional(), - }) - .optional(), - }) - .and(z.custom()) - -const viteSchema = z.custom() - -const viteReactSchema = z.custom() - -const routersSchema = z.object({ - ssr: z - .object({ - entry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - client: z - .object({ - entry: z.string().optional(), - base: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - server: z - .object({ - base: z.string().optional(), - globalMiddlewareEntry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - api: z - .object({ - entry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - public: z - .object({ - dir: z.string().optional(), - base: z.string().optional(), - }) - .optional(), -}) - -const tsrConfig = configSchema.partial().extend({ - appDirectory: z.string().optional(), -}) - -export const inlineConfigSchema = z.object({ - react: viteReactSchema.optional(), - vite: viteSchema.optional(), - tsr: tsrConfig.optional(), - routers: routersSchema.optional(), - server: serverSchema.optional(), -}) - -export type TanStackStartInputConfig = z.input -export type TanStackStartOutputConfig = z.infer diff --git a/packages/react-start-config/src/vinxi-file-router.ts b/packages/react-start-config/src/vinxi-file-router.ts deleted file mode 100644 index 9e6d829d1b..0000000000 --- a/packages/react-start-config/src/vinxi-file-router.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { - BaseFileSystemRouter as VinxiBaseFileSystemRouter, - analyzeModule as vinxiFsRouterAnalyzeModule, - cleanPath as vinxiFsRouterCleanPath, -} from 'vinxi/fs-router' -import { - CONSTANTS as GENERATOR_CONSTANTS, - startAPIRouteSegmentsFromTSRFilePath, -} from '@tanstack/router-generator' -import type { configSchema } from '@tanstack/router-generator' -import type { - AppOptions as VinxiAppOptions, - RouterSchemaInput as VinxiRouterSchemaInput, -} from 'vinxi' -import type { z } from 'zod' - -export function tanstackStartVinxiFileRouter(opts: { - tsrConfig: z.infer - apiBase: string -}) { - const apiBaseSegment = opts.apiBase.split('/').filter(Boolean).join('/') - const isAPIPath = new RegExp(`/${apiBaseSegment}/`) - - return function (router: VinxiRouterSchemaInput, app: VinxiAppOptions) { - // Our own custom File Router that extends the VinxiBaseFileSystemRouter - // for splitting the API routes into its own "bundle" - // and adding the $APIRoute metadata to the route object - // This could be customized in future to support more complex splits - class TanStackStartFsRouter extends VinxiBaseFileSystemRouter { - toPath(src: string): string { - const inputPath = vinxiFsRouterCleanPath(src, this.config) - - const segments = startAPIRouteSegmentsFromTSRFilePath( - inputPath, - opts.tsrConfig, - ) - - const pathname = segments - .map((part) => { - if (part.type === 'splat') { - return `*splat` - } - - if (part.type === 'param') { - return `:${part.value}?` - } - - return part.value - }) - .join('/') - - return pathname.length > 0 ? `/${pathname}` : '/' - } - - toRoute(src: string) { - const webPath = this.toPath(src) - - const [_, exports] = vinxiFsRouterAnalyzeModule(src) - - const hasAPIRoute = exports.find( - (exp) => exp.n === GENERATOR_CONSTANTS.APIRouteExportVariable, - ) - - return { - path: webPath, - filePath: src, - $APIRoute: - isAPIPath.test(webPath) && hasAPIRoute - ? { - src, - pick: [GENERATOR_CONSTANTS.APIRouteExportVariable], - } - : undefined, - } - } - } - - return new TanStackStartFsRouter( - { - dir: opts.tsrConfig.routesDirectory, - extensions: ['js', 'jsx', 'ts', 'tsx'], - }, - router, - app, - ) - } -} diff --git a/packages/react-start-config/tsconfig.json b/packages/react-start-config/tsconfig.json deleted file mode 100644 index 940a9cce0a..0000000000 --- a/packages/react-start-config/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": ["src/index.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist/esm", - "target": "esnext", - "noEmit": false - } -} diff --git a/packages/react-start-plugin/README.md b/packages/react-start-plugin/README.md index 90488bbcd8..45e57a4d5b 100644 --- a/packages/react-start-plugin/README.md +++ b/packages/react-start-plugin/README.md @@ -1,5 +1,9 @@ -# TanStack Start Vite Plugin +# TanStack React Start - Plugin -See https://tanstack.com/router/latest/docs/framework/react/routing/file-based-routing +This package is not meant to be used directly. It is a dependency of [`@tanstack/react-start`](https://www.npmjs.com/package/@tanstack/react-start). + +TanStack React Start is a fullstack-framework made for SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router). + +Head over to [tanstack.com/start](https://tanstack.com/start) for more information about getting started. diff --git a/packages/react-start-plugin/package.json b/packages/react-start-plugin/package.json index f13d4951cc..d67c053e03 100644 --- a/packages/react-start-plugin/package.json +++ b/packages/react-start-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-start-plugin", - "version": "1.115.0", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -27,7 +27,7 @@ "clean": "rimraf ./dist && rimraf ./coverage", "clean:snapshots": "rimraf **/*snapshot* --glob", "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "vitest", + "test:unit": "exit 0; vitest", "test:eslint": "eslint ./src", "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", @@ -65,22 +65,16 @@ "node": ">=12" }, "dependencies": { - "@babel/code-frame": "7.26.2", - "@babel/core": "^7.26.8", - "@babel/plugin-syntax-jsx": "^7.25.9", - "@babel/plugin-syntax-typescript": "^7.25.9", - "@babel/template": "^7.26.8", - "@babel/traverse": "^7.26.8", - "@babel/types": "^7.26.8", "@tanstack/router-utils": "workspace:^", - "babel-dead-code-elimination": "^1.0.10", - "tiny-invariant": "^1.3.3", - "vite": "6.1.4" + "@tanstack/start-plugin-core": "workspace:^", + "zod": "^3.24.2" }, "devDependencies": { - "@types/babel__code-frame": "^7.0.6", - "@types/babel__core": "^7.20.5", - "@types/babel__template": "^7.4.4", - "@types/babel__traverse": "^7.20.6" + "@vitejs/plugin-react": "^4.3.4", + "vite": "^6.0.0" + }, + "peerDependencies": { + "@vitejs/plugin-react": ">=4.3.4", + "vite": ">=6.0.0" } } diff --git a/packages/react-start-plugin/src/compilers.ts b/packages/react-start-plugin/src/compilers.ts deleted file mode 100644 index ca806fc991..0000000000 --- a/packages/react-start-plugin/src/compilers.ts +++ /dev/null @@ -1,584 +0,0 @@ -import * as babel from '@babel/core' -import * as t from '@babel/types' -import { codeFrameColumns } from '@babel/code-frame' -import { - deadCodeElimination, - findReferencedIdentifiers, -} from 'babel-dead-code-elimination' -import { generateFromAst, parseAst } from '@tanstack/router-utils' -import type { GeneratorResult, ParseAstOptions } from '@tanstack/router-utils' - -// build these once and reuse them -const handleServerOnlyCallExpression = - buildEnvOnlyCallExpressionHandler('server') -const handleClientOnlyCallExpression = - buildEnvOnlyCallExpressionHandler('client') - -type CompileOptions = ParseAstOptions & { - env: 'server' | 'client' | 'ssr' - dce?: boolean -} - -type IdentifierConfig = { - name: string - type: 'ImportSpecifier' | 'ImportNamespaceSpecifier' - namespaceId: string - handleCallExpression: ( - path: babel.NodePath, - opts: CompileOptions, - ) => void - paths: Array -} - -export function compileStartOutput(opts: CompileOptions): GeneratorResult { - const ast = parseAst(opts) - - const doDce = opts.dce ?? true - // find referenced identifiers *before* we transform anything - const refIdents = doDce ? findReferencedIdentifiers(ast) : undefined - - babel.traverse(ast, { - Program: { - enter(programPath) { - const identifiers: { - createServerFn: IdentifierConfig - createMiddleware: IdentifierConfig - serverOnly: IdentifierConfig - clientOnly: IdentifierConfig - createIsomorphicFn: IdentifierConfig - } = { - createServerFn: { - name: 'createServerFn', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleCreateServerFnCallExpression, - paths: [], - }, - createMiddleware: { - name: 'createMiddleware', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleCreateMiddlewareCallExpression, - paths: [], - }, - serverOnly: { - name: 'serverOnly', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleServerOnlyCallExpression, - paths: [], - }, - clientOnly: { - name: 'clientOnly', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleClientOnlyCallExpression, - paths: [], - }, - createIsomorphicFn: { - name: 'createIsomorphicFn', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleCreateIsomorphicFnCallExpression, - paths: [], - }, - } - - const identifierKeys = Object.keys(identifiers) as Array< - keyof typeof identifiers - > - - programPath.traverse({ - ImportDeclaration: (path) => { - if (path.node.source.value !== '@tanstack/react-start') { - return - } - - // handle a destructured imports being renamed like "import { createServerFn as myCreateServerFn } from '@tanstack/react-start';" - path.node.specifiers.forEach((specifier) => { - identifierKeys.forEach((identifierKey) => { - const identifier = identifiers[identifierKey] - - if ( - specifier.type === 'ImportSpecifier' && - specifier.imported.type === 'Identifier' - ) { - if (specifier.imported.name === identifierKey) { - identifier.name = specifier.local.name - identifier.type = 'ImportSpecifier' - } - } - - // handle namespace imports like "import * as TanStackStart from '@tanstack/react-start';" - if (specifier.type === 'ImportNamespaceSpecifier') { - identifier.type = 'ImportNamespaceSpecifier' - identifier.namespaceId = specifier.local.name - identifier.name = `${identifier.namespaceId}.${identifierKey}` - } - }) - }) - }, - CallExpression: (path) => { - identifierKeys.forEach((identifierKey) => { - // Check to see if the call expression is a call to the - // identifiers[identifierKey].name - if ( - t.isIdentifier(path.node.callee) && - path.node.callee.name === identifiers[identifierKey].name - ) { - // The identifier could be a call to the original function - // in the source code. If this is case, we need to ignore it. - // Check the scope to see if the identifier is a function declaration. - // if it is, then we can ignore it. - - if ( - path.scope.getBinding(identifiers[identifierKey].name)?.path - .node.type === 'FunctionDeclaration' - ) { - return - } - - return identifiers[identifierKey].paths.push(path) - } - - if (t.isMemberExpression(path.node.callee)) { - if ( - t.isIdentifier(path.node.callee.object) && - t.isIdentifier(path.node.callee.property) - ) { - const callname = [ - path.node.callee.object.name, - path.node.callee.property.name, - ].join('.') - - if (callname === identifiers[identifierKey].name) { - identifiers[identifierKey].paths.push(path) - } - } - } - - return - }) - }, - }) - - identifierKeys.forEach((identifierKey) => { - identifiers[identifierKey].paths.forEach((path) => { - identifiers[identifierKey].handleCallExpression( - path as babel.NodePath, - opts, - ) - }) - }) - }, - }, - }) - - if (doDce) { - deadCodeElimination(ast, refIdents) - } - - return generateFromAst(ast, { - sourceMaps: true, - sourceFileName: opts.filename, - filename: opts.filename, - }) -} - -function handleCreateServerFnCallExpression( - path: babel.NodePath, - opts: ParseAstOptions, -) { - // The function is the 'fn' property of the object passed to createServerFn - - // const firstArg = path.node.arguments[0] - // if (t.isObjectExpression(firstArg)) { - // // Was called with some options - // } - - // Traverse the member expression and find the call expressions for - // the validator, handler, and middleware methods. Check to make sure they - // are children of the createServerFn call expression. - - const calledOptions = path.node.arguments[0] - ? (path.get('arguments.0') as babel.NodePath) - : null - - const shouldValidateClient = !!calledOptions?.node.properties.find((prop) => { - return ( - t.isObjectProperty(prop) && - t.isIdentifier(prop.key) && - prop.key.name === 'validateClient' && - t.isBooleanLiteral(prop.value) && - prop.value.value === true - ) - }) - - const callExpressionPaths = { - middleware: null as babel.NodePath | null, - validator: null as babel.NodePath | null, - handler: null as babel.NodePath | null, - } - - const validMethods = Object.keys(callExpressionPaths) - - const rootCallExpression = getRootCallExpression(path) - - // if (debug) - // console.info( - // 'Handling createServerFn call expression:', - // rootCallExpression.toString(), - // ) - - // Check if the call is assigned to a variable - if (!rootCallExpression.parentPath.isVariableDeclarator()) { - throw new Error('createServerFn must be assigned to a variable!') - } - - // Get the identifier name of the variable - const variableDeclarator = rootCallExpression.parentPath.node - const existingVariableName = (variableDeclarator.id as t.Identifier).name - - rootCallExpression.traverse({ - MemberExpression(memberExpressionPath) { - if (t.isIdentifier(memberExpressionPath.node.property)) { - const name = memberExpressionPath.node.property - .name as keyof typeof callExpressionPaths - - if ( - validMethods.includes(name) && - memberExpressionPath.parentPath.isCallExpression() - ) { - callExpressionPaths[name] = memberExpressionPath.parentPath - } - } - }, - }) - - if (callExpressionPaths.validator) { - const innerInputExpression = callExpressionPaths.validator.node.arguments[0] - - if (!innerInputExpression) { - throw new Error( - 'createServerFn().validator() must be called with a validator!', - ) - } - - // If we're on the client, and we're not validating the client, remove the validator call expression - if ( - opts.env === 'client' && - !shouldValidateClient && - t.isMemberExpression(callExpressionPaths.validator.node.callee) - ) { - callExpressionPaths.validator.replaceWith( - callExpressionPaths.validator.node.callee.object, - ) - } - } - - // First, we need to move the handler function to a nested function call - // that is applied to the arguments passed to the server function. - - const handlerFnPath = callExpressionPaths.handler?.get( - 'arguments.0', - ) as babel.NodePath - - if (!callExpressionPaths.handler || !handlerFnPath.node) { - throw codeFrameError( - opts.code, - path.node.callee.loc!, - `createServerFn must be called with a "handler" property!`, - ) - } - - const handlerFn = handlerFnPath.node - - // So, the way we do this is we give the handler function a way - // to access the serverFn ctx on the server via function scope. - // The 'use server' extracted function will be called with the - // payload from the client, then use the scoped serverFn ctx - // to execute the handler function. - // This way, we can do things like data and middleware validation - // in the __execute function without having to AST transform the - // handler function too much itself. - - // .handler((optsOut, ctx) => { - // return ((optsIn) => { - // 'use server' - // ctx.__execute(handlerFn, optsIn) - // })(optsOut) - // }) - - // If the handler function is an identifier and we're on the client, we need to - // remove the bound function from the file. - // If we're on the server, you can leave it, since it will get referenced - // as a second argument. - - if (t.isIdentifier(handlerFn)) { - if (opts.env === 'client' || opts.env === 'ssr') { - // Find the binding for the handler function - const binding = handlerFnPath.scope.getBinding(handlerFn.name) - // Remove it - if (binding) { - binding.path.remove() - } - } - // If the env is server, just leave it alone - } - - handlerFnPath.replaceWith( - t.arrowFunctionExpression( - [t.identifier('opts'), t.identifier('signal')], - t.blockStatement( - // Everything in here is server-only, since the client - // will strip out anything in the 'use server' directive. - [ - t.returnStatement( - t.callExpression( - t.identifier(`${existingVariableName}.__executeServer`), - [t.identifier('opts'), t.identifier('signal')], - ), - ), - ], - [t.directive(t.directiveLiteral('use server'))], - ), - ), - ) - - if (opts.env === 'server') { - callExpressionPaths.handler.node.arguments.push(handlerFn) - } -} - -function handleCreateMiddlewareCallExpression( - path: babel.NodePath, - opts: ParseAstOptions, -) { - const rootCallExpression = getRootCallExpression(path) - - // if (debug) - // console.info( - // 'Handling createMiddleware call expression:', - // rootCallExpression.toString(), - // ) - - const callExpressionPaths = { - middleware: null as babel.NodePath | null, - validator: null as babel.NodePath | null, - client: null as babel.NodePath | null, - server: null as babel.NodePath | null, - } - - const validMethods = Object.keys(callExpressionPaths) - - rootCallExpression.traverse({ - MemberExpression(memberExpressionPath) { - if (t.isIdentifier(memberExpressionPath.node.property)) { - const name = memberExpressionPath.node.property - .name as keyof typeof callExpressionPaths - - if ( - validMethods.includes(name) && - memberExpressionPath.parentPath.isCallExpression() - ) { - callExpressionPaths[name] = memberExpressionPath.parentPath - } - } - }, - }) - - if (callExpressionPaths.validator) { - const innerInputExpression = callExpressionPaths.validator.node.arguments[0] - - if (!innerInputExpression) { - throw new Error( - 'createMiddleware().validator() must be called with a validator!', - ) - } - - // If we're on the client or ssr, remove the validator call expression - if (opts.env === 'client' || opts.env === 'ssr') { - if (t.isMemberExpression(callExpressionPaths.validator.node.callee)) { - callExpressionPaths.validator.replaceWith( - callExpressionPaths.validator.node.callee.object, - ) - } - } - } - - const serverFnPath = callExpressionPaths.server?.get( - 'arguments.0', - ) as babel.NodePath - - if ( - callExpressionPaths.server && - serverFnPath.node && - (opts.env === 'client' || opts.env === 'ssr') - ) { - // If we're on the client, remove the server call expression - if (t.isMemberExpression(callExpressionPaths.server.node.callee)) { - callExpressionPaths.server.replaceWith( - callExpressionPaths.server.node.callee.object, - ) - } - } -} - -function buildEnvOnlyCallExpressionHandler(env: 'client' | 'server') { - return function envOnlyCallExpressionHandler( - path: babel.NodePath, - opts: ParseAstOptions, - ) { - // if (debug) - // console.info(`Handling ${env}Only call expression:`, path.toString()) - - const isEnvMatch = - env === 'client' - ? opts.env === 'client' - : opts.env === 'server' || opts.env === 'ssr' - - if (isEnvMatch) { - // extract the inner function from the call expression - const innerInputExpression = path.node.arguments[0] - - if (!t.isExpression(innerInputExpression)) { - throw new Error( - `${env}Only() functions must be called with a function!`, - ) - } - - path.replaceWith(innerInputExpression) - return - } - - // If we're on the wrong environment, replace the call expression - // with a function that always throws an error. - path.replaceWith( - t.arrowFunctionExpression( - [], - t.blockStatement([ - t.throwStatement( - t.newExpression(t.identifier('Error'), [ - t.stringLiteral( - `${env}Only() functions can only be called on the ${env}!`, - ), - ]), - ), - ]), - ), - ) - } -} - -function handleCreateIsomorphicFnCallExpression( - path: babel.NodePath, - opts: CompileOptions, -) { - const rootCallExpression = getRootCallExpression(path) - - // if (debug) - // console.info( - // 'Handling createIsomorphicFn call expression:', - // rootCallExpression.toString(), - // ) - - const callExpressionPaths = { - client: null as babel.NodePath | null, - server: null as babel.NodePath | null, - } - - const validMethods = Object.keys(callExpressionPaths) - - rootCallExpression.traverse({ - MemberExpression(memberExpressionPath) { - if (t.isIdentifier(memberExpressionPath.node.property)) { - const name = memberExpressionPath.node.property - .name as keyof typeof callExpressionPaths - - if ( - validMethods.includes(name) && - memberExpressionPath.parentPath.isCallExpression() - ) { - callExpressionPaths[name] = memberExpressionPath.parentPath - } - } - }, - }) - - if ( - validMethods.every( - (method) => - !callExpressionPaths[method as keyof typeof callExpressionPaths], - ) - ) { - const variableId = rootCallExpression.parentPath.isVariableDeclarator() - ? rootCallExpression.parentPath.node.id - : null - console.warn( - 'createIsomorphicFn called without a client or server implementation!', - 'This will result in a no-op function.', - 'Variable name:', - t.isIdentifier(variableId) ? variableId.name : 'unknown', - ) - } - - const resolvedEnv = opts.env === 'ssr' ? 'server' : opts.env - - const envCallExpression = callExpressionPaths[resolvedEnv] - - if (!envCallExpression) { - // if we don't have an implementation for this environment, default to a no-op - rootCallExpression.replaceWith( - t.arrowFunctionExpression([], t.blockStatement([])), - ) - return - } - - const innerInputExpression = envCallExpression.node.arguments[0] - - if (!t.isExpression(innerInputExpression)) { - throw new Error( - `createIsomorphicFn().${resolvedEnv}(func) must be called with a function!`, - ) - } - - rootCallExpression.replaceWith(innerInputExpression) -} - -function getRootCallExpression(path: babel.NodePath) { - // Find the highest callExpression parent - let rootCallExpression: babel.NodePath = path - - // Traverse up the chain of CallExpressions - while (rootCallExpression.parentPath.isMemberExpression()) { - const parent = rootCallExpression.parentPath - if (parent.parentPath.isCallExpression()) { - rootCallExpression = parent.parentPath - } - } - - return rootCallExpression -} - -function codeFrameError( - code: string, - loc: { - start: { line: number; column: number } - end: { line: number; column: number } - }, - message: string, -) { - const frame = codeFrameColumns( - code, - { - start: loc.start, - end: loc.end, - }, - { - highlightCode: true, - message, - }, - ) - - return new Error(frame) -} diff --git a/packages/react-start-plugin/src/index.ts b/packages/react-start-plugin/src/index.ts index 6ab529afca..83c3857ac3 100644 --- a/packages/react-start-plugin/src/index.ts +++ b/packages/react-start-plugin/src/index.ts @@ -1,143 +1,110 @@ -import { fileURLToPath, pathToFileURL } from 'node:url' import path from 'node:path' -import { existsSync } from 'node:fs' -import { logDiff } from '@tanstack/router-utils' -import { compileStartOutput } from './compilers' -import type { Plugin } from 'vite' - -const debug = - process.env.TSR_VITE_DEBUG && - ['true', 'react-start-plugin'].includes(process.env.TSR_VITE_DEBUG) - -export type TanStackStartViteOptions = { - globalMiddlewareEntry: string -} - -const transformFuncs = [ - 'createServerFn', - 'createMiddleware', - 'serverOnly', - 'clientOnly', - 'createIsomorphicFn', -] -const tokenRegex = new RegExp(transformFuncs.join('|')) -// const eitherFuncRegex = new RegExp( -// `(function ${transformFuncs.join('|function ')})`, -// ) - -export function createTanStackStartPlugin(opts: TanStackStartViteOptions): { - client: Array - ssr: Array - server: Array -} { - const globalMiddlewarePlugin = (): Plugin => { - let entry: string | null = null - let resolvedGlobalMiddlewareEntry: string | null = null - let globalMiddlewareEntryExists = false - let ROOT: string = process.cwd() - return { - name: 'vite-plugin-tanstack-start-ensure-global-middleware', - enforce: 'pre', +import viteReact from '@vitejs/plugin-react' +import { TanStackStartVitePluginCore } from '@tanstack/start-plugin-core' +import * as vite from 'vite' +import { getTanStackStartOptions } from './schema' +import type { TanStackStartInputConfig, WithReactPlugin } from './schema' +import type { PluginOption, ResolvedConfig } from 'vite' + +export type { + TanStackStartInputConfig, + TanStackStartOutputConfig, + WithReactPlugin, +} from './schema' + +export function TanStackStartVitePlugin( + opts?: TanStackStartInputConfig & WithReactPlugin, +): Array { + type OptionsWithReact = ReturnType & + WithReactPlugin + const options: OptionsWithReact = getTanStackStartOptions(opts) + + let resolvedConfig: ResolvedConfig + + return [ + TanStackStartVitePluginCore({ framework: 'react' }, options), + { + name: 'tanstack-react-start:resolve-entries', configResolved: (config) => { - ROOT = config.root - entry = path.resolve(ROOT, (config as any).router.handler) - resolvedGlobalMiddlewareEntry = path.resolve( - ROOT, - opts.globalMiddlewareEntry, - ) - globalMiddlewareEntryExists = existsSync(resolvedGlobalMiddlewareEntry) - - if (!entry) { - throw new Error( - '@tanstack/react-start-plugin: No server entry found!', - ) - } + resolvedConfig = config }, - transform(code, id) { - if (entry && id.includes(entry)) { - if (globalMiddlewareEntryExists) { - return { - code: `${code}\n\nimport '${path.resolve(ROOT, opts.globalMiddlewareEntry)}'`, - map: null, - } - } + resolveId(id) { + if ( + [ + '/~start/server-entry', + '/~start/default-server-entry', + '/~start/default-client-entry', + ].includes(id) + ) { + return `${id}.tsx` } + if (id === '/~start/server-entry.tsx') { + return id + } + return null }, - } - } + load(id) { + const routerImportPath = JSON.stringify( + path.resolve(options.root, options.tsr.srcDirectory, 'router'), + ) - return { - client: [ - globalMiddlewarePlugin(), - TanStackStartServerFnsAndMiddleware({ ...opts, env: 'client' }), - ], - ssr: [ - globalMiddlewarePlugin(), - TanStackStartServerFnsAndMiddleware({ ...opts, env: 'ssr' }), - ], - server: [ - globalMiddlewarePlugin(), - TanStackStartServerFnsAndMiddleware({ ...opts, env: 'server' }), - ], - } -} + if (id === '/~start/server-entry.tsx') { + const ssrEntryPath = options.serverEntryPath.startsWith( + '/~start/default-server-entry', + ) + ? options.serverEntryPath + : vite.normalizePath( + path.resolve(resolvedConfig.root, options.serverEntryPath), + ) + + return ` +import { toWebRequest, defineEventHandler } from '@tanstack/react-start/server'; +import serverEntry from '${ssrEntryPath}'; + +export default defineEventHandler(function(event) { + const request = toWebRequest(event); + return serverEntry({ request }); +}) +` + } -export function TanStackStartServerFnsAndMiddleware(opts: { - env: 'server' | 'ssr' | 'client' -}): Plugin { - let ROOT: string = process.cwd() + if (id === '/~start/default-client-entry.tsx') { + return ` +import { StrictMode, startTransition } from 'react' +import { hydrateRoot } from 'react-dom/client' +import { StartClient } from '@tanstack/react-start' +import { createRouter } from ${routerImportPath} + +const router = createRouter() + +startTransition(() => { + hydrateRoot( + document, + + + + ) +}) +` + } - return { - name: 'vite-plugin-tanstack-start-create-server-fn', - enforce: 'pre', - configResolved: (config) => { - ROOT = config.root - }, - transform(code, id) { - const url = pathToFileURL(id) - url.searchParams.delete('v') - id = fileURLToPath(url).replace(/\\/g, '/') + if (id === '/~start/default-server-entry.tsx') { + return ` +import { createStartHandler, defaultStreamHandler } from '@tanstack/react-start/server' +import { createRouter } from ${routerImportPath} - const includesToken = tokenRegex.test(code) - // const includesEitherFunc = eitherFuncRegex.test(code) +export default createStartHandler({ + createRouter, +})(defaultStreamHandler) +` + } - if ( - !includesToken - // includesEitherFunc - // /node_modules/.test(id) - ) { return null - } - - if (code.includes('@react-refresh')) { - throw new Error( - `We detected that the '@vitejs/plugin-react' was passed before '@tanstack/react-start-plugin'. Please make sure that '@tanstack/router-vite-plugin' is passed before '@vitejs/plugin-react' and try again: -e.g. - -plugins: [ - TanStackStartVite(), // Place this before viteReact() - viteReact(), -] -`, - ) - } - - if (debug) console.info(`${opts.env} Compiling Start: `, id) - - const compiled = compileStartOutput({ - code, - root: ROOT, - filename: id, - env: opts.env, - }) - - if (debug) { - logDiff(code, compiled.code) - console.log('Output:\n', compiled.code + '\n\n') - } - - return compiled + }, }, - } + viteReact(options.react), + ] } + +export { TanStackStartVitePlugin as tanstackStart } diff --git a/packages/react-start-plugin/src/schema.ts b/packages/react-start-plugin/src/schema.ts new file mode 100644 index 0000000000..4522cc801a --- /dev/null +++ b/packages/react-start-plugin/src/schema.ts @@ -0,0 +1,31 @@ +import { z } from 'zod' +import { + createTanStackConfig, + createTanStackStartOptionsSchema, +} from '@tanstack/start-plugin-core' +import type { Options as ViteReactOptions } from '@vitejs/plugin-react' + +export type WithReactPlugin = { + react?: ViteReactOptions +} + +const frameworkPlugin = { + react: z.custom().optional(), +} + +// eslint-disable-next-line unused-imports/no-unused-vars +const TanStackStartOptionsSchema = + createTanStackStartOptionsSchema(frameworkPlugin) + +const defaultConfig = createTanStackConfig(frameworkPlugin) + +export function getTanStackStartOptions(opts?: TanStackStartInputConfig) { + return defaultConfig.parse(opts) +} + +export type TanStackStartInputConfig = z.input< + typeof TanStackStartOptionsSchema +> +export type TanStackStartOutputConfig = ReturnType< + typeof getTanStackStartOptions +> diff --git a/packages/react-start-plugin/tsconfig.json b/packages/react-start-plugin/tsconfig.json index 37d21ef6ca..090ec3917d 100644 --- a/packages/react-start-plugin/tsconfig.json +++ b/packages/react-start-plugin/tsconfig.json @@ -3,6 +3,8 @@ "include": ["src", "vite.config.ts", "tests"], "exclude": ["tests/**/test-files/**", "tests/**/snapshots/**"], "compilerOptions": { - "jsx": "react-jsx" + "outDir": "dist/esm", + "target": "esnext", + "noEmit": true } } diff --git a/packages/react-start-plugin/vite.config.ts b/packages/react-start-plugin/vite.config.ts index 5389f0f739..2c711fd181 100644 --- a/packages/react-start-plugin/vite.config.ts +++ b/packages/react-start-plugin/vite.config.ts @@ -16,5 +16,6 @@ export default mergeConfig( tanstackViteConfig({ entry: './src/index.ts', srcDir: './src', + outDir: './dist', }), ) diff --git a/packages/react-start-router-manifest/README.md b/packages/react-start-router-manifest/README.md deleted file mode 100644 index bb009b0c87..0000000000 --- a/packages/react-start-router-manifest/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/react-start-router-manifest/eslint.config.js b/packages/react-start-router-manifest/eslint.config.js deleted file mode 100644 index 931f0ec774..0000000000 --- a/packages/react-start-router-manifest/eslint.config.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check - -import pluginReact from '@eslint-react/eslint-plugin' -import pluginReactHooks from 'eslint-plugin-react-hooks' -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - ...pluginReact.configs.recommended, - files: ['**/*.{ts,tsx}'], - }, - { - plugins: { - 'react-hooks': pluginReactHooks, - }, - rules: { - '@eslint-react/no-unstable-context-value': 'off', - '@eslint-react/no-unstable-default-props': 'off', - '@eslint-react/dom/no-missing-button-type': 'off', - 'react-hooks/exhaustive-deps': 'error', - 'react-hooks/rules-of-hooks': 'error', - }, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/react-start-router-manifest/package.json b/packages/react-start-router-manifest/package.json deleted file mode 100644 index f367442a9c..0000000000 --- a/packages/react-start-router-manifest/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "@tanstack/react-start-router-manifest", - "version": "1.120.3", - "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/react-start-router-manifest" - }, - "homepage": "https://tanstack.com/start", - "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": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "tsc" - }, - "type": "module", - "types": "dist/esm/index.d.ts", - "exports": { - ".": { - "import": { - "types": "./dist/esm/index.d.ts", - "default": "./dist/esm/index.js" - } - }, - "./package.json": "./package.json" - }, - "sideEffects": false, - "files": [ - "dist", - "src" - ], - "engines": { - "node": ">=12" - }, - "dependencies": { - "@tanstack/router-core": "workspace:^", - "tiny-invariant": "^1.3.3", - "vinxi": "0.5.3" - }, - "devDependencies": { - "typescript": "^5.7.2" - } -} diff --git a/packages/react-start-router-manifest/src/index.ts b/packages/react-start-router-manifest/src/index.ts deleted file mode 100644 index 3f0a37f609..0000000000 --- a/packages/react-start-router-manifest/src/index.ts +++ /dev/null @@ -1,88 +0,0 @@ -// @ts-expect-error -import tsrGetManifest from 'tsr:routes-manifest' -import { getManifest } from 'vinxi/manifest' -import { default as invariant } from 'tiny-invariant' -import type { Manifest } from '@tanstack/router-core' - -function sanitizeBase(base: string) { - return base.replace(/^\/|\/$/g, '') -} - -/** - * @description Returns the full, unfiltered router manifest. This includes relationships - * between routes, assets, and preloads and is NOT what you want to serialize and - * send to the client. - */ -export function getFullRouterManifest() { - const routerManifest = tsrGetManifest() as Manifest - - const rootRoute = (routerManifest.routes.__root__ = - routerManifest.routes.__root__ || {}) - - rootRoute.assets = rootRoute.assets || [] - - let script = '' - // Always fake that HMR is ready - if (process.env.NODE_ENV === 'development') { - const CLIENT_BASE = sanitizeBase(process.env.TSS_CLIENT_BASE || '') - - if (!CLIENT_BASE) { - throw new Error( - 'tanstack/start-router-manifest: TSS_CLIENT_BASE must be defined in your environment for getFullRouterManifest()', - ) - } - script = `import RefreshRuntime from "/${CLIENT_BASE}/@react-refresh"; - RefreshRuntime.injectIntoGlobalHook(window) - window.$RefreshReg$ = () => {} - window.$RefreshSig$ = () => (type) => type - window.__vite_plugin_react_preamble_installed__ = true;` - } - - // Get the entry for the client from vinxi - const vinxiClientManifest = getManifest('client') - - const importPath = - vinxiClientManifest.inputs[vinxiClientManifest.handler]?.output.path - if (!importPath) { - invariant(importPath, 'Could not find client entry in vinxi manifest') - } - - rootRoute.assets.push({ - tag: 'script', - attrs: { - type: 'module', - suppressHydrationWarning: true, - async: true, - }, - children: `${script}import("${importPath}")`, - }) - - return routerManifest -} - -/** - * @description Returns the router manifest that should be sent to the client. - * This includes only the assets and preloads for the current route and any - * special assets that are needed for the client. It does not include relationships - * between routes or any other data that is not needed for the client. - */ -export function getRouterManifest() { - const routerManifest = getFullRouterManifest() - - // Strip out anything that isn't needed for the client - return { - ...routerManifest, - routes: Object.fromEntries( - Object.entries(routerManifest.routes).map(([k, v]: any) => { - const { preloads, assets } = v - return [ - k, - { - preloads, - assets, - }, - ] - }), - ), - } -} diff --git a/packages/react-start-router-manifest/tsconfig.json b/packages/react-start-router-manifest/tsconfig.json deleted file mode 100644 index 940a9cce0a..0000000000 --- a/packages/react-start-router-manifest/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": ["src/index.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist/esm", - "target": "esnext", - "noEmit": false - } -} diff --git a/packages/react-start-router-manifest/vite.config.ts b/packages/react-start-router-manifest/vite.config.ts deleted file mode 100644 index d6472068fb..0000000000 --- a/packages/react-start-router-manifest/vite.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { defineConfig, mergeConfig } from 'vitest/config' -import { tanstackViteConfig } from '@tanstack/config/vite' -import packageJson from './package.json' -import type { ViteUserConfig } from 'vitest/config' - -const config = defineConfig({ - plugins: [] as ViteUserConfig['plugins'], - test: { - name: packageJson.name, - watch: false, - environment: 'jsdom', - }, -}) - -export default mergeConfig( - config, - tanstackViteConfig({ - entry: './src/index.ts', - srcDir: './src', - externalDeps: ['tsr:routes-manifest'], - }), -) diff --git a/packages/react-start-server/README.md b/packages/react-start-server/README.md index bb009b0c87..7be47d33fd 100644 --- a/packages/react-start-server/README.md +++ b/packages/react-start-server/README.md @@ -1,33 +1,9 @@ -> 🤫 we're cooking up something special! - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! +# TanStack React Start - Server - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - +This package is not meant to be used directly. It is a dependency of [`@tanstack/react-start`](https://www.npmjs.com/package/@tanstack/react-start). -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) +TanStack React Start is a fullstack-framework made for SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router). -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! +Head over to [tanstack.com/start](https://tanstack.com/start) for more information about getting started. diff --git a/packages/react-start-server/package.json b/packages/react-start-server/package.json index 9bbf439abe..a845a9d8e1 100644 --- a/packages/react-start-server/package.json +++ b/packages/react-start-server/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-start-server", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -68,6 +68,7 @@ "@tanstack/start-client-core": "workspace:^", "@tanstack/start-server-core": "workspace:^", "tiny-warning": "^1.0.3", + "tiny-invariant": "^1.3.3", "h3": "1.13.0", "isbot": "^5.1.22", "jsesc": "^3.1.0", diff --git a/packages/react-start-server/src/defaultStreamHandler.tsx b/packages/react-start-server/src/defaultStreamHandler.tsx index e95a9fcb87..8891dfd218 100644 --- a/packages/react-start-server/src/defaultStreamHandler.tsx +++ b/packages/react-start-server/src/defaultStreamHandler.tsx @@ -54,6 +54,11 @@ export const defaultStreamHandler = defineHandlerCallback( }, }), onError: (error, info) => { + if ( + error instanceof Error && + error.message === 'ShellBoundaryError' + ) + return console.error('Error in renderToPipeableStream:', error, info) }, }, diff --git a/packages/react-start-server/tsconfig.json b/packages/react-start-server/tsconfig.json index 134e51f065..b447592593 100644 --- a/packages/react-start-server/tsconfig.json +++ b/packages/react-start-server/tsconfig.json @@ -8,6 +8,6 @@ "src", "tests", "vite.config.ts", - "../start-client/src/tsrScript.ts" + "../start-server-core/src/server-functions-handler.ts" ] } diff --git a/packages/react-start-server/vite.config.ts b/packages/react-start-server/vite.config.ts index e05e5cc394..3a4c1c54ef 100644 --- a/packages/react-start-server/vite.config.ts +++ b/packages/react-start-server/vite.config.ts @@ -19,5 +19,10 @@ export default mergeConfig( tanstackViteConfig({ srcDir: './src', entry: './src/index.tsx', + externalDeps: [ + 'tanstack-start-server-fn-manifest:v', + 'tanstack-start-router-manifest:v', + 'tanstack-start-server-routes-manifest:v', + ], }), ) diff --git a/packages/react-start/README.md b/packages/react-start/README.md index bb009b0c87..a36c48bd14 100644 --- a/packages/react-start/README.md +++ b/packages/react-start/README.md @@ -1,33 +1,42 @@ -> 🤫 we're cooking up something special! - -# TanStack Start +# TanStack React Start -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) +![TanStack React Start Header](https://github.com/tanstack/router/raw/main/media/header.png) -🤖 Type-safe router w/ built-in caching & URL state management for React! +SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router) and Vite. Ready to deploy to your favorite hosting provider. #TanStack - + + - - - - - - semantic-release - + + + + + + + + + semantic-release + + Join the discussion on Github -Best of JS + + + Best of JS + + - + + - + + Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! +Visit [tanstack.com/start](https://tanstack.com/start) for docs, guides, API and more! diff --git a/packages/react-start/package.json b/packages/react-start/package.json index a08b503980..761ed13bd6 100644 --- a/packages/react-start/package.json +++ b/packages/react-start/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-start", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -62,34 +62,14 @@ "default": "./dist/cjs/server.cjs" } }, - "./config": { + "./plugin/vite": { "import": { - "types": "./dist/esm/config.d.ts", - "default": "./dist/esm/config.js" + "types": "./dist/esm/plugin-vite.d.ts", + "default": "./dist/esm/plugin-vite.js" }, "require": { - "types": "./dist/cjs/config.d.cts", - "default": "./dist/cjs/config.cjs" - } - }, - "./api": { - "import": { - "types": "./dist/esm/api.d.ts", - "default": "./dist/esm/api.js" - }, - "require": { - "types": "./dist/cjs/api.d.cts", - "default": "./dist/cjs/api.cjs" - } - }, - "./router-manifest": { - "import": { - "types": "./dist/esm/router-manifest.d.ts", - "default": "./dist/esm/router-manifest.js" - }, - "require": { - "types": "./dist/cjs/router-manifest.d.cts", - "default": "./dist/cjs/router-manifest.cjs" + "types": "./dist/cjs/plugin-vite.d.cts", + "default": "./dist/cjs/plugin-vite.cjs" } }, "./server-functions-client": { @@ -112,26 +92,6 @@ "default": "./dist/cjs/server-functions-server.cjs" } }, - "./server-functions-handler": { - "import": { - "types": "./dist/esm/server-functions-handler.d.ts", - "default": "./dist/esm/server-functions-handler.js" - }, - "require": { - "types": "./dist/cjs/server-functions-handler.d.cts", - "default": "./dist/cjs/server-functions-handler.cjs" - } - }, - "./server-functions-ssr": { - "import": { - "types": "./dist/esm/server-functions-ssr.d.ts", - "default": "./dist/esm/server-functions-ssr.js" - }, - "require": { - "types": "./dist/cjs/server-functions-ssr.d.cts", - "default": "./dist/cjs/server-functions-ssr.cjs" - } - }, "./package.json": "./package.json" }, "sideEffects": false, @@ -145,18 +105,15 @@ "dependencies": { "@tanstack/react-start-client": "workspace:^", "@tanstack/react-start-server": "workspace:^", - "@tanstack/react-start-config": "workspace:^", - "@tanstack/react-start-router-manifest": "workspace:^", + "@tanstack/react-start-plugin": "workspace:^", "@tanstack/start-server-functions-client": "workspace:^", - "@tanstack/start-server-functions-server": "workspace:^", - "@tanstack/start-server-functions-handler": "workspace:^", - "@tanstack/start-server-functions-ssr": "workspace:^", - "@tanstack/start-api-routes": "workspace:^" + "@tanstack/start-server-functions-server": "workspace:^" }, "peerDependencies": { + "@vitejs/plugin-react": ">=4.3.4", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0", - "vite": "^6.0.0" + "vite": ">=6.0.0" }, "devDependencies": { "esbuild": "^0.25.0" diff --git a/packages/react-start/src/api.tsx b/packages/react-start/src/api.tsx deleted file mode 100644 index fff3bec5ea..0000000000 --- a/packages/react-start/src/api.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/start-api-routes' diff --git a/packages/react-start/src/config.tsx b/packages/react-start/src/config.tsx deleted file mode 100644 index 57a7ae394d..0000000000 --- a/packages/react-start/src/config.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/react-start-config' diff --git a/packages/react-start/src/plugin-vite.ts b/packages/react-start/src/plugin-vite.ts new file mode 100644 index 0000000000..d991c3b71c --- /dev/null +++ b/packages/react-start/src/plugin-vite.ts @@ -0,0 +1 @@ +export * from '@tanstack/react-start-plugin' diff --git a/packages/react-start/src/router-manifest.tsx b/packages/react-start/src/router-manifest.tsx deleted file mode 100644 index ce430d7884..0000000000 --- a/packages/react-start/src/router-manifest.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/react-start-router-manifest' diff --git a/packages/react-start/src/server-functions-handler.tsx b/packages/react-start/src/server-functions-handler.tsx deleted file mode 100644 index c3cc9770d2..0000000000 --- a/packages/react-start/src/server-functions-handler.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/start-server-functions-handler' diff --git a/packages/react-start/src/server-functions-ssr.tsx b/packages/react-start/src/server-functions-ssr.tsx deleted file mode 100644 index 7359e26f45..0000000000 --- a/packages/react-start/src/server-functions-ssr.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/start-server-functions-ssr' diff --git a/packages/react-start/vite.config.ts b/packages/react-start/vite.config.ts index 46bc2ea875..99fd4a8b00 100644 --- a/packages/react-start/vite.config.ts +++ b/packages/react-start/vite.config.ts @@ -17,22 +17,16 @@ export default mergeConfig( entry: [ './src/client.tsx', './src/server.tsx', - './src/config.tsx', - './src/router-manifest.tsx', + './src/plugin-vite.ts', './src/server-functions-client.tsx', './src/server-functions-server.tsx', - './src/server-functions-ssr.tsx', - './src/api.tsx', ], externalDeps: [ '@tanstack/react-start-client', '@tanstack/react-start-server', - '@tanstack/react-start-config', - '@tanstack/react-start-router-manifest', + '@tanstack/react-start-plugin', '@tanstack/start-server-functions-client', '@tanstack/start-server-functions-server', - '@tanstack/start-server-functions-ssr', - '@tanstack/start-api-routes', ], }), ) diff --git a/packages/router-cli/package.json b/packages/router-cli/package.json index 3d620859f8..fd4a56148c 100644 --- a/packages/router-cli/package.json +++ b/packages/router-cli/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/router-cli", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/router-core/package.json b/packages/router-core/package.json index ce60e3f821..c691a964c0 100644 --- a/packages/router-core/package.json +++ b/packages/router-core/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/router-core", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/router-core/src/fileRoute.ts b/packages/router-core/src/fileRoute.ts index 8d2e5b33a5..2c689c3929 100644 --- a/packages/router-core/src/fileRoute.ts +++ b/packages/router-core/src/fileRoute.ts @@ -2,6 +2,10 @@ import type { AnyContext, AnyPathParams, AnyRoute, + FileBaseRouteOptions, + ResolveParams, + Route, + RouteConstraints, UpdatableRouteOptions, } from './route' import type { AnyValidator } from './validators' @@ -28,6 +32,87 @@ export interface FileRoutesByPath { // } } +export interface FileRouteOptions< + TFilePath extends string, + TParentRoute extends AnyRoute, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TSearchValidator = undefined, + TParams = ResolveParams, + TRouteContextFn = AnyContext, + TBeforeLoadFn = AnyContext, + TLoaderDeps extends Record = {}, + TLoaderFn = undefined, +> extends FileBaseRouteOptions< + TParentRoute, + TId, + TPath, + TSearchValidator, + TParams, + TLoaderDeps, + TLoaderFn, + AnyContext, + TRouteContextFn, + TBeforeLoadFn + >, + UpdatableRouteOptions< + TParentRoute, + TId, + TFullPath, + TParams, + TSearchValidator, + TLoaderFn, + TLoaderDeps, + AnyContext, + TRouteContextFn, + TBeforeLoadFn + > {} + +export type CreateFileRoute< + TFilePath extends string, + TParentRoute extends AnyRoute, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], +> = < + TSearchValidator = undefined, + TParams = ResolveParams, + TRouteContextFn = AnyContext, + TBeforeLoadFn = AnyContext, + TLoaderDeps extends Record = {}, + TLoaderFn = undefined, +>( + options?: FileRouteOptions< + TFilePath, + TParentRoute, + TId, + TPath, + TFullPath, + TSearchValidator, + TParams, + TRouteContextFn, + TBeforeLoadFn, + TLoaderDeps, + TLoaderFn + >, +) => Route< + TParentRoute, + TPath, + TFullPath, + TFilePath, + TId, + TSearchValidator, + TParams, + AnyContext, + TRouteContextFn, + TBeforeLoadFn, + TLoaderDeps, + TLoaderFn, + unknown, + unknown +> + export type LazyRouteOptions = Pick< UpdatableRouteOptions< AnyRoute, @@ -44,8 +129,12 @@ export type LazyRouteOptions = Pick< 'component' | 'errorComponent' | 'pendingComponent' | 'notFoundComponent' > -export interface LazyRoute { +export interface LazyRoute { options: { id: string } & LazyRouteOptions } + +export type CreateLazyFileRoute = ( + opts: LazyRouteOptions, +) => LazyRoute diff --git a/packages/router-core/src/index.ts b/packages/router-core/src/index.ts index 4988400855..9f47c3ac3a 100644 --- a/packages/router-core/src/index.ts +++ b/packages/router-core/src/index.ts @@ -3,7 +3,6 @@ export type { DeferredPromiseState, DeferredPromise } from './defer' export { preloadWarning } from './link' export type { IsRequiredParams, - ParsePathParams, AddTrailingSlash, RemoveTrailingSlashes, AddLeadingSlash, @@ -60,8 +59,10 @@ export type { InferFileRouteTypes, FileRouteTypes, FileRoutesByPath, + CreateFileRoute, LazyRoute, LazyRouteOptions, + CreateLazyFileRoute, } from './fileRoute' export type { @@ -142,15 +143,11 @@ export type { ErrorRouteProps, ErrorComponentProps, NotFoundRouteProps, - ParseSplatParams, - SplatParams, ResolveParams, ParseParamsFn, StringifyParamsFn, ParamsOptions, UpdatableStaticRouteOption, - LooseReturnType, - LooseAsyncReturnType, ContextReturnType, ContextAsyncReturnType, ResolveRouteContext, @@ -198,6 +195,8 @@ export type { RouteAddChildrenFn, RouteAddFileChildrenFn, RouteAddFileTypesFn, + ResolveOptionalParams, + ResolveRequiredParams, } from './route' export { @@ -209,6 +208,8 @@ export { SearchParamError, PathParamError, getInitialRouterState, + processRouteTree, + getMatchedRoutes, } from './router' export type { ViewTransitionOptions, @@ -242,7 +243,6 @@ export type { ControllablePromise, InjectedHtmlEntry, RouterErrorSerializer, - MatchedRoutesResult, EmitFn, LoadFn, GetMatchFn, @@ -322,6 +322,8 @@ export type { MergeAll, ValidateJSON, StrictOrFrom, + LooseReturnType, + LooseAsyncReturnType, } from './utils' export type { @@ -370,7 +372,12 @@ export type { UseLoaderDataResult, ResolveUseLoaderData } from './useLoaderData' export type { Redirect, ResolvedRedirect, AnyRedirect } from './redirect' -export { redirect, isRedirect, isResolvedRedirect } from './redirect' +export { + redirect, + isRedirect, + isResolvedRedirect, + parseRedirect, +} from './redirect' export type { NotFoundError } from './not-found' export { isNotFound, notFound } from './not-found' diff --git a/packages/router-core/src/link.ts b/packages/router-core/src/link.ts index 26d038e769..6f488b10cc 100644 --- a/packages/router-core/src/link.ts +++ b/packages/router-core/src/link.ts @@ -30,18 +30,98 @@ import type { ParsedLocation } from './location' export type IsRequiredParams = Record extends TParams ? never : true -export type ParsePathParams = T & - `${string}$${string}` extends never - ? TAcc - : T extends `${string}$${infer TPossiblyParam}` - ? TPossiblyParam extends '' - ? TAcc - : TPossiblyParam & `${string}/${string}` extends never - ? TPossiblyParam | TAcc - : TPossiblyParam extends `${infer TParam}/${infer TRest}` - ? ParsePathParams +export interface ParsePathParamsResult< + in out TRequired, + in out TOptional, + in out TRest, +> { + required: TRequired + optional: TOptional + rest: TRest +} + +export type AnyParsePathParamsResult = ParsePathParamsResult< + string, + string, + string +> + +export type ParsePathParamsBoundaryStart = + T extends `${infer TLeft}{-${infer TRight}` + ? ParsePathParamsResult< + ParsePathParams['required'], + | ParsePathParams['optional'] + | ParsePathParams['required'] + | ParsePathParams['optional'], + ParsePathParams['rest'] + > + : T extends `${infer TLeft}{${infer TRight}` + ? ParsePathParamsResult< + | ParsePathParams['required'] + | ParsePathParams['required'], + | ParsePathParams['optional'] + | ParsePathParams['optional'], + ParsePathParams['rest'] + > + : never + +export type ParsePathParamsSymbol = + T extends `${string}$${infer TRight}` + ? TRight extends `${string}/${string}` + ? TRight extends `${infer TParam}/${infer TRest}` + ? TParam extends '' + ? ParsePathParamsResult< + ParsePathParams['required'], + '_splat' | ParsePathParams['optional'], + ParsePathParams['rest'] + > + : ParsePathParamsResult< + TParam | ParsePathParams['required'], + ParsePathParams['optional'], + ParsePathParams['rest'] + > + : never + : TRight extends '' + ? ParsePathParamsResult + : ParsePathParamsResult + : never + +export type ParsePathParamsBoundaryEnd = + T extends `${infer TLeft}}${infer TRight}` + ? ParsePathParamsResult< + | ParsePathParams['required'] + | ParsePathParams['required'], + | ParsePathParams['optional'] + | ParsePathParams['optional'], + ParsePathParams['rest'] + > + : never + +export type ParsePathParamsEscapeStart = + T extends `${infer TLeft}[${infer TRight}` + ? ParsePathParamsResult< + | ParsePathParams['required'] + | ParsePathParams['required'], + | ParsePathParams['optional'] + | ParsePathParams['optional'], + ParsePathParams['rest'] + > + : never + +export type ParsePathParamsEscapeEnd = + T extends `${string}]${infer TRight}` ? ParsePathParams : never + +export type ParsePathParams = T extends `${string}[${string}` + ? ParsePathParamsEscapeStart + : T extends `${string}]${string}` + ? ParsePathParamsEscapeEnd + : T extends `${string}}${string}` + ? ParsePathParamsBoundaryEnd + : T extends `${string}{${string}` + ? ParsePathParamsBoundaryStart + : T extends `${string}$${string}` + ? ParsePathParamsSymbol : never - : TAcc export type AddTrailingSlash = T extends `${string}/` ? T : `${T & string}/` @@ -344,6 +424,7 @@ export type ToSubOptionsProps< hash?: true | Updater state?: true | NonNullableUpdater from?: FromPathOption & {} + unsafeRelative?: 'path' } export type ParamsReducerFn< @@ -591,6 +672,11 @@ export interface LinkOptionsProps { * @default false */ disabled?: boolean + /** + * When the preload strategy is set to `intent`, this controls the proximity of the link to the cursor before it is preloaded. + * If the user exits this proximity before this delay, the preload will be cancelled. + */ + preloadIntentProximity?: number } export type LinkOptions< diff --git a/packages/router-core/src/path.ts b/packages/router-core/src/path.ts index 4d002673cd..e1f6d737df 100644 --- a/packages/router-core/src/path.ts +++ b/packages/router-core/src/path.ts @@ -5,6 +5,9 @@ import type { AnyPathParams } from './route' export interface Segment { type: 'pathname' | 'param' | 'wildcard' value: string + // Add a new property to store the static segment if present + prefixSegment?: string + suffixSegment?: string } export function joinPaths(paths: Array) { @@ -137,10 +140,52 @@ export function resolvePath({ } } - const joined = joinPaths([basepath, ...baseSegments.map((d) => d.value)]) + const segmentValues = baseSegments.map((segment) => { + if (segment.type === 'param') { + const param = segment.value.substring(1) + if (segment.prefixSegment && segment.suffixSegment) { + return `${segment.prefixSegment}{$${param}}${segment.suffixSegment}` + } else if (segment.prefixSegment) { + return `${segment.prefixSegment}{$${param}}` + } else if (segment.suffixSegment) { + return `{$${param}}${segment.suffixSegment}` + } + } + if (segment.type === 'wildcard') { + if (segment.prefixSegment && segment.suffixSegment) { + return `${segment.prefixSegment}{$}${segment.suffixSegment}` + } else if (segment.prefixSegment) { + return `${segment.prefixSegment}{$}` + } else if (segment.suffixSegment) { + return `{$}${segment.suffixSegment}` + } + } + return segment.value + }) + const joined = joinPaths([basepath, ...segmentValues]) return cleanPath(joined) } +const PARAM_RE = /^\$.{1,}$/ // $paramName +const PARAM_W_CURLY_BRACES_RE = /^(.*?)\{(\$[a-zA-Z_$][a-zA-Z0-9_$]*)\}(.*)$/ // prefix{$paramName}suffix +const WILDCARD_RE = /^\$$/ // $ +const WILDCARD_W_CURLY_BRACES_RE = /^(.*?)\{\$\}(.*)$/ // prefix{$}suffix + +/** + * Required: `/foo/$bar` ✅ + * Prefix and Suffix: `/foo/prefix${bar}suffix` ✅ + * Wildcard: `/foo/$` ✅ + * Wildcard with Prefix and Suffix: `/foo/prefix{$}suffix` ✅ + * + * Future: + * Optional: `/foo/{-bar}` + * Optional named segment: `/foo/{bar}` + * Optional named segment with Prefix and Suffix: `/foo/prefix{-bar}suffix` + * Escape special characters: + * - `/foo/[$]` - Static route + * - `/foo/[$]{$foo} - Dynamic route with a static prefix of `$` + * - `/foo/{$foo}[$]` - Dynamic route with a static suffix of `$` + */ export function parsePathname(pathname?: string): Array { if (!pathname) { return [] @@ -167,20 +212,55 @@ export function parsePathname(pathname?: string): Array { segments.push( ...split.map((part): Segment => { - if (part === '$' || part === '*') { + // Check for wildcard with curly braces: prefix{$}suffix + const wildcardBracesMatch = part.match(WILDCARD_W_CURLY_BRACES_RE) + if (wildcardBracesMatch) { + const prefix = wildcardBracesMatch[1] + const suffix = wildcardBracesMatch[2] return { type: 'wildcard', - value: part, + value: '$', + prefixSegment: prefix || undefined, + suffixSegment: suffix || undefined, } } - if (part.charAt(0) === '$') { + // Check for the new parameter format: prefix{$paramName}suffix + const paramBracesMatch = part.match(PARAM_W_CURLY_BRACES_RE) + if (paramBracesMatch) { + const prefix = paramBracesMatch[1] + const paramName = paramBracesMatch[2] + const suffix = paramBracesMatch[3] return { type: 'param', - value: part, + value: '' + paramName, + prefixSegment: prefix || undefined, + suffixSegment: suffix || undefined, } } + // Check for bare parameter format: $paramName (without curly braces) + if (PARAM_RE.test(part)) { + const paramName = part.substring(1) + return { + type: 'param', + value: '$' + paramName, + prefixSegment: undefined, + suffixSegment: undefined, + } + } + + // Check for bare wildcard: $ (without curly braces) + if (WILDCARD_RE.test(part)) { + return { + type: 'wildcard', + value: '$', + prefixSegment: undefined, + suffixSegment: undefined, + } + } + + // Handle regular pathname segment return { type: 'pathname', value: part.includes('%25') @@ -248,9 +328,13 @@ export function interpolatePath({ interpolatedPathSegments.map((segment) => { if (segment.type === 'wildcard') { usedParams._splat = params._splat + const segmentPrefix = segment.prefixSegment || '' + const segmentSuffix = segment.suffixSegment || '' const value = encodeParam('_splat') - if (leaveWildcards) return `${segment.value}${value ?? ''}` - return value + if (leaveWildcards) { + return `${segmentPrefix}${segment.value}${value ?? ''}${segmentSuffix}` + } + return `${segmentPrefix}${value}${segmentSuffix}` } if (segment.type === 'param') { @@ -259,11 +343,14 @@ export function interpolatePath({ isMissingParams = true } usedParams[key] = params[key] + + const segmentPrefix = segment.prefixSegment || '' + const segmentSuffix = segment.suffixSegment || '' if (leaveParams) { const value = encodeParam(segment.value) - return `${segment.value}${value ?? ''}` + return `${segmentPrefix}${segment.value}${value ?? ''}${segmentSuffix}` } - return encodeParam(key) ?? 'undefined' + return `${segmentPrefix}${encodeParam(key) ?? 'undefined'}${segmentSuffix}` } return segment.value @@ -390,9 +477,57 @@ export function matchByPath( if (routeSegment) { if (routeSegment.type === 'wildcard') { - const _splat = decodeURI( - joinPaths(baseSegments.slice(i).map((d) => d.value)), - ) + // Capture all remaining segments for a wildcard + const remainingBaseSegments = baseSegments.slice(i) + + let _splat: string + + // If this is a wildcard with prefix/suffix, we need to handle the first segment specially + if (routeSegment.prefixSegment || routeSegment.suffixSegment) { + if (!baseSegment) return false + + const prefix = routeSegment.prefixSegment || '' + const suffix = routeSegment.suffixSegment || '' + + // Check if the base segment starts with prefix and ends with suffix + const baseValue = baseSegment.value + if ('prefixSegment' in routeSegment) { + if (!baseValue.startsWith(prefix)) { + return false + } + } + if ('suffixSegment' in routeSegment) { + if ( + !baseSegments[baseSegments.length - 1]?.value.endsWith(suffix) + ) { + return false + } + } + + let rejoinedSplat = decodeURI( + joinPaths(remainingBaseSegments.map((d) => d.value)), + ) + + // Remove the prefix and suffix from the rejoined splat + if (prefix && rejoinedSplat.startsWith(prefix)) { + rejoinedSplat = rejoinedSplat.slice(prefix.length) + } + + if (suffix && rejoinedSplat.endsWith(suffix)) { + rejoinedSplat = rejoinedSplat.slice( + 0, + rejoinedSplat.length - suffix.length, + ) + } + + _splat = rejoinedSplat + } else { + // If no prefix/suffix, just rejoin the remaining segments + _splat = decodeURI( + joinPaths(remainingBaseSegments.map((d) => d.value)), + ) + } + // TODO: Deprecate * params['*'] = _splat params['_splat'] = _splat @@ -426,11 +561,41 @@ export function matchByPath( if (baseSegment.value === '/') { return false } - if (baseSegment.value.charAt(0) !== '$') { - params[routeSegment.value.substring(1)] = decodeURIComponent( - baseSegment.value, - ) + + let _paramValue: string + + // If this param has prefix/suffix, we need to extract the actual parameter value + if (routeSegment.prefixSegment || routeSegment.suffixSegment) { + const prefix = routeSegment.prefixSegment || '' + const suffix = routeSegment.suffixSegment || '' + + // Check if the base segment starts with prefix and ends with suffix + const baseValue = baseSegment.value + if (prefix && !baseValue.startsWith(prefix)) { + return false + } + if (suffix && !baseValue.endsWith(suffix)) { + return false + } + + let paramValue = baseValue + if (prefix && paramValue.startsWith(prefix)) { + paramValue = paramValue.slice(prefix.length) + } + if (suffix && paramValue.endsWith(suffix)) { + paramValue = paramValue.slice( + 0, + paramValue.length - suffix.length, + ) + } + + _paramValue = decodeURIComponent(paramValue) + } else { + // If no prefix/suffix, just decode the base segment value + _paramValue = decodeURIComponent(baseSegment.value) } + + params[routeSegment.value.substring(1)] = _paramValue } } diff --git a/packages/router-core/src/redirect.ts b/packages/router-core/src/redirect.ts index 24de9024b2..02e85221b9 100644 --- a/packages/router-core/src/redirect.ts +++ b/packages/router-core/src/redirect.ts @@ -1,6 +1,5 @@ import type { NavigateOptions } from './link' import type { AnyRouter, RegisteredRouter } from './router' -import type { PickAsRequired } from './utils' export type AnyRedirect = Redirect @@ -13,6 +12,17 @@ export type Redirect< TTo extends string | undefined = undefined, TMaskFrom extends string = TFrom, TMaskTo extends string = '.', +> = Response & { + options: NavigateOptions + redirectHandled?: boolean +} + +export type RedirectOptions< + TRouter extends AnyRouter = RegisteredRouter, + TFrom extends string = string, + TTo extends string | undefined = undefined, + TMaskFrom extends string = TFrom, + TMaskTo extends string = '.', > = { href?: string /** @@ -42,12 +52,7 @@ export type ResolvedRedirect< TTo extends string = '', TMaskFrom extends string = TFrom, TMaskTo extends string = '', -> = PickAsRequired< - Redirect, - 'code' | 'statusCode' | 'headers' -> & { - href: string -} +> = Redirect export function redirect< TRouter extends AnyRouter = RegisteredRouter, @@ -56,30 +61,48 @@ export function redirect< const TMaskFrom extends string = TFrom, const TMaskTo extends string = '', >( - opts: Redirect, + opts: RedirectOptions, ): Redirect { - ;(opts as any).isRedirect = true opts.statusCode = opts.statusCode || opts.code || 307 - opts.headers = opts.headers || {} + if (!opts.reloadDocument) { - opts.reloadDocument = false try { new URL(`${opts.href}`) opts.reloadDocument = true } catch {} } + const headers = new Headers(opts.headers || {}) + + const response = new Response(null, { + status: opts.statusCode, + headers, + }) + + ;(response as Redirect).options = + opts + if (opts.throw) { - throw opts + throw response } - return opts + return response as Redirect } export function isRedirect(obj: any): obj is AnyRedirect { - return !!obj?.isRedirect + return obj instanceof Response && !!(obj as any).options } -export function isResolvedRedirect(obj: any): obj is ResolvedRedirect { - return !!obj?.isRedirect && obj.href +export function isResolvedRedirect( + obj: any, +): obj is AnyRedirect & { options: { href: string } } { + return isRedirect(obj) && !!obj.options.href +} + +export function parseRedirect(obj: any) { + if (typeof obj === 'object' && obj.isSerializedRedirect) { + return redirect(obj) + } + + return undefined } diff --git a/packages/router-core/src/route.ts b/packages/router-core/src/route.ts index 6344357790..c87b77fe9e 100644 --- a/packages/router-core/src/route.ts +++ b/packages/router-core/src/route.ts @@ -1,3 +1,4 @@ +import invariant from 'tiny-invariant' import { joinPaths, trimPathLeft } from './path' import { notFound } from './not-found' import { rootRouteId } from './root' @@ -17,9 +18,12 @@ import type { AnyRouter, RegisteredRouter } from './router' import type { BuildLocationFn, NavigateFn } from './RouterProvider' import type { Assign, + Awaitable, Constrain, Expand, IntersectAssign, + LooseAsyncReturnType, + LooseReturnType, NoInfer, } from './utils' import type { @@ -150,27 +154,24 @@ export type ResolveSearchSchema = ? ResolveSearchSchemaFn : ResolveSearchSchemaFn -export type ParseSplatParams = TPath & - `${string}$` extends never - ? TPath & `${string}$/${string}` extends never - ? never - : '_splat' - : '_splat' +export type ResolveRequiredParams = { + [K in ParsePathParams['required']]: T +} -export interface SplatParams { - _splat?: string +export type ResolveOptionalParams = { + [K in ParsePathParams['optional']]?: T } -export type ResolveParams = - ParseSplatParams extends never - ? Record, string> - : Record, string> & SplatParams +export type ResolveParams< + TPath extends string, + T = string, +> = ResolveRequiredParams & ResolveOptionalParams export type ParseParamsFn = ( - rawParams: ResolveParams, -) => TParams extends Record, any> + rawParams: Expand>, +) => TParams extends ResolveParams ? TParams - : Record, any> + : ResolveParams export type StringifyParamsFn = ( params: TParams, @@ -270,20 +271,6 @@ export type TrimPathRight = T extends '/' ? TrimPathRight : T -export type LooseReturnType = T extends ( - ...args: Array -) => infer TReturn - ? TReturn - : never - -export type LooseAsyncReturnType = T extends ( - ...args: Array -) => infer TReturn - ? TReturn extends Promise - ? TReturn - : TReturn - : never - export type ContextReturnType = unknown extends TContextFn ? TContextFn : LooseReturnType extends never @@ -448,7 +435,7 @@ export interface RouteExtensions { } export type RouteLazyFn = ( - lazyFn: () => Promise, + lazyFn: () => Promise>, ) => TRoute export type RouteAddChildrenFn< @@ -602,7 +589,26 @@ export interface Route< > isRoot: TParentRoute extends AnyRoute ? true : false _componentsPromise?: Promise> - lazyFn?: () => Promise + lazyFn?: () => Promise< + LazyRoute< + Route< + TParentRoute, + TPath, + TFullPath, + TCustomId, + TId, + TSearchValidator, + TParams, + TRouterContext, + TRouteContextFn, + TBeforeLoadFn, + TLoaderDeps, + TLoaderFn, + TChildren, + TFileRouteTypes + > + > + > _lazyPromise?: Promise rank: number to: TrimPathRight @@ -621,7 +627,24 @@ export interface Route< TBeforeLoadFn >, ) => this - lazy: RouteLazyFn + lazy: RouteLazyFn< + Route< + TParentRoute, + TPath, + TFullPath, + TCustomId, + TId, + TSearchValidator, + TParams, + TRouterContext, + TRouteContextFn, + TBeforeLoadFn, + TLoaderDeps, + TLoaderFn, + TChildren, + TFileRouteTypes + > + > addChildren: RouteAddChildrenFn< TParentRoute, TPath, @@ -960,7 +983,7 @@ type AssetFnContextOptions< TLoaderDeps > params: ResolveAllParamsFromParent - loaderData: ResolveLoaderData + loaderData?: ResolveLoaderData } export interface DefaultUpdatableRouteOptionsExtensions { @@ -1070,9 +1093,20 @@ export interface UpdatableRouteOptions< TLoaderDeps >, ) => void - headers?: (ctx: { - loaderData: ResolveLoaderData - }) => Record + headers?: ( + ctx: AssetFnContextOptions< + TRouteId, + TFullPath, + TParentRoute, + TParams, + TSearchValidator, + TLoaderFn, + TRouterContext, + TRouteContextFn, + TBeforeLoadFn, + TLoaderDeps + >, + ) => Awaitable> head?: ( ctx: AssetFnContextOptions< TRouteId, @@ -1086,11 +1120,11 @@ export interface UpdatableRouteOptions< TBeforeLoadFn, TLoaderDeps >, - ) => { + ) => Awaitable<{ links?: AnyRouteMatch['links'] scripts?: AnyRouteMatch['headScripts'] meta?: AnyRouteMatch['meta'] - } + }> scripts?: ( ctx: AssetFnContextOptions< TRouteId, @@ -1104,7 +1138,7 @@ export interface UpdatableRouteOptions< TBeforeLoadFn, TLoaderDeps >, - ) => AnyRouteMatch['scripts'] + ) => Awaitable ssr?: boolean codeSplitGroupings?: Array< Array< @@ -1336,7 +1370,26 @@ export class BaseRoute< children?: TChildren originalIndex?: number rank!: number - lazyFn?: () => Promise + lazyFn?: () => Promise< + LazyRoute< + Route< + TParentRoute, + TPath, + TFullPath, + TCustomId, + TId, + TSearchValidator, + TParams, + TRouterContext, + TRouteContextFn, + TBeforeLoadFn, + TLoaderDeps, + TLoaderFn, + TChildren, + TFileRouteTypes + > + > + > _lazyPromise?: Promise _componentsPromise?: Promise> @@ -1409,7 +1462,8 @@ export class BaseRoute< if (isRoot) { this._path = rootRouteId as TPath } else if (!this.parentRoute) { - throw new Error( + invariant( + false, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`, ) } @@ -1449,6 +1503,16 @@ export class BaseRoute< this._ssr = options?.ssr ?? opts.defaultSsr ?? true } + clone = (other: typeof this) => { + this._path = other._path + this._id = other._id + this._fullPath = other._fullPath + this._to = other._to + this._ssr = other._ssr + this.options.getParentRoute = other.options.getParentRoute + this.children = other.children + } + addChildren: RouteAddChildrenFn< TParentRoute, TPath, @@ -1562,7 +1626,24 @@ export class BaseRoute< return this } - lazy: RouteLazyFn = (lazyFn) => { + lazy: RouteLazyFn< + Route< + TParentRoute, + TPath, + TFullPath, + TCustomId, + TId, + TSearchValidator, + TParams, + TRouterContext, + TRouteContextFn, + TBeforeLoadFn, + TLoaderDeps, + TLoaderFn, + TChildren, + TFileRouteTypes + > + > = (lazyFn) => { this.lazyFn = lazyFn return this } diff --git a/packages/router-core/src/router.ts b/packages/router-core/src/router.ts index 3a510d6506..7c45828fa1 100644 --- a/packages/router-core/src/router.ts +++ b/packages/router-core/src/router.ts @@ -28,7 +28,7 @@ import { isNotFound } from './not-found' import { setupScrollRestoration } from './scroll-restoration' import { defaultParseSearch, defaultStringifySearch } from './searchParams' import { rootRouteId } from './root' -import { isRedirect, isResolvedRedirect } from './redirect' +import { isRedirect } from './redirect' import type { SearchParser, SearchSerializer } from './searchParams' import type { AnyRedirect, ResolvedRedirect } from './redirect' import type { @@ -165,6 +165,14 @@ export interface RouterOptions< * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/preloading#preload-delay) */ defaultPreloadDelay?: number + /** + * The default `preloadIntentProximity` a route should use if no preloadIntentProximity is provided. + * + * @default 0 + * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultpreloadintentproximity-property) + * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/preloading#preload-intent-proximity) + */ + defaultPreloadIntentProximity?: number /** * The default `pendingMs` a route should use if no pendingMs is provided. * @@ -407,7 +415,7 @@ export interface RouterState< location: ParsedLocation> resolvedLocation?: ParsedLocation> statusCode: number - redirect?: ResolvedRedirect + redirect?: AnyRedirect } export interface BuildNextOptions { @@ -425,8 +433,9 @@ export interface BuildNextOptions { unmaskOnReload?: boolean } from?: string - _fromLocation?: ParsedLocation href?: string + _fromLocation?: ParsedLocation + unsafeRelative?: 'path' } type NavigationEventInfo = { @@ -513,11 +522,6 @@ export interface RouterErrorSerializer { deserialize: (err: TSerializedError) => unknown } -export interface MatchedRoutesResult { - matchedRoutes: Array - routeParams: Record -} - export type PreloadRouteFn< TRouteTree extends AnyRoute, TTrailingSlashOption extends TrailingSlashOption, @@ -593,8 +597,8 @@ export type ParseLocationFn = ( ) => ParsedLocation> export type GetMatchRoutesFn = ( - next: ParsedLocation, - dest?: BuildNextOptions, + pathname: string, + routePathname: string | undefined, ) => { matchedRoutes: Array routeParams: Record @@ -836,6 +840,8 @@ export class RouterCore< // router can be used in a non-react environment if necessary startTransition: StartTransitionFn = (fn) => fn() + isShell = false + update: UpdateFn< TRouteTree, TTrailingSlashOption, @@ -882,7 +888,6 @@ export class RouterCore< } if ( - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition !this.history || (this.options.history && this.options.history !== this.history) ) { @@ -901,7 +906,6 @@ export class RouterCore< this.buildRouteTree() } - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!this.__store) { this.__store = new Store(getInitialRouterState(this.latestLocation), { onUpdate: () => { @@ -920,13 +924,16 @@ export class RouterCore< if ( typeof window !== 'undefined' && 'CSS' in window && - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition typeof window.CSS?.supports === 'function' ) { this.isViewTransitionTypesSupported = window.CSS.supports( 'selector(:active-view-transition-type(a)', ) } + + if ((this.latestLocation.search as any).__TSS_SHELL) { + this.isShell = true + } } get state() { @@ -934,124 +941,29 @@ export class RouterCore< } buildRouteTree = () => { - this.routesById = {} as RoutesById - this.routesByPath = {} as RoutesByPath - - const notFoundRoute = this.options.notFoundRoute - if (notFoundRoute) { - notFoundRoute.init({ - originalIndex: 99999999999, - defaultSsr: this.options.defaultSsr, - }) - ;(this.routesById as any)[notFoundRoute.id] = notFoundRoute - } - - const recurseRoutes = (childRoutes: Array) => { - childRoutes.forEach((childRoute, i) => { - childRoute.init({ + const { routesById, routesByPath, flatRoutes } = processRouteTree({ + routeTree: this.routeTree, + initRoute: (route, i) => { + route.init({ originalIndex: i, defaultSsr: this.options.defaultSsr, }) - - const existingRoute = (this.routesById as any)[childRoute.id] - - invariant( - !existingRoute, - `Duplicate routes found with id: ${String(childRoute.id)}`, - ) - ;(this.routesById as any)[childRoute.id] = childRoute - - if (!childRoute.isRoot && childRoute.path) { - const trimmedFullPath = trimPathRight(childRoute.fullPath) - if ( - !(this.routesByPath as any)[trimmedFullPath] || - childRoute.fullPath.endsWith('/') - ) { - ;(this.routesByPath as any)[trimmedFullPath] = childRoute - } - } - - const children = childRoute.children - - if (children?.length) { - recurseRoutes(children) - } - }) - } - - recurseRoutes([this.routeTree]) - - const scoredRoutes: Array<{ - child: AnyRoute - trimmed: string - parsed: ReturnType - index: number - scores: Array - }> = [] - - const routes: Array = Object.values(this.routesById) - - routes.forEach((d, i) => { - if (d.isRoot || !d.path) { - return - } - - const trimmed = trimPathLeft(d.fullPath) - const parsed = parsePathname(trimmed) - - while (parsed.length > 1 && parsed[0]?.value === '/') { - parsed.shift() - } - - const scores = parsed.map((segment) => { - if (segment.value === '/') { - return 0.75 - } - - if (segment.type === 'param') { - return 0.5 - } - - if (segment.type === 'wildcard') { - return 0.25 - } - - return 1 - }) - - scoredRoutes.push({ child: d, trimmed, parsed, index: i, scores }) + }, }) - this.flatRoutes = scoredRoutes - .sort((a, b) => { - const minLength = Math.min(a.scores.length, b.scores.length) + this.routesById = routesById as RoutesById + this.routesByPath = routesByPath as RoutesByPath + this.flatRoutes = flatRoutes as Array - // Sort by min available score - for (let i = 0; i < minLength; i++) { - if (a.scores[i] !== b.scores[i]) { - return b.scores[i]! - a.scores[i]! - } - } - - // Sort by length of score - if (a.scores.length !== b.scores.length) { - return b.scores.length - a.scores.length - } - - // Sort by min available parsed value - for (let i = 0; i < minLength; i++) { - if (a.parsed[i]!.value !== b.parsed[i]!.value) { - return a.parsed[i]!.value > b.parsed[i]!.value ? 1 : -1 - } - } + const notFoundRoute = this.options.notFoundRoute - // Sort by original index - return a.index - b.index - }) - .map((d, i) => { - d.child.rank = i - return d.child + if (notFoundRoute) { + notFoundRoute.init({ + originalIndex: 99999999999, + defaultSsr: this.options.defaultSsr, }) + this.routesById[notFoundRoute.id] = notFoundRoute + } } subscribe: SubscribeFn = (eventType, fn) => { @@ -1155,9 +1067,9 @@ export class RouterCore< } as ParsedLocation, opts, ) - } else { - return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts) } + + return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts) } private matchRoutesInternal( @@ -1165,8 +1077,8 @@ export class RouterCore< opts?: MatchRoutesOpts, ): Array { const { foundRoute, matchedRoutes, routeParams } = this.getMatchedRoutes( - next, - opts?.dest, + next.pathname, + opts?.dest?.to as string, ) let isGlobalNotFound = false @@ -1418,7 +1330,8 @@ export class RouterCore< const route = this.looseRoutesById[match.routeId]! const existingMatch = this.getMatch(match.id) - // only execute `context` if we are not just building a location + // only execute `context` if we are not calling from router.buildLocation + if (!existingMatch && opts?._buildLocation !== true) { const parentMatch = matches[index - 1] const parentContext = getParentContext(parentMatch) @@ -1447,72 +1360,24 @@ export class RouterCore< ...match.__beforeLoadContext, } } - - // If it's already a success, update headers and head content - // These may get updated again if the match is refreshed - // due to being stale - if (match.status === 'success') { - match.headers = route.options.headers?.({ - loaderData: match.loaderData, - }) - const assetContext = { - matches, - match, - params: match.params, - loaderData: match.loaderData, - } - const headFnContent = route.options.head?.(assetContext) - match.links = headFnContent?.links - match.headScripts = headFnContent?.scripts - match.meta = headFnContent?.meta - match.scripts = route.options.scripts?.(assetContext) - } }) return matches } - getMatchedRoutes: GetMatchRoutesFn = (next, dest) => { - let routeParams: Record = {} - const trimmedPath = trimPathRight(next.pathname) - const getMatchedParams = (route: AnyRoute) => { - const result = matchPathname(this.basepath, trimmedPath, { - to: route.fullPath, - caseSensitive: - route.options.caseSensitive ?? this.options.caseSensitive, - fuzzy: true, - }) - return result - } - - let foundRoute: AnyRoute | undefined = - dest?.to !== undefined ? this.routesByPath[dest.to!] : undefined - if (foundRoute) { - routeParams = getMatchedParams(foundRoute)! - } else { - foundRoute = this.flatRoutes.find((route) => { - const matchedParams = getMatchedParams(route) - - if (matchedParams) { - routeParams = matchedParams - return true - } - - return false - }) - } - - let routeCursor: AnyRoute = - foundRoute || (this.routesById as any)[rootRouteId] - - const matchedRoutes: Array = [routeCursor] - - while (routeCursor.parentRoute) { - routeCursor = routeCursor.parentRoute - matchedRoutes.unshift(routeCursor) - } - - return { matchedRoutes, routeParams, foundRoute } + getMatchedRoutes: GetMatchRoutesFn = ( + pathname: string, + routePathname: string | undefined, + ) => { + return getMatchedRoutes({ + pathname, + routePathname, + basepath: this.basepath, + caseSensitive: this.options.caseSensitive, + routesByPath: this.routesByPath, + routesById: this.routesById, + flatRoutes: this.flatRoutes, + }) } cancelMatch = (id: string) => { @@ -1535,75 +1400,67 @@ export class RouterCore< dest: BuildNextOptions & { unmaskOnReload?: boolean } = {}, - matchedRoutesResult?: MatchedRoutesResult, ): ParsedLocation => { - const fromMatches = dest._fromLocation - ? this.matchRoutes(dest._fromLocation, { _buildLocation: true }) - : this.state.matches - - const fromMatch = - dest.from != null - ? fromMatches.find((d) => - matchPathname(this.basepath, trimPathRight(d.pathname), { - to: dest.from, - caseSensitive: false, - fuzzy: false, - }), - ) - : undefined + // We allow the caller to override the current location + const currentLocation = dest._fromLocation || this.latestLocation - const fromPath = fromMatch?.pathname || this.latestLocation.pathname - - invariant( - dest.from == null || fromMatch != null, - 'Could not find match for from: ' + dest.from, - ) + const allFromMatches = this.matchRoutes(currentLocation, { + _buildLocation: true, + }) - const fromSearch = this.state.pendingMatches?.length - ? last(this.state.pendingMatches)?.search - : last(fromMatches)?.search || this.latestLocation.search + const lastMatch = last(allFromMatches)! + + // First let's find the starting pathname + // By default, start with the current location + let fromPath = lastMatch.fullPath + + // If there is a to, it means we are changing the path in some way + // So we need to find the relative fromPath + if (dest.unsafeRelative === 'path') { + fromPath = currentLocation.pathname + } else if (dest.to && dest.from) { + fromPath = dest.from + const existingFrom = [...allFromMatches].reverse().find((d) => { + return ( + d.fullPath === fromPath || d.fullPath === joinPaths([fromPath, '/']) + ) + }) - const stayingMatches = matchedRoutesResult?.matchedRoutes.filter((d) => - fromMatches.find((e) => e.routeId === d.id), - ) - let pathname: string - if (dest.to) { - const resolvePathTo = - fromMatch?.fullPath || - last(fromMatches)?.fullPath || - this.latestLocation.pathname - pathname = this.resolvePathWithBase(resolvePathTo, `${dest.to}`) - } else { - const fromRouteByFromPathRouteId = - this.routesById[ - stayingMatches?.find((route) => { - const interpolatedPath = interpolatePath({ - path: route.fullPath, - params: matchedRoutesResult?.routeParams ?? {}, - decodeCharMap: this.pathParamsDecodeCharMap, - }).interpolatedPath - const pathname = joinPaths([this.basepath, interpolatedPath]) - return pathname === fromPath - })?.id as keyof this['routesById'] - ] - pathname = this.resolvePathWithBase( - fromPath, - fromRouteByFromPathRouteId?.to ?? fromPath, - ) + if (!existingFrom) { + console.warn(`Could not find match for from: ${dest.from}`) + } } - const prevParams = { ...last(fromMatches)?.params } + // From search should always use the current location + const fromSearch = lastMatch.search + // Same with params. It can't hurt to provide as many as possible + const fromParams = { ...lastMatch.params } + + // Resolve the next to + const nextTo = dest.to + ? this.resolvePathWithBase(fromPath, `${dest.to}`) + : fromPath + // Resolve the next params let nextParams = (dest.params ?? true) === true - ? prevParams + ? fromParams : { - ...prevParams, - ...functionalUpdate(dest.params as any, prevParams), + ...fromParams, + ...functionalUpdate(dest.params as any, fromParams), } + const destRoutes = this.matchRoutes( + nextTo, + {}, + { + _buildLocation: true, + }, + ).map((d) => this.looseRoutesById[d.routeId]!) + + // If there are any params, we need to stringify them if (Object.keys(nextParams).length > 0) { - matchedRoutesResult?.matchedRoutes + destRoutes .map((route) => { return ( route.options.params?.stringify ?? route.options.stringifyParams @@ -1615,25 +1472,27 @@ export class RouterCore< }) } - pathname = interpolatePath({ - path: pathname, + // Interpolate the next to into the next pathname + const nextPathname = interpolatePath({ + path: nextTo, params: nextParams ?? {}, leaveWildcards: false, leaveParams: opts.leaveParams, decodeCharMap: this.pathParamsDecodeCharMap, }).interpolatedPath - let search = fromSearch + // Resolve the next search + let nextSearch = fromSearch if (opts._includeValidateSearch && this.options.search?.strict) { let validatedSearch = {} - matchedRoutesResult?.matchedRoutes.forEach((route) => { + destRoutes.forEach((route) => { try { if (route.options.validateSearch) { validatedSearch = { ...validatedSearch, ...(validateSearch(route.options.validateSearch, { ...validatedSearch, - ...search, + ...nextSearch, }) ?? {}), } } @@ -1641,137 +1500,52 @@ export class RouterCore< // ignore errors here because they are already handled in matchRoutes } }) - search = validatedSearch + nextSearch = validatedSearch } - const applyMiddlewares = (search: any) => { - const allMiddlewares = - matchedRoutesResult?.matchedRoutes.reduce( - (acc, route) => { - const middlewares: Array> = [] - if ('search' in route.options) { - if (route.options.search?.middlewares) { - middlewares.push(...route.options.search.middlewares) - } - } - // TODO remove preSearchFilters and postSearchFilters in v2 - else if ( - route.options.preSearchFilters || - route.options.postSearchFilters - ) { - const legacyMiddleware: SearchMiddleware = ({ - search, - next, - }) => { - let nextSearch = search - if ( - 'preSearchFilters' in route.options && - route.options.preSearchFilters - ) { - nextSearch = route.options.preSearchFilters.reduce( - (prev, next) => next(prev), - search, - ) - } - const result = next(nextSearch) - if ( - 'postSearchFilters' in route.options && - route.options.postSearchFilters - ) { - return route.options.postSearchFilters.reduce( - (prev, next) => next(prev), - result, - ) - } - return result - } - middlewares.push(legacyMiddleware) - } - if (opts._includeValidateSearch && route.options.validateSearch) { - const validate: SearchMiddleware = ({ search, next }) => { - const result = next(search) - try { - const validatedSearch = { - ...result, - ...(validateSearch( - route.options.validateSearch, - result, - ) ?? {}), - } - return validatedSearch - } catch { - // ignore errors here because they are already handled in matchRoutes - return result - } - } - middlewares.push(validate) - } - return acc.concat(middlewares) - }, - [] as Array>, - ) ?? [] - - // the chain ends here since `next` is not called - const final: SearchMiddleware = ({ search }) => { - if (!dest.search) { - return {} - } - if (dest.search === true) { - return search - } - return functionalUpdate(dest.search, search) - } - allMiddlewares.push(final) - - const applyNext = (index: number, currentSearch: any): any => { - // no more middlewares left, return the current search - if (index >= allMiddlewares.length) { - return currentSearch - } - - const middleware = allMiddlewares[index]! - - const next = (newSearch: any): any => { - return applyNext(index + 1, newSearch) - } - - return middleware({ search: currentSearch, next }) - } - - // Start applying middlewares - return applyNext(0, search) - } + nextSearch = applySearchMiddleware({ + search: nextSearch, + dest, + destRoutes, + _includeValidateSearch: opts._includeValidateSearch, + }) - search = applyMiddlewares(search) + // Replace the equal deep + nextSearch = replaceEqualDeep(fromSearch, nextSearch) - search = replaceEqualDeep(fromSearch, search) - const searchStr = this.options.stringifySearch(search) + // Stringify the next search + const searchStr = this.options.stringifySearch(nextSearch) + // Resolve the next hash const hash = dest.hash === true - ? this.latestLocation.hash + ? currentLocation.hash : dest.hash - ? functionalUpdate(dest.hash, this.latestLocation.hash) + ? functionalUpdate(dest.hash, currentLocation.hash) : undefined + // Resolve the next hash string const hashStr = hash ? `#${hash}` : '' + // Resolve the next state let nextState = dest.state === true - ? this.latestLocation.state + ? currentLocation.state : dest.state - ? functionalUpdate(dest.state, this.latestLocation.state) + ? functionalUpdate(dest.state, currentLocation.state) : {} - nextState = replaceEqualDeep(this.latestLocation.state, nextState) + // Replace the equal deep + nextState = replaceEqualDeep(currentLocation.state, nextState) + // Return the next location return { - pathname, - search, + pathname: nextPathname, + search: nextSearch, searchStr, state: nextState as any, hash: hash ?? '', - href: `${pathname}${searchStr}${hashStr}`, + href: `${nextPathname}${searchStr}${hashStr}`, unmaskOnReload: dest.unmaskOnReload, } } @@ -1781,6 +1555,7 @@ export class RouterCore< maskedDest?: BuildNextOptions, ) => { const next = build(dest) + let maskedNext = maskedDest ? build(maskedDest) : undefined if (!maskedNext) { @@ -1812,16 +1587,12 @@ export class RouterCore< } } - const nextMatches = this.getMatchedRoutes(next, dest) - const final = build(dest, nextMatches) - if (maskedNext) { - const maskedMatches = this.getMatchedRoutes(maskedNext, maskedDest) - const maskedFinal = build(maskedDest, maskedMatches) - final.maskedLocation = maskedFinal + const maskedFinal = build(maskedDest) + next.maskedLocation = maskedFinal } - return final + return next } if (opts.mask) { @@ -1958,6 +1729,13 @@ export class RouterCore< } navigate: NavigateFn = ({ to, reloadDocument, href, ...rest }) => { + if (!reloadDocument && href) { + try { + new URL(`${href}`) + reloadDocument = true + } catch {} + } + if (reloadDocument) { if (!href) { const location = this.buildLocation({ to, ...rest } as any) @@ -1980,10 +1758,30 @@ export class RouterCore< latestLoadPromise: undefined | Promise - load: LoadFn = async (opts?: { sync?: boolean }): Promise => { + beforeLoad = () => { + // Cancel any pending matches + this.cancelMatches() this.latestLocation = this.parseLocation(this.latestLocation) - let redirect: ResolvedRedirect | undefined + // Match the routes + const pendingMatches = this.matchRoutes(this.latestLocation) + + // Ingest the new matches + this.__store.setState((s) => ({ + ...s, + status: 'pending', + isLoading: true, + location: this.latestLocation, + pendingMatches, + // If a cached moved to pendingMatches, remove it from cachedMatches + cachedMatches: s.cachedMatches.filter((d) => { + return !pendingMatches.find((e) => e.id === d.id) + }), + })) + } + + load: LoadFn = async (opts?: { sync?: boolean }): Promise => { + let redirect: AnyRedirect | undefined let notFound: NotFoundError | undefined let loadPromise: Promise @@ -1992,36 +1790,10 @@ export class RouterCore< loadPromise = new Promise((resolve) => { this.startTransition(async () => { try { + this.beforeLoad() const next = this.latestLocation const prevLocation = this.state.resolvedLocation - // Cancel any pending matches - this.cancelMatches() - - let pendingMatches!: Array - - batch(() => { - // this call breaks a route context of destination route after a redirect - // we should be fine not eagerly calling this since we call it later - // this.clearExpiredCache() - - // Match the routes - pendingMatches = this.matchRoutes(next) - - // Ingest the new matches - this.__store.setState((s) => ({ - ...s, - status: 'pending', - isLoading: true, - location: next, - pendingMatches, - // If a cached moved to pendingMatches, remove it from cachedMatches - cachedMatches: s.cachedMatches.filter((d) => { - return !pendingMatches.find((e) => e.id === d.id) - }), - })) - }) - if (!this.state.redirect) { this.emit({ type: 'onBeforeNavigate', @@ -2042,7 +1814,7 @@ export class RouterCore< await this.loadMatches({ sync: opts?.sync, - matches: pendingMatches, + matches: this.state.pendingMatches as Array, location: next, // eslint-disable-next-line @typescript-eslint/require-await onReady: async () => { @@ -2103,11 +1875,11 @@ export class RouterCore< }, }) } catch (err) { - if (isResolvedRedirect(err)) { + if (isRedirect(err)) { redirect = err if (!this.isServer) { this.navigate({ - ...redirect, + ...redirect.options, replace: true, ignoreBlocker: true, }) @@ -2119,7 +1891,7 @@ export class RouterCore< this.__store.setState((s) => ({ ...s, statusCode: redirect - ? redirect.statusCode + ? redirect.status : notFound ? 404 : s.matches.some((d) => d.status === 'error') @@ -2275,13 +2047,15 @@ export class RouterCore< } const handleRedirectAndNotFound = (match: AnyRouteMatch, err: any) => { - if (isResolvedRedirect(err)) { - if (!err.reloadDocument) { - throw err + if (isRedirect(err) || isNotFound(err)) { + if (isRedirect(err)) { + if (err.redirectHandled) { + if (!err.options.reloadDocument) { + throw err + } + } } - } - if (isRedirect(err) || isNotFound(err)) { updateMatch(match.id, (prev) => ({ ...prev, status: isRedirect(err) @@ -2305,7 +2079,9 @@ export class RouterCore< if (isRedirect(err)) { rendered = true - err = this.resolveRedirect({ ...err, _fromLocation: location }) + err.options._fromLocation = location + err.redirectHandled = true + err = this.resolveRedirect(err) throw err } else if (isNotFound(err)) { this._handleNotFound(matches, err, { @@ -2609,6 +2385,31 @@ export class RouterCore< !this.state.matches.find((d) => d.id === matchId), })) + const executeHead = async () => { + const match = this.getMatch(matchId) + // in case of a redirecting match during preload, the match does not exist + if (!match) { + return + } + const assetContext = { + matches, + match, + params: match.params, + loaderData: match.loaderData, + } + const headFnContent = + await route.options.head?.(assetContext) + const meta = headFnContent?.meta + const links = headFnContent?.links + const headScripts = headFnContent?.scripts + + const scripts = + await route.options.scripts?.(assetContext) + const headers = + await route.options.headers?.(assetContext) + return { meta, links, headScripts, headers, scripts } + } + const runLoader = async () => { try { // If the Matches component rendered @@ -2649,23 +2450,6 @@ export class RouterCore< await potentialPendingMinPromise() - const assetContext = { - matches, - match: this.getMatch(matchId)!, - params: this.getMatch(matchId)!.params, - loaderData, - } - const headFnContent = - route.options.head?.(assetContext) - const meta = headFnContent?.meta - const links = headFnContent?.links - const headScripts = headFnContent?.scripts - - const scripts = route.options.scripts?.(assetContext) - const headers = route.options.headers?.({ - loaderData, - }) - // Last but not least, wait for the the components // to be preloaded before we resolve the match await route._componentsPromise @@ -2677,11 +2461,11 @@ export class RouterCore< isFetching: false, updatedAt: Date.now(), loaderData, - meta, - links, - headScripts, - headers, - scripts, + })) + const head = await executeHead() + updateMatch(matchId, (prev) => ({ + ...prev, + ...head, })) } catch (e) { let error = e @@ -2699,12 +2483,13 @@ export class RouterCore< onErrorError, ) } - + const head = await executeHead() updateMatch(matchId, (prev) => ({ ...prev, error, status: 'error', isFetching: false, + ...head, })) } @@ -2713,9 +2498,12 @@ export class RouterCore< match: this.getMatch(matchId)!, }) } catch (err) { + const head = await executeHead() + updateMatch(matchId, (prev) => ({ ...prev, loaderPromise: undefined, + ...head, })) handleRedirectAndNotFound(this.getMatch(matchId)!, err) } @@ -2742,8 +2530,8 @@ export class RouterCore< loaderPromise: undefined, })) } catch (err) { - if (isResolvedRedirect(err)) { - await this.navigate(err) + if (isRedirect(err)) { + await this.navigate(err.options) } } })() @@ -2752,6 +2540,15 @@ export class RouterCore< (loaderShouldRunAsync && sync) ) { await runLoader() + } else { + // if the loader did not run, still update head. + // reason: parent's beforeLoad may have changed the route context + // and only now do we know the route context (and that the loader would not run) + const head = await executeHead() + updateMatch(matchId, (prev) => ({ + ...prev, + ...head, + })) } } if (!loaderIsRunningAsync) { @@ -2828,11 +2625,14 @@ export class RouterCore< return this.load({ sync: opts?.sync }) } - resolveRedirect = (err: AnyRedirect): ResolvedRedirect => { - const redirect = err as ResolvedRedirect + resolveRedirect = (redirect: AnyRedirect): AnyRedirect => { + if (!redirect.options.href) { + redirect.options.href = this.buildLocation(redirect.options).href + redirect.headers.set('Location', redirect.options.href) + } - if (!redirect.href) { - redirect.href = this.buildLocation(redirect as any).href + if (!redirect.headers.get('Location')) { + redirect.headers.set('Location', redirect.options.href) } return redirect @@ -2967,11 +2767,12 @@ export class RouterCore< return matches } catch (err) { if (isRedirect(err)) { - if (err.reloadDocument) { + if (err.options.reloadDocument) { return undefined } + return await this.preloadRoute({ - ...(err as any), + ...err.options, _fromLocation: next, }) } @@ -3205,3 +3006,338 @@ function routeNeedsPreload(route: AnyRoute) { } return false } + +interface RouteLike { + id: string + isRoot?: boolean + path?: string + fullPath: string + rank?: number + parentRoute?: RouteLike + children?: Array + options?: { + caseSensitive?: boolean + } +} + +export function processRouteTree({ + routeTree, + initRoute, +}: { + routeTree: TRouteLike + initRoute?: (route: TRouteLike, index: number) => void +}) { + const routesById = {} as Record + const routesByPath = {} as Record + + const recurseRoutes = (childRoutes: Array) => { + childRoutes.forEach((childRoute, i) => { + initRoute?.(childRoute, i) + + const existingRoute = routesById[childRoute.id] + + invariant( + !existingRoute, + `Duplicate routes found with id: ${String(childRoute.id)}`, + ) + + routesById[childRoute.id] = childRoute + + if (!childRoute.isRoot && childRoute.path) { + const trimmedFullPath = trimPathRight(childRoute.fullPath) + if ( + !routesByPath[trimmedFullPath] || + childRoute.fullPath.endsWith('/') + ) { + routesByPath[trimmedFullPath] = childRoute + } + } + + const children = childRoute.children as Array + + if (children?.length) { + recurseRoutes(children) + } + }) + } + + recurseRoutes([routeTree]) + + const scoredRoutes: Array<{ + child: TRouteLike + trimmed: string + parsed: ReturnType + index: number + scores: Array + }> = [] + + const routes: Array = Object.values(routesById) + + routes.forEach((d, i) => { + if (d.isRoot || !d.path) { + return + } + + const trimmed = trimPathLeft(d.fullPath) + const parsed = parsePathname(trimmed) + + // Removes the leading slash if it is not the only remaining segment + while (parsed.length > 1 && parsed[0]?.value === '/') { + parsed.shift() + } + + const scores = parsed.map((segment) => { + if (segment.value === '/') { + return 0.75 + } + + if ( + segment.type === 'param' && + segment.prefixSegment && + segment.suffixSegment + ) { + return 0.55 + } + + if (segment.type === 'param' && segment.prefixSegment) { + return 0.52 + } + + if (segment.type === 'param' && segment.suffixSegment) { + return 0.51 + } + + if (segment.type === 'param') { + return 0.5 + } + + if ( + segment.type === 'wildcard' && + segment.prefixSegment && + segment.suffixSegment + ) { + return 0.3 + } + + if (segment.type === 'wildcard' && segment.prefixSegment) { + return 0.27 + } + + if (segment.type === 'wildcard' && segment.suffixSegment) { + return 0.26 + } + + if (segment.type === 'wildcard') { + return 0.25 + } + + return 1 + }) + + scoredRoutes.push({ child: d, trimmed, parsed, index: i, scores }) + }) + + const flatRoutes = scoredRoutes + .sort((a, b) => { + const minLength = Math.min(a.scores.length, b.scores.length) + + // Sort by min available score + for (let i = 0; i < minLength; i++) { + if (a.scores[i] !== b.scores[i]) { + return b.scores[i]! - a.scores[i]! + } + } + + // Sort by length of score + if (a.scores.length !== b.scores.length) { + return b.scores.length - a.scores.length + } + + // Sort by min available parsed value + for (let i = 0; i < minLength; i++) { + if (a.parsed[i]!.value !== b.parsed[i]!.value) { + return a.parsed[i]!.value > b.parsed[i]!.value ? 1 : -1 + } + } + + // Sort by original index + return a.index - b.index + }) + .map((d, i) => { + d.child.rank = i + return d.child + }) + + return { routesById, routesByPath, flatRoutes } +} + +export function getMatchedRoutes({ + pathname, + routePathname, + basepath, + caseSensitive, + routesByPath, + routesById, + flatRoutes, +}: { + pathname: string + routePathname?: string + basepath: string + caseSensitive?: boolean + routesByPath: Record + routesById: Record + flatRoutes: Array +}) { + let routeParams: Record = {} + const trimmedPath = trimPathRight(pathname) + const getMatchedParams = (route: TRouteLike) => { + const result = matchPathname(basepath, trimmedPath, { + to: route.fullPath, + caseSensitive: route.options?.caseSensitive ?? caseSensitive, + fuzzy: true, + }) + return result + } + + let foundRoute: TRouteLike | undefined = + routePathname !== undefined ? routesByPath[routePathname] : undefined + if (foundRoute) { + routeParams = getMatchedParams(foundRoute)! + } else { + foundRoute = flatRoutes.find((route) => { + const matchedParams = getMatchedParams(route) + + if (matchedParams) { + routeParams = matchedParams + return true + } + + return false + }) + } + + let routeCursor: TRouteLike = foundRoute || routesById[rootRouteId]! + + const matchedRoutes: Array = [routeCursor] + + while (routeCursor.parentRoute) { + routeCursor = routeCursor.parentRoute as TRouteLike + matchedRoutes.unshift(routeCursor) + } + + return { matchedRoutes, routeParams, foundRoute } +} + +function applySearchMiddleware({ + search, + dest, + destRoutes, + _includeValidateSearch, +}: { + search: any + dest: BuildNextOptions + destRoutes: Array + _includeValidateSearch: boolean | undefined +}) { + const allMiddlewares = + destRoutes.reduce( + (acc, route) => { + const middlewares: Array> = [] + + if ('search' in route.options) { + if (route.options.search?.middlewares) { + middlewares.push(...route.options.search.middlewares) + } + } + // TODO remove preSearchFilters and postSearchFilters in v2 + else if ( + route.options.preSearchFilters || + route.options.postSearchFilters + ) { + const legacyMiddleware: SearchMiddleware = ({ + search, + next, + }) => { + let nextSearch = search + + if ( + 'preSearchFilters' in route.options && + route.options.preSearchFilters + ) { + nextSearch = route.options.preSearchFilters.reduce( + (prev, next) => next(prev), + search, + ) + } + + const result = next(nextSearch) + + if ( + 'postSearchFilters' in route.options && + route.options.postSearchFilters + ) { + return route.options.postSearchFilters.reduce( + (prev, next) => next(prev), + result, + ) + } + + return result + } + middlewares.push(legacyMiddleware) + } + + if (_includeValidateSearch && route.options.validateSearch) { + const validate: SearchMiddleware = ({ search, next }) => { + const result = next(search) + try { + const validatedSearch = { + ...result, + ...(validateSearch(route.options.validateSearch, result) ?? {}), + } + return validatedSearch + } catch { + // ignore errors here because they are already handled in matchRoutes + return result + } + } + + middlewares.push(validate) + } + + return acc.concat(middlewares) + }, + [] as Array>, + ) ?? [] + + // the chain ends here since `next` is not called + const final: SearchMiddleware = ({ search }) => { + if (!dest.search) { + return {} + } + if (dest.search === true) { + return search + } + return functionalUpdate(dest.search, search) + } + + allMiddlewares.push(final) + + const applyNext = (index: number, currentSearch: any): any => { + // no more middlewares left, return the current search + if (index >= allMiddlewares.length) { + return currentSearch + } + + const middleware = allMiddlewares[index]! + + const next = (newSearch: any): any => { + return applyNext(index + 1, newSearch) + } + + return middleware({ search: currentSearch, next }) + } + + // Start applying middlewares + return applyNext(0, search) +} diff --git a/packages/router-core/src/scroll-restoration.ts b/packages/router-core/src/scroll-restoration.ts index 7efa94a908..1e3270534f 100644 --- a/packages/router-core/src/scroll-restoration.ts +++ b/packages/router-core/src/scroll-restoration.ts @@ -18,12 +18,22 @@ export type ScrollRestorationOptions = { scrollBehavior?: ScrollToOptions['behavior'] } +function getSafeSessionStorage() { + try { + if ( + typeof window !== 'undefined' && + typeof window.sessionStorage === 'object' + ) { + return window.sessionStorage + } + } catch { + return undefined + } + return undefined +} + export const storageKey = 'tsr-scroll-restoration-v1_3' -let sessionsStorage = false -try { - sessionsStorage = - typeof window !== 'undefined' && typeof window.sessionStorage === 'object' -} catch {} + const throttle = (fn: (...args: Array) => void, wait: number) => { let timeout: any return (...args: Array) => { @@ -35,28 +45,32 @@ const throttle = (fn: (...args: Array) => void, wait: number) => { } } } -export const scrollRestorationCache: ScrollRestorationCache = sessionsStorage - ? (() => { - const state: ScrollRestorationByKey = - JSON.parse(window.sessionStorage.getItem(storageKey) || 'null') || {} - - return { - state, - // This setter is simply to make sure that we set the sessionStorage right - // after the state is updated. It doesn't necessarily need to be a functional - // update. - set: (updater) => ( - (scrollRestorationCache.state = - functionalUpdate(updater, scrollRestorationCache.state) || - scrollRestorationCache.state), - window.sessionStorage.setItem( - storageKey, - JSON.stringify(scrollRestorationCache.state), - ) - ), - } - })() - : (undefined as any) + +function createScrollRestorationCache(): ScrollRestorationCache | undefined { + const safeSessionStorage = getSafeSessionStorage() + if (!safeSessionStorage) { + return undefined + } + + const persistedState = safeSessionStorage.getItem(storageKey) + let state: ScrollRestorationByKey = persistedState + ? JSON.parse(persistedState) + : {} + + return { + state, + // This setter is simply to make sure that we set the sessionStorage right + // after the state is updated. It doesn't necessarily need to be a functional + // update. + set: (updater) => ( + (state = functionalUpdate(updater, state) || state), + safeSessionStorage.setItem(storageKey, JSON.stringify(state)) + ), + } +} + +export const scrollRestorationCache = createScrollRestorationCache() + /** * The default `getKey` function for `useScrollRestoration`. * It returns the `key` from the location state or the `href` of the location. @@ -176,6 +190,9 @@ export function restoreScroll( } export function setupScrollRestoration(router: AnyRouter, force?: boolean) { + if (scrollRestorationCache === undefined) { + return + } const shouldScrollRestoration = force ?? router.options.scrollRestoration ?? false diff --git a/packages/router-core/src/typePrimitives.ts b/packages/router-core/src/typePrimitives.ts index f0c5d2ae9f..ebc80ed732 100644 --- a/packages/router-core/src/typePrimitives.ts +++ b/packages/router-core/src/typePrimitives.ts @@ -5,7 +5,7 @@ import type { SearchParamOptions, ToPathOption, } from './link' -import type { Redirect } from './redirect' +import type { RedirectOptions } from './redirect' import type { RouteIds } from './routeInfo' import type { AnyRouter, RegisteredRouter } from './router' import type { UseParamsResult } from './useParams' @@ -104,7 +104,7 @@ export type ValidateRedirectOptions< TDefaultFrom extends string = string, > = Constrain< TOptions, - Redirect< + RedirectOptions< TRouter, InferFrom, InferTo, diff --git a/packages/router-core/src/utils.ts b/packages/router-core/src/utils.ts index 1df674e8b9..5a9c1ba71a 100644 --- a/packages/router-core/src/utils.ts +++ b/packages/router-core/src/utils.ts @@ -1,6 +1,7 @@ import type { RouteIds } from './routeInfo' import type { AnyRouter } from './router' +export type Awaitable = T | Promise export type NoInfer = [T][T extends any ? 0 : never] export type IsAny = 1 extends 0 & TValue ? TYesResult @@ -169,6 +170,20 @@ export type ValidateJSON = ((...args: Array) => any) extends T : 'Function is not serializable' : { [K in keyof T]: ValidateJSON } +export type LooseReturnType = T extends ( + ...args: Array +) => infer TReturn + ? TReturn + : never + +export type LooseAsyncReturnType = T extends ( + ...args: Array +) => infer TReturn + ? TReturn extends Promise + ? TReturn + : TReturn + : never + export function last(arr: Array) { return arr[arr.length - 1] } diff --git a/packages/router-core/tests/path.test.ts b/packages/router-core/tests/path.test.ts index 0b709d2453..8d9ff4ad7e 100644 --- a/packages/router-core/tests/path.test.ts +++ b/packages/router-core/tests/path.test.ts @@ -3,10 +3,13 @@ import { exactPathTest, interpolatePath, matchPathname, + parsePathname, removeBasepath, removeTrailingSlash, resolvePath, + trimPathLeft, } from '../src/path' +import type { Segment as PathSegment } from '../src/path' describe('removeBasepath', () => { it.each([ @@ -263,110 +266,261 @@ describe('resolvePath', () => { }) }) }) + + describe.each([{ base: '/' }, { base: '/nested' }])( + 'param routes w/ base=$base', + ({ base }) => { + describe('wildcard (prefix + suffix)', () => { + it.each([ + { name: 'regular top-level', to: '/$' }, + { name: 'regular nested', to: '/params/wildcard/$' }, + { name: 'with top-level prefix', to: '/prefix{$}' }, + { name: 'with nested prefix', to: '/params/wildcard/prefix{$}' }, + { name: 'with top-level suffix', to: '/{$}suffix' }, + { name: 'with nested suffix', to: '/params/wildcard/{$}suffix' }, + { + name: 'with top-level prefix + suffix', + to: '/prefix{$}suffix', + }, + { + name: 'with nested prefix + suffix', + to: '/params/wildcard/prefix{$}suffix', + }, + ])('$name', ({ to }) => { + const candidate = base + trimPathLeft(to) + expect( + resolvePath({ + basepath: '/', + base, + to: candidate, + trailingSlash: 'never', + caseSensitive: false, + }), + ).toEqual(candidate) + }) + }) + + describe('named (prefix + suffix)', () => { + it.each([ + { name: 'regular top-level', to: '/$foo' }, + { name: 'regular nested', to: '/params/named/$foo' }, + { name: 'with top-level prefix', to: '/prefix{$foo}' }, + { name: 'with nested prefix', to: '/params/named/prefix{$foo}' }, + { name: 'with top-level suffix', to: '/{$foo}suffix' }, + { name: 'with nested suffix', to: '/params/named/{$foo}suffix' }, + { + name: 'with top-level prefix + suffix', + to: '/prefix{$foo}suffix', + }, + { + name: 'with nested prefix + suffix', + to: '/params/named/prefix{$foo}suffix', + }, + ])('$name', ({ to }) => { + const candidate = base + trimPathLeft(to) + expect( + resolvePath({ + basepath: '/', + base, + to: candidate, + trailingSlash: 'never', + caseSensitive: false, + }), + ).toEqual(candidate) + }) + }) + }, + ) }) describe('interpolatePath', () => { - it.each([ - { - name: 'should interpolate the path', - path: '/users/$id', - params: { id: '123' }, - result: '/users/123', - }, - { - name: 'should interpolate the path with multiple params', - path: '/users/$id/$name', - params: { id: '123', name: 'tanner' }, - result: '/users/123/tanner', - }, - { - name: 'should interpolate the path with extra params', - path: '/users/$id', - params: { id: '123', name: 'tanner' }, - result: '/users/123', - }, - { - name: 'should interpolate the path with missing params', - path: '/users/$id/$name', - params: { id: '123' }, - result: '/users/123/undefined', - }, - { - name: 'should interpolate the path with missing params and extra params', - path: '/users/$id', - params: { name: 'john' }, - result: '/users/undefined', - }, - { - name: 'should interpolate the path with the param being a number', - path: '/users/$id', - params: { id: 123 }, - result: '/users/123', - }, - { - name: 'should interpolate the path with the param being a falsey number', - path: '/users/$id', - params: { id: 0 }, - result: '/users/0', - }, - { - name: 'should interpolate the path with URI component encoding', - path: '/users/$id', - params: { id: '?#@john+smith' }, - result: '/users/%3F%23%40john%2Bsmith', - }, - { - name: 'should interpolate the path without URI encoding characters in decodeCharMap', - path: '/users/$id', - params: { id: '?#@john+smith' }, - result: '/users/%3F%23@john+smith', - decodeCharMap: new Map( - ['@', '+'].map((char) => [encodeURIComponent(char), char]), - ), - }, - { - name: 'should interpolate the path with the splat param at the end', - path: '/users/$', - params: { _splat: '123' }, - result: '/users/123', - }, - { - name: 'should interpolate the path with a single named path param and the splat param at the end', - path: '/users/$username/$', - params: { username: 'seancassiere', _splat: '123' }, - result: '/users/seancassiere/123', - }, - { - name: 'should interpolate the path with 2 named path params with the splat param at the end', - path: '/users/$username/$id/$', - params: { username: 'seancassiere', id: '123', _splat: '456' }, - result: '/users/seancassiere/123/456', - }, - { - name: 'should interpolate the path with multiple named path params with the splat param at the end', - path: '/$username/settings/$repo/$id/$', - params: { - username: 'sean-cassiere', - repo: 'my-repo', - id: '123', - _splat: '456', - }, - result: '/sean-cassiere/settings/my-repo/123/456', - }, - { - name: 'should interpolate the path with the splat param containing slashes', - path: '/users/$', - params: { _splat: 'sean/cassiere' }, - result: '/users/sean/cassiere', - }, - ])('$name', ({ path, params, decodeCharMap, result }) => { - expect( - interpolatePath({ - path, - params, - decodeCharMap, - }).interpolatedPath, - ).toBe(result) + describe('regular usage', () => { + it.each([ + { + name: 'should interpolate the path', + path: '/users/$id', + params: { id: '123' }, + result: '/users/123', + }, + { + name: 'should interpolate the path with multiple params', + path: '/users/$id/$name', + params: { id: '123', name: 'tanner' }, + result: '/users/123/tanner', + }, + { + name: 'should interpolate the path with extra params', + path: '/users/$id', + params: { id: '123', name: 'tanner' }, + result: '/users/123', + }, + { + name: 'should interpolate the path with missing params', + path: '/users/$id/$name', + params: { id: '123' }, + result: '/users/123/undefined', + }, + { + name: 'should interpolate the path with missing params and extra params', + path: '/users/$id', + params: { name: 'john' }, + result: '/users/undefined', + }, + { + name: 'should interpolate the path with the param being a number', + path: '/users/$id', + params: { id: 123 }, + result: '/users/123', + }, + { + name: 'should interpolate the path with the param being a falsey number', + path: '/users/$id', + params: { id: 0 }, + result: '/users/0', + }, + { + name: 'should interpolate the path with URI component encoding', + path: '/users/$id', + params: { id: '?#@john+smith' }, + result: '/users/%3F%23%40john%2Bsmith', + }, + { + name: 'should interpolate the path without URI encoding characters in decodeCharMap', + path: '/users/$id', + params: { id: '?#@john+smith' }, + result: '/users/%3F%23@john+smith', + decodeCharMap: new Map( + ['@', '+'].map((char) => [encodeURIComponent(char), char]), + ), + }, + { + name: 'should interpolate the path with the splat param at the end', + path: '/users/$', + params: { _splat: '123' }, + result: '/users/123', + }, + { + name: 'should interpolate the path with a single named path param and the splat param at the end', + path: '/users/$username/$', + params: { username: 'seancassiere', _splat: '123' }, + result: '/users/seancassiere/123', + }, + { + name: 'should interpolate the path with 2 named path params with the splat param at the end', + path: '/users/$username/$id/$', + params: { username: 'seancassiere', id: '123', _splat: '456' }, + result: '/users/seancassiere/123/456', + }, + { + name: 'should interpolate the path with multiple named path params with the splat param at the end', + path: '/$username/settings/$repo/$id/$', + params: { + username: 'sean-cassiere', + repo: 'my-repo', + id: '123', + _splat: '456', + }, + result: '/sean-cassiere/settings/my-repo/123/456', + }, + { + name: 'should interpolate the path with the splat param containing slashes', + path: '/users/$', + params: { _splat: 'sean/cassiere' }, + result: '/users/sean/cassiere', + }, + ])('$name', ({ path, params, decodeCharMap, result }) => { + expect( + interpolatePath({ + path, + params, + decodeCharMap, + }).interpolatedPath, + ).toBe(result) + }) + }) + + describe('wildcard (prefix + suffix)', () => { + it.each([ + { + name: 'regular', + to: '/$', + params: { _splat: 'bar/foo/me' }, + result: '/bar/foo/me', + }, + { + name: 'regular curly braces', + to: '/{$}', + params: { _splat: 'bar/foo/me' }, + result: '/bar/foo/me', + }, + { + name: 'with prefix', + to: '/prefix{$}', + params: { _splat: 'bar' }, + result: '/prefixbar', + }, + { + name: 'with suffix', + to: '/{$}-suffix', + params: { _splat: 'bar' }, + result: '/bar-suffix', + }, + { + name: 'with prefix + suffix', + to: '/prefix{$}-suffix', + params: { _splat: 'bar' }, + result: '/prefixbar-suffix', + }, + ])('$name', ({ to, params, result }) => { + expect( + interpolatePath({ + path: to, + params, + }).interpolatedPath, + ).toBe(result) + }) + }) + + describe('named params (prefix + suffix', () => { + it.each([ + { + name: 'regular', + to: '/$foo', + params: { foo: 'bar' }, + result: '/bar', + }, + { + name: 'regular curly braces', + to: '/{$foo}', + params: { foo: 'bar' }, + result: '/bar', + }, + { + name: 'with prefix', + to: '/prefix{$bar}', + params: { bar: 'baz' }, + result: '/prefixbaz', + }, + { + name: 'with suffix', + to: '/{$foo}.suffix', + params: { foo: 'bar' }, + result: '/bar.suffix', + }, + { + name: 'with prefix and suffix', + to: '/prefix{$param}.suffix', + params: { param: 'foobar' }, + result: '/prefixfoobar.suffix', + }, + ])('$name', ({ to, params, result }) => { + expect( + interpolatePath({ + path: to, + params, + }).interpolatedPath, + ).toBe(result) + }) }) }) @@ -491,10 +645,442 @@ describe('matchPathname', () => { _splat: '456', }, }, + { + name: 'should match and return the splat params when multiple subsequent segments are present', + input: '/docs/tanner/sean/manuel', + matchingOptions: { + to: '/docs/$', + }, + expectedMatchedParams: { + '*': 'tanner/sean/manuel', + _splat: 'tanner/sean/manuel', + }, + }, + ])('$name', ({ input, matchingOptions, expectedMatchedParams }) => { + expect(matchPathname('/', input, matchingOptions)).toStrictEqual( + expectedMatchedParams, + ) + }) + }) + + describe('wildcard (prefix + suffix)', () => { + it.each([ + { + name: 'regular', + input: '/docs/foo/bar', + matchingOptions: { + to: '/docs/$', + }, + expectedMatchedParams: { + '*': 'foo/bar', + _splat: 'foo/bar', + }, + }, + { + name: 'regular curly braces', + input: '/docs/foo/bar', + matchingOptions: { + to: '/docs/{$}', + }, + expectedMatchedParams: { + '*': 'foo/bar', + _splat: 'foo/bar', + }, + }, + { + name: 'with prefix', + input: '/docs/prefixbar/baz', + matchingOptions: { + to: '/docs/prefix{$}', + }, + expectedMatchedParams: { + '*': 'bar/baz', + _splat: 'bar/baz', + }, + }, + { + name: 'with suffix', + input: '/docs/bar/baz.suffix', + matchingOptions: { + to: '/docs/{$}.suffix', + }, + expectedMatchedParams: { + '*': 'bar/baz', + _splat: 'bar/baz', + }, + }, + { + name: 'with prefix + suffix', + input: '/docs/prefixbar/baz-suffix', + matchingOptions: { + to: '/docs/prefix{$}-suffix', + }, + expectedMatchedParams: { + '*': 'bar/baz', + _splat: 'bar/baz', + }, + }, ])('$name', ({ input, matchingOptions, expectedMatchedParams }) => { expect(matchPathname('/', input, matchingOptions)).toStrictEqual( expectedMatchedParams, ) }) }) + + describe('named params (prefix + suffix)', () => { + it.each([ + { + name: 'regular', + input: '/docs/foo', + matchingOptions: { + to: '/docs/$bar', + }, + expectedMatchedParams: { + bar: 'foo', + }, + }, + { + name: 'regular curly braces', + input: '/docs/foo', + matchingOptions: { + to: '/docs/{$bar}', + }, + expectedMatchedParams: { + bar: 'foo', + }, + }, + { + name: 'with prefix', + input: '/docs/prefixfoo', + matchingOptions: { + to: '/docs/prefix{$bar}', + }, + expectedMatchedParams: { + bar: 'foo', + }, + }, + { + name: 'with suffix', + input: '/docs/foo.suffix', + matchingOptions: { + to: '/docs/{$bar}.suffix', + }, + expectedMatchedParams: { + bar: 'foo', + }, + }, + { + name: 'with prefix + suffix', + input: '/docs/prefixfoobar-suffix', + matchingOptions: { + to: '/docs/prefix{$param}-suffix', + }, + expectedMatchedParams: { + param: 'foobar', + }, + }, + ])('$name', ({ input, matchingOptions, expectedMatchedParams }) => { + expect(matchPathname('/', input, matchingOptions)).toStrictEqual( + expectedMatchedParams, + ) + }) + }) +}) + +describe('parsePathname', () => { + type ParsePathnameTestScheme = Array<{ + name: string + to: string | undefined + expected: Array + }> + + describe('regular usage', () => { + it.each([ + { + name: 'should handle pathname being undefined', + to: undefined, + expected: [], + }, + { + name: 'should handle pathname being empty', + to: '', + expected: [], + }, + { + name: 'should handle pathname at root', + to: '/', + expected: [{ type: 'pathname', value: '/' }], + }, + { + name: 'should handle pathname with a single segment', + to: '/foo', + expected: [ + { type: 'pathname', value: '/' }, + { type: 'pathname', value: 'foo' }, + ], + }, + { + name: 'should handle pathname with multiple segments', + to: '/foo/bar/baz', + expected: [ + { type: 'pathname', value: '/' }, + { type: 'pathname', value: 'foo' }, + { type: 'pathname', value: 'bar' }, + { type: 'pathname', value: 'baz' }, + ], + }, + { + name: 'should handle pathname with a trailing slash', + to: '/foo/', + expected: [ + { type: 'pathname', value: '/' }, + { type: 'pathname', value: 'foo' }, + { type: 'pathname', value: '/' }, + ], + }, + { + name: 'should handle named params', + to: '/foo/$bar', + expected: [ + { type: 'pathname', value: '/' }, + { type: 'pathname', value: 'foo' }, + { type: 'param', value: '$bar' }, + ], + }, + { + name: 'should handle named params at the root', + to: '/$bar', + expected: [ + { type: 'pathname', value: '/' }, + { type: 'param', value: '$bar' }, + ], + }, + { + name: 'should handle named params followed by a segment', + to: '/foo/$bar/baz', + expected: [ + { type: 'pathname', value: '/' }, + { type: 'pathname', value: 'foo' }, + { type: 'param', value: '$bar' }, + { type: 'pathname', value: 'baz' }, + ], + }, + { + name: 'should handle multiple named params', + to: '/foo/$bar/$baz/qux/$quux', + expected: [ + { type: 'pathname', value: '/' }, + { type: 'pathname', value: 'foo' }, + { type: 'param', value: '$bar' }, + { type: 'param', value: '$baz' }, + { type: 'pathname', value: 'qux' }, + { type: 'param', value: '$quux' }, + ], + }, + { + name: 'should handle splat params', + to: '/foo/$', + expected: [ + { type: 'pathname', value: '/' }, + { type: 'pathname', value: 'foo' }, + { type: 'wildcard', value: '$' }, + ], + }, + { + name: 'should handle splat params at the root', + to: '/$', + expected: [ + { type: 'pathname', value: '/' }, + { type: 'wildcard', value: '$' }, + ], + }, + ] satisfies ParsePathnameTestScheme)('$name', ({ to, expected }) => { + const result = parsePathname(to) + expect(result).toEqual(expected) + }) + }) + + describe('wildcard (prefix + suffix)', () => { + it.each([ + { + name: 'regular', + to: '/$', + expected: [ + { type: 'pathname', value: '/' }, + { type: 'wildcard', value: '$' }, + ], + }, + { + name: 'regular curly braces', + to: '/{$}', + expected: [ + { type: 'pathname', value: '/' }, + { type: 'wildcard', value: '$' }, + ], + }, + { + name: 'with prefix (regular text)', + to: '/foo{$}', + expected: [ + { type: 'pathname', value: '/' }, + { + type: 'wildcard', + value: '$', + prefixSegment: 'foo', + }, + ], + }, + { + name: 'with prefix + followed by special character', + to: '/foo.{$}', + expected: [ + { type: 'pathname', value: '/' }, + { + type: 'wildcard', + value: '$', + prefixSegment: 'foo.', + }, + ], + }, + { + name: 'with suffix', + to: '/{$}-foo', + expected: [ + { type: 'pathname', value: '/' }, + { + type: 'wildcard', + value: '$', + suffixSegment: '-foo', + }, + ], + }, + { + name: 'with prefix + suffix', + to: '/foo{$}-bar', + expected: [ + { type: 'pathname', value: '/' }, + { + type: 'wildcard', + value: '$', + prefixSegment: 'foo', + suffixSegment: '-bar', + }, + ], + }, + { + name: 'with prefix + followed by special character and a segment', + to: '/foo.{$}/bar', + expected: [ + { type: 'pathname', value: '/' }, + { + type: 'wildcard', + value: '$', + prefixSegment: 'foo.', + }, + { type: 'pathname', value: 'bar' }, + ], + }, + ] satisfies ParsePathnameTestScheme)('$name', ({ to, expected }) => { + const result = parsePathname(to) + expect(result).toEqual(expected) + }) + }) + + describe('named params (prefix + suffix)', () => { + it.each([ + { + name: 'regular', + to: '/$bar', + expected: [ + { type: 'pathname', value: '/' }, + { type: 'param', value: '$bar' }, + ], + }, + { + name: 'regular curly braces', + to: '/{$bar}', + expected: [ + { type: 'pathname', value: '/' }, + { type: 'param', value: '$bar' }, + ], + }, + { + name: 'with prefix (regular text)', + to: '/foo{$bar}', + expected: [ + { type: 'pathname', value: '/' }, + { + type: 'param', + value: '$bar', + prefixSegment: 'foo', + }, + ], + }, + { + name: 'with prefix + followed by special character', + to: '/foo.{$bar}', + expected: [ + { type: 'pathname', value: '/' }, + { + type: 'param', + value: '$bar', + prefixSegment: 'foo.', + }, + ], + }, + { + name: 'with suffix', + to: '/{$bar}.foo', + expected: [ + { type: 'pathname', value: '/' }, + { + type: 'param', + value: '$bar', + suffixSegment: '.foo', + }, + ], + }, + { + name: 'with suffix + started by special character', + to: '/{$bar}.foo', + expected: [ + { type: 'pathname', value: '/' }, + { + type: 'param', + value: '$bar', + suffixSegment: '.foo', + }, + ], + }, + { + name: 'with suffix + started by special character and followed by segment', + to: '/{$bar}.foo/baz', + expected: [ + { type: 'pathname', value: '/' }, + { + type: 'param', + value: '$bar', + suffixSegment: '.foo', + }, + { type: 'pathname', value: 'baz' }, + ], + }, + { + name: 'with suffix + prefix', + to: '/foo{$bar}.baz', + expected: [ + { type: 'pathname', value: '/' }, + { + type: 'param', + value: '$bar', + prefixSegment: 'foo', + suffixSegment: '.baz', + }, + ], + }, + ] satisfies ParsePathnameTestScheme)('$name', ({ to, expected }) => { + const result = parsePathname(to) + expect(result).toEqual(expected) + }) + }) }) diff --git a/packages/router-devtools-core/package.json b/packages/router-devtools-core/package.json index 59cc80782b..642c67fa8a 100644 --- a/packages/router-devtools-core/package.json +++ b/packages/router-devtools-core/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/router-devtools-core", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for Web applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/router-devtools/package.json b/packages/router-devtools/package.json index 82405a50bb..549286718d 100644 --- a/packages/router-devtools/package.json +++ b/packages/router-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/router-devtools", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "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 6a86263abf..00328a6322 100644 --- a/packages/router-generator/package.json +++ b/packages/router-generator/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/router-generator", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/router-generator/src/config.ts b/packages/router-generator/src/config.ts index b76b1d5af3..f9eae06dfb 100644 --- a/packages/router-generator/src/config.ts +++ b/packages/router-generator/src/config.ts @@ -2,24 +2,203 @@ import path from 'node:path' import { existsSync, readFileSync } from 'node:fs' import { z } from 'zod' import { virtualRootRouteSchema } from './filesystem/virtual/config' +import type { VirtualRootRoute } from '@tanstack/virtual-file-routes' -export const configSchema = z.object({ +export interface ConfigOptions { + /** + * The framework of your application, either `react` or `solid`. + * + * @default 'react' + */ + target?: 'react' | 'solid' + /** + * This option is used to configure the Virtual File Routes feature. See the {@link https://tanstack.com/router/latest/docs/framework/react/routing/virtual-file-routes Virtual File Routes} guide for more information. + * + * @default undefined + */ + virtualRouteConfig?: string | VirtualRootRoute // TODO: This should be a type + /** + * This option is used to identify route files in the route directory. This means that only files that start with this prefix will be considered for routing. + * + * @default '' all files in the route directory will be considered for routing. + */ + routeFilePrefix?: string + /** + * This option is used to ignore specific files and directories in the route directory. This can be useful if you want to "opt-in" certain files or directories that you do not want to be considered for routing. + * + * When using this option, it allows you have structures like this where it let's you co-located related files that are not route files. + * + * @example + *
+   * src/routes
+   * |── posts
+   * │   ├── -components  // Ignored with routeFileIgnorePrefix of '-'
+   * │   │   ├── Post.tsx
+   * │   ├── index.tsx
+   * │   ├── route.tsx
+   * 
+ * + * @default '-' + */ + routeFileIgnorePrefix?: string + /** + * This option is used to ignore specific files and directories in the route directory. It can be used in regular expression format. For example, .((css|const).ts)|test-page will ignore files / directories with names containing .css.ts, .const.ts or test-page. + * + * @default undefined + */ + routeFileIgnorePattern?: string + /** + * This is the path to the directory where the route files are located, relative to the cwd (current working directory). + * + * By default, the value is set to the following and cannot be set to an empty string or undefined. + * + * @default './src/routes' + */ + routesDirectory?: string + /** + * This is the path to the file where the generated route tree will be saved, relative to the cwd (current working directory). + * + * By default, the value is set to the following and cannot be set to an empty string or undefined. + * + * @default './src/routeTree.gen.ts' + */ + generatedRouteTree?: string + /** + * When your generated route tree is generated and when you first create a new route, those files will be formatted with the quote style you specify here. + * + * **Tip**: You should ignore the path of your generated route tree file from your linter and formatter to avoid conflicts. + * + * @default 'single' + */ + quoteStyle?: 'single' | 'double', + /** + * When your generated route tree is generated and when you first create a new route, those files will be formatted with semicolons if this option is set to true. + * + * **Tip**: You should ignore the path of your generated route tree file from your linter and formatter to avoid conflicts. + * + * @default false + */ + semicolons?: boolean, + /** + * This option is used to disable generating types for the route tree. + * + * If set to true, the generated route tree will not include any types and will be written as a .js file instead of a .ts file. + * + * @default false + */ + disableTypes?: boolean; + /** + * This option adds file extensions to the route names in the generated route tree. + * + * @default false + */ + addExtensions?: boolean; + /** + * This option turns off the console logging for the route generation process. + * + * @default false + */ + disableLogging?: boolean; + /** + * {@link https://tanstack.com/start TanStack Start} leverages the generatedRouteTree file to also store a JSON tree which allows Start to easily traverse the available route tree to understand the routing structure of the application. This JSON tree is saved at the end of the generated route tree file. + * + * This option allows you to disable the generation of the manifest. + * + * @default false + */ + disableManifestGeneration?: boolean; + /** + * This option turns on the formatting function on the generated route tree file, which can be time-consuming for large projects. + * + * @default true + */ + enableRouteTreeFormatting?: boolean; + __enableAPIRoutesGeneration?: boolean; + /** + * As a framework, TanStack Start supports the concept of API routes. This option configures the base path for API routes. + * + * This means that all API routes will be prefixed with /api. + * + * This configuration value is only useful if you are using TanStack Start. + * + * **Important**: This default value may conflict with your own project's routing if you planned on having a normal route with the same base path. You can change this value to avoid conflicts. + * + * @default '/api' + */ + apiBase?: string; + /** + * This option let's you prepend content to the start of the generated route tree file. + * + * @default + * ```ts + [ + '\/* eslint-disable *\/', + '// @ts-nocheck', + '// noinspection JSUnusedGlobalSymbols', + ] + * ``` + */ + routeTreeFileHeader?: Array; + /** + * This option let's you append content to the end of the generated route tree file. + * + * @default [] + */ + routeTreeFileFooter?: Array; + /** + * This feature is only available is you are using the TanStack Router Bundler Plugin. + * + * This option is used to enable automatic code-splitting for non-critical route configuration items. See the "Automatic Code-Splitting" guide for more information. + * + * **Important**: The next major release of TanStack Router (i.e. v2), will have this value defaulted to `true`. + * + * @default false + */ + autoCodeSplitting?: boolean; + /** + * As mentioned in the Routing Concepts guide, an index route is a route that is matched when the URL path is exactly the same as the parent route. The `indexToken` is used to identify the index route file in the route directory. + * + * With a value of `index`, the following filenames would equal the same runtime URL: + * + * ```txt + * src/routes/posts.index.tsx -> /posts/ + * src/routes/posts/index.tsx -> /posts/ + * ``` + * + * @default 'index' + */ + indexToken?: string; + /** + * As mentioned in the Routing Concepts guide, a layout route is rendered at the specified path, and the child routes are rendered within the layout route. The `routeToken` is used to identify the layout route file in the route directory. + * + * With a value of `index`, the following filenames would equal the same runtime URL: + * + * ```txt + * src/routes/posts.tsx -> /posts + * src/routes/posts.route.tsx -> /posts + * src/routes/posts/route.tsx -> /posts + * ``` + * + * @default 'route' + */ + routeToken?: string; + pathParamsAllowedCharacters?: Array; + customScaffolding?: unknown; + experimental?: { + enableCodeSplitting?: boolean; + }; +} + +export const baseConfigSchema = z.object({ target: z.enum(['react', 'solid']).optional().default('react'), virtualRouteConfig: virtualRootRouteSchema.or(z.string()).optional(), routeFilePrefix: z.string().optional(), routeFileIgnorePrefix: z.string().optional().default('-'), routeFileIgnorePattern: z.string().optional(), routesDirectory: z.string().optional().default('./src/routes'), - generatedRouteTree: z.string().optional().default('./src/routeTree.gen.ts'), quoteStyle: z.enum(['single', 'double']).optional().default('single'), semicolons: z.boolean().optional().default(false), - disableTypes: z.boolean().optional().default(false), - addExtensions: z.boolean().optional().default(false), disableLogging: z.boolean().optional().default(false), - disableManifestGeneration: z.boolean().optional().default(false), - enableRouteTreeFormatting: z.boolean().optional().default(true), - __enableAPIRoutesGeneration: z.boolean().optional(), // Internal flag to be turned on for TanStack Start - apiBase: z.string().optional().default('/api'), routeTreeFileHeader: z .array(z.string()) .optional() @@ -28,18 +207,28 @@ export const configSchema = z.object({ '// @ts-nocheck', '// noinspection JSUnusedGlobalSymbols', ]), - routeTreeFileFooter: z.array(z.string()).optional().default([]), - autoCodeSplitting: z.boolean().optional(), indexToken: z.string().optional().default('index'), routeToken: z.string().optional().default('route'), pathParamsAllowedCharacters: z .array(z.enum([';', ':', '@', '&', '=', '+', '$', ','])) .optional(), +}) + +export type BaseConfig = z.infer + +export const configSchema = baseConfigSchema.extend({ + generatedRouteTree: z.string().optional().default('./src/routeTree.gen.ts'), + disableTypes: z.boolean().optional().default(false), + verboseFileRoutes: z.boolean().optional(), + addExtensions: z.boolean().optional().default(false), + disableManifestGeneration: z.boolean().optional().default(false), + enableRouteTreeFormatting: z.boolean().optional().default(true), + routeTreeFileFooter: z.array(z.string()).optional().default([]), + autoCodeSplitting: z.boolean().optional(), customScaffolding: z .object({ routeTemplate: z.string().optional(), lazyRouteTemplate: z.string().optional(), - apiTemplate: z.string().optional(), }) .optional(), experimental: z @@ -48,9 +237,9 @@ export const configSchema = z.object({ enableCodeSplitting: z.boolean().optional(), }) .optional(), -}) +}) satisfies z.ZodType -export type Config = z.infer +export type Config = z.output type ResolveParams = { configDirectory: string @@ -61,7 +250,7 @@ export function resolveConfigPath({ configDirectory }: ResolveParams) { } export function getConfig( - inlineConfig: Partial = {}, + inlineConfig: ConfigOptions = {}, configDirectory?: string, ): Config { if (configDirectory === undefined) { diff --git a/packages/router-generator/src/filesystem/physical/getRouteNodes.ts b/packages/router-generator/src/filesystem/physical/getRouteNodes.ts index 0c0df6ea5d..f72da5fac2 100644 --- a/packages/router-generator/src/filesystem/physical/getRouteNodes.ts +++ b/packages/router-generator/src/filesystem/physical/getRouteNodes.ts @@ -4,8 +4,6 @@ import { determineInitialRoutePath, logging, removeExt, - removeLeadingSlash, - removeTrailingSlash, replaceBackslash, routePathToVariable, } from '../../utils' @@ -22,7 +20,16 @@ import type { Config } from '../../config' const disallowedRouteGroupConfiguration = /\(([^)]+)\).(ts|js|tsx|jsx)/ export async function getRouteNodes( - config: Config, + config: Pick< + Config, + | 'routesDirectory' + | 'routeFilePrefix' + | 'routeFileIgnorePrefix' + | 'routeFileIgnorePattern' + | 'disableLogging' + | 'routeToken' + | 'indexToken' + >, root: string, ): Promise { const { routeFilePrefix, routeFileIgnorePrefix, routeFileIgnorePattern } = @@ -196,7 +203,7 @@ export async function getRouteNodes( */ export function getRouteMeta( routePath: string, - config: Config, + config: Pick, ): { // `__root` is can be more easily determined by filtering down to routePath === /${rootPathId} // `pathless` is needs to determined after `lazy` has been cleaned up from the routePath @@ -215,15 +222,7 @@ export function getRouteMeta( } { let fsRouteType: FsRouteType = 'static' - if ( - removeLeadingSlash(routePath).startsWith( - `${removeTrailingSlash(removeLeadingSlash(config.apiBase))}/`, - ) && - config.__enableAPIRoutesGeneration - ) { - // api routes, i.e. `/api/foo.ts` - fsRouteType = 'api' - } else if (routePath.endsWith(`/${config.routeToken}`)) { + if (routePath.endsWith(`/${config.routeToken}`)) { // layout routes, i.e `/foo/route.tsx` or `/foo/_layout/route.tsx` fsRouteType = 'layout' } else if (routePath.endsWith('/lazy')) { @@ -257,7 +256,7 @@ export function getRouteMeta( function isValidPathlessLayoutRoute( normalizedRoutePath: string, routeType: FsRouteType, - config: Config, + config: Pick, ): boolean { if (routeType === 'lazy') { return false diff --git a/packages/router-generator/src/filesystem/virtual/config.ts b/packages/router-generator/src/filesystem/virtual/config.ts index 5960c25ef8..3ea45cd48e 100644 --- a/packages/router-generator/src/filesystem/virtual/config.ts +++ b/packages/router-generator/src/filesystem/virtual/config.ts @@ -38,8 +38,8 @@ const virtualRouteNodeSchema = z.union([ physicalSubTreeSchema, ]) -export const virtualRootRouteSchema: z.ZodType = z.object({ +export const virtualRootRouteSchema = z.object({ type: z.literal('root'), file: z.string(), children: z.array(virtualRouteNodeSchema).optional(), -}) +}) satisfies z.ZodType; diff --git a/packages/router-generator/src/filesystem/virtual/getRouteNodes.ts b/packages/router-generator/src/filesystem/virtual/getRouteNodes.ts index b9fa25c41a..9cca5b59bd 100644 --- a/packages/router-generator/src/filesystem/virtual/getRouteNodes.ts +++ b/packages/router-generator/src/filesystem/virtual/getRouteNodes.ts @@ -37,7 +37,15 @@ function flattenTree(node: RouteNode): Array { } export async function getRouteNodes( - tsrConfig: Config, + tsrConfig: Pick< + Config, + | 'routesDirectory' + | 'virtualRouteConfig' + | 'routeFileIgnorePrefix' + | 'disableLogging' + | 'indexToken' + | 'routeToken' + >, root: string, ): Promise { const fullDir = resolve(tsrConfig.routesDirectory) @@ -90,7 +98,7 @@ export async function getRouteNodes( * */ async function getVirtualRouteConfigFromFileExport( - tsrConfig: Config, + tsrConfig: Pick, root: string, ): Promise { if ( @@ -115,7 +123,14 @@ async function getVirtualRouteConfigFromFileExport( } export async function getRouteNodesRecursive( - tsrConfig: Config, + tsrConfig: Pick< + Config, + | 'routesDirectory' + | 'routeFileIgnorePrefix' + | 'disableLogging' + | 'indexToken' + | 'routeToken' + >, root: string, fullDir: string, nodes?: Array, diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts index b7c579daec..83b4c1fbdf 100644 --- a/packages/router-generator/src/generator.ts +++ b/packages/router-generator/src/generator.ts @@ -2,12 +2,10 @@ import path from 'node:path' import * as fs from 'node:fs' import * as fsp from 'node:fs/promises' import { - determineInitialRoutePath, format, logging, multiSortBy, removeExt, - removeTrailingSlash, removeUnderscores, replaceBackslash, resetRegex, @@ -18,18 +16,12 @@ import { import { getRouteNodes as physicalGetRouteNodes } from './filesystem/physical/getRouteNodes' import { getRouteNodes as virtualGetRouteNodes } from './filesystem/virtual/getRouteNodes' import { rootPathId } from './filesystem/physical/rootPathId' -import { - defaultAPIRouteTemplate, - fillTemplate, - getTargetTemplate, -} from './template' +import { fillTemplate, getTargetTemplate } from './template' import type { FsRouteType, GetRouteNodesResult, RouteNode } from './types' import type { Config } from './config' -export const CONSTANTS = { - // When changing this, you'll want to update the import in `start-api-routes/src/index.ts#defaultAPIFileRouteHandler` - APIRouteExportVariable: 'APIRoute', -} +// Maybe import this from `@tanstack/router-core` in the future??? +const rootRouteId = '__root__' let latestTask = 0 const routeGroupPatternRegex = /\(.+\)/g @@ -76,10 +68,6 @@ export async function generator(config: Config, root: string) { const TYPES_DISABLED = config.disableTypes - // Controls whether API Routes are generated for TanStack Start - const ENABLED_API_ROUTES_GENERATION = - config.__enableAPIRoutesGeneration ?? false - let getRouteNodesResult: GetRouteNodesResult if (config.virtualRouteConfig) { @@ -117,30 +105,6 @@ export async function generator(config: Config, root: string) { const routeTree: Array = [] const routePiecesByPath: Record = {} - // Filtered API Route nodes - const onlyAPIRouteNodes = preRouteNodes.filter((d) => { - if (!ENABLED_API_ROUTES_GENERATION) { - return false - } - - if (d._fsRouteType !== 'api') { - return false - } - - return true - }) - - // Filtered Generator Route nodes - const onlyGeneratorRouteNodes = preRouteNodes.filter((d) => { - if (ENABLED_API_ROUTES_GENERATION) { - if (d._fsRouteType === 'api') { - return false - } - } - - return true - }) - // Loop over the flat list of routeNodes and // build up a tree based on the routeNodes' routePath const routeNodes: Array = [] @@ -243,7 +207,7 @@ export async function generator(config: Config, root: string) { tLazyRouteTemplate.template(), { tsrImports: tLazyRouteTemplate.imports.tsrImports(), - tsrPath: escapedRoutePath, + tsrPath: escapedRoutePath.replaceAll(/\{(.+)\}/gm, '$1'), tsrExportStart: tLazyRouteTemplate.imports.tsrExportStart(escapedRoutePath), tsrExportEnd: tLazyRouteTemplate.imports.tsrExportEnd(), @@ -269,20 +233,104 @@ export async function generator(config: Config, root: string) { tRouteTemplate.template(), { tsrImports: tRouteTemplate.imports.tsrImports(), - tsrPath: escapedRoutePath, + tsrPath: escapedRoutePath.replaceAll(/\{(.+)\}/gm, '$1'), tsrExportStart: tRouteTemplate.imports.tsrExportStart(escapedRoutePath), tsrExportEnd: tRouteTemplate.imports.tsrExportEnd(), }, ) } + } else if (config.verboseFileRoutes === false) { + // Check if the route file has a Route export + if ( + !routeCode + .split('\n') + .some((line) => line.trim().startsWith('export const Route')) + ) { + return + } + + // Update the existing route file + replaced = routeCode + .replace( + /(FileRoute\(\s*['"])([^\s]*)(['"],?\s*\))/g, + (_, p1, __, p3) => `${p1}${escapedRoutePath}${p3}`, + ) + .replace( + new RegExp( + `(import\\s*\\{)(.*)(create(Lazy)?FileRoute)(.*)(\\}\\s*from\\s*['"]@tanstack\\/${ROUTE_TEMPLATE.subPkg}['"])`, + 'gs', + ), + (_, p1, p2, ___, ____, p5, p6) => { + const beforeCreateFileRoute = () => { + if (!p2) return '' + + let trimmed = p2.trim() + + if (trimmed.endsWith(',')) { + trimmed = trimmed.slice(0, -1) + } + + return trimmed + } + + const afterCreateFileRoute = () => { + if (!p5) return '' + + let trimmed = p5.trim() + + if (trimmed.startsWith(',')) { + trimmed = trimmed.slice(1) + } + + return trimmed + } + + const newImport = () => { + const before = beforeCreateFileRoute() + const after = afterCreateFileRoute() + + if (!before) return after + + if (!after) return before + + return `${before},${after}` + } + + const middle = newImport() + + if (middle === '') return '' + + return `${p1} ${newImport()} ${p6}` + }, + ) + .replace( + /create(Lazy)?FileRoute(\(\s*['"])([^\s]*)(['"],?\s*\))/g, + (_, __, p2, ___, p4) => + `${node._fsRouteType === 'lazy' ? 'createLazyFileRoute' : 'createFileRoute'}`, + ) } else { + // Check if the route file has a Route export + if ( + !routeCode + .split('\n') + .some((line) => line.trim().startsWith('export const Route')) + ) { + return + } + // Update the existing route file replaced = routeCode + // fix wrong ids .replace( /(FileRoute\(\s*['"])([^\s]*)(['"],?\s*\))/g, (_, p1, __, p3) => `${p1}${escapedRoutePath}${p3}`, ) + // fix missing ids + .replace( + /((FileRoute)(\s*)(\({))/g, + (_, __, p2, p3, p4) => `${p2}('${escapedRoutePath}')${p3}${p4}`, + ) .replace( new RegExp( `(import\\s*\\{.*)(create(Lazy)?FileRoute)(.*\\}\\s*from\\s*['"]@tanstack\\/${ROUTE_TEMPLATE.subPkg}['"])`, @@ -296,6 +344,18 @@ export async function generator(config: Config, root: string) { (_, __, p2, ___, p4) => `${node._fsRouteType === 'lazy' ? 'createLazyFileRoute' : 'createFileRoute'}${p2}${escapedRoutePath}${p4}`, ) + + // check whether the import statement is already present + const regex = new RegExp( + `(import\\s*\\{.*)(create(Lazy)?FileRoute)(.*\\}\\s*from\\s*['"]@tanstack\\/${ROUTE_TEMPLATE.subPkg}['"])`, + 'gm', + ) + if (!replaced.match(regex)) { + replaced = [ + `import { ${node._fsRouteType === 'lazy' ? 'createLazyFileRoute' : 'createFileRoute'} } from '@tanstack/${ROUTE_TEMPLATE.subPkg}'`, + ...replaced.split('\n'), + ].join('\n') + } } await writeIfDifferent(node.fullPath, routeCode, replaced, { @@ -406,77 +466,22 @@ export async function generator(config: Config, root: string) { routeNodes.push(node) } - for (const node of onlyGeneratorRouteNodes) { + for (const node of preRouteNodes) { await handleNode(node) } + + // This is run against the `preRouteNodes` array since it + // has the flattened Route nodes and not the full tree + // Since TSR allows multiple way of defining a route, + // we need to ensure that a user hasn't defined the + // same route in multiple ways (i.e. `flat`, `nested`, `virtual`) checkRouteFullPathUniqueness( preRouteNodes.filter( - (d) => - d.children === undefined && - (['api', 'lazy'] satisfies Array).every( - (type) => type !== d._fsRouteType, - ), + (d) => d.children === undefined && 'lazy' !== d._fsRouteType, ), config, ) - const startAPIRouteNodes: Array = checkStartAPIRoutes( - onlyAPIRouteNodes, - config, - ) - - const handleAPINode = async (node: RouteNode) => { - const routeCode = fs.readFileSync(node.fullPath, 'utf-8') - - const escapedRoutePath = node.routePath?.replaceAll('$', '$$') ?? '' - - if (!routeCode) { - const replaced = await fillTemplate( - config, - config.customScaffolding?.apiTemplate ?? defaultAPIRouteTemplate, - { - tsrImports: - "import { createAPIFileRoute } from '@tanstack/react-start/api';", - tsrPath: escapedRoutePath, - tsrExportStart: `export const ${CONSTANTS.APIRouteExportVariable} = createAPIFileRoute('${escapedRoutePath}')(`, - tsrExportEnd: ');', - }, - ) - - await writeIfDifferent( - node.fullPath, - '', // Empty string because the file doesn't exist yet - replaced, - { - beforeWrite: () => { - logger.log(`🟡 Creating ${node.fullPath}`) - }, - }, - ) - } else { - await writeIfDifferent( - node.fullPath, - routeCode, - routeCode.replace( - /(createAPIFileRoute\(\s*['"])([^\s]*)(['"],?\s*\))/g, - (_, p1, __, p3) => `${p1}${escapedRoutePath}${p3}`, - ), - { - beforeWrite: () => { - logger.log(`🟡 Updating ${node.fullPath}`) - }, - }, - ) - } - } - - // Handle the API routes for TanStack Start - if (ENABLED_API_ROUTES_GENERATION) { - for (const node of startAPIRouteNodes) { - await handleAPINode(node) - } - } - function buildRouteTreeConfig(nodes: Array, depth = 1): string { const children = nodes.map((node) => { if (node._fsRouteType === '__root') { @@ -527,6 +532,30 @@ export async function generator(config: Config, root: string) { (d) => d, ]) + const typeImports = Object.entries({ + // Used for augmentation of regular routes + CreateFileRoute: + config.verboseFileRoutes === false && + sortedRouteNodes.some( + (d) => isRouteNodeValidForAugmentation(d) && d._fsRouteType !== 'lazy', + ), + // Used for augmentation of lazy (`.lazy`) routes + CreateLazyFileRoute: + config.verboseFileRoutes === false && + sortedRouteNodes.some( + (node) => + routePiecesByPath[node.routePath!]?.lazy && + isRouteNodeValidForAugmentation(node), + ), + // Used in the process of augmenting the routes + FileRoutesByPath: + config.verboseFileRoutes === false && + sortedRouteNodes.some((d) => isRouteNodeValidForAugmentation(d)), + }) + .filter((d) => d[1]) + .map((d) => d[0]) + .sort((a, b) => a.localeCompare(b)) + const imports = Object.entries({ createFileRoute: sortedRouteNodes.some((d) => d.isVirtual), lazyFn: sortedRouteNodes.some( @@ -555,14 +584,22 @@ export async function generator(config: Config, root: string) { ), ) } + const routeImports = [ ...config.routeTreeFileHeader, `// This file was automatically generated by TanStack Router. // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.`, - imports.length - ? `import { ${imports.join(', ')} } from '${ROUTE_TEMPLATE.fullPkg}'\n` - : '', + [ + imports.length + ? `import { ${imports.join(', ')} } from '${ROUTE_TEMPLATE.fullPkg}'` + : '', + !TYPES_DISABLED && typeImports.length + ? `import type { ${typeImports.join(', ')} } from '${ROUTE_TEMPLATE.fullPkg}'` + : '', + ] + .filter(Boolean) + .join('\n'), '// Import Routes', [ `import { Route as rootRoute } from './${getImportPath(rootRouteNode)}'`, @@ -571,7 +608,7 @@ export async function generator(config: Config, root: string) { .map((node) => { return `import { Route as ${ node.variableName - }Import } from './${getImportPath(node)}'` + }RouteImport } from './${getImportPath(node)}'` }), ].join('\n'), virtualRouteNodes.length ? '// Create Virtual Routes' : '', @@ -579,7 +616,7 @@ export async function generator(config: Config, root: string) { .map((node) => { return `const ${ node.variableName - }Import = createFileRoute('${node.routePath}')()` + }RouteImport = createFileRoute('${node.routePath}')()` }) .join('\n'), '// Create/Update Routes', @@ -594,7 +631,8 @@ export async function generator(config: Config, root: string) { const lazyComponentNode = routePiecesByPath[node.routePath!]?.lazy return [ - `const ${node.variableName}Route = ${node.variableName}Import.update({ + [ + `const ${node.variableName}Route = ${node.variableName}RouteImport.update({ ${[ `id: '${node.path}'`, !node.isNonPath ? `path: '${node.cleanedPath}'` : undefined, @@ -603,19 +641,19 @@ export async function generator(config: Config, root: string) { .filter(Boolean) .join(',')} }${TYPES_DISABLED ? '' : 'as any'})`, - loaderNode - ? `.updateLoader({ loader: lazyFn(() => import('./${replaceBackslash( - removeExt( - path.relative( - path.dirname(config.generatedRouteTree), - path.resolve(config.routesDirectory, loaderNode.filePath), + loaderNode + ? `.updateLoader({ loader: lazyFn(() => import('./${replaceBackslash( + removeExt( + path.relative( + path.dirname(config.generatedRouteTree), + path.resolve(config.routesDirectory, loaderNode.filePath), + ), + config.addExtensions, ), - config.addExtensions, - ), - )}'), 'loader') })` - : '', - componentNode || errorComponentNode || pendingComponentNode - ? `.update({ + )}'), 'loader') })` + : '', + componentNode || errorComponentNode || pendingComponentNode + ? `.update({ ${( [ ['component', componentNode], @@ -639,22 +677,23 @@ export async function generator(config: Config, root: string) { }) .join('\n,')} })` - : '', - lazyComponentNode - ? `.lazy(() => import('./${replaceBackslash( - removeExt( - path.relative( - path.dirname(config.generatedRouteTree), - path.resolve( - config.routesDirectory, - lazyComponentNode.filePath, + : '', + lazyComponentNode + ? `.lazy(() => import('./${replaceBackslash( + removeExt( + path.relative( + path.dirname(config.generatedRouteTree), + path.resolve( + config.routesDirectory, + lazyComponentNode.filePath, + ), ), + config.addExtensions, ), - config.addExtensions, - ), - )}').then((d) => d.Route))` - : '', - ].join('') + )}').then((d) => d.Route))` + : '', + ].join(''), + ].join('\n\n') }) .join('\n\n'), ...(TYPES_DISABLED @@ -671,12 +710,12 @@ export async function generator(config: Config, root: string) { id: '${filePathId}' path: '${inferPath(routeNode)}' fullPath: '${inferFullPath(routeNode)}' - preLoaderRoute: typeof ${routeNode.variableName}Import + preLoaderRoute: typeof ${routeNode.variableName}RouteImport parentRoute: typeof ${ routeNode.isVirtualParentRequired ? `${routeNode.parent?.variableName}Route` : routeNode.parent?.variableName - ? `${routeNode.parent.variableName}Import` + ? `${routeNode.parent.variableName}RouteImport` : 'rootRoute' } }` @@ -685,6 +724,41 @@ export async function generator(config: Config, root: string) { } }`, ]), + ...(TYPES_DISABLED + ? [] + : config.verboseFileRoutes !== false + ? [] + : [ + `// Add type-safety to the createFileRoute function across the route tree`, + routeNodes + .map((routeNode) => { + function getModuleDeclaration(routeNode?: RouteNode) { + if (!isRouteNodeValidForAugmentation(routeNode)) { + return '' + } + return `declare module './${getImportPath(routeNode)}' { + const ${routeNode._fsRouteType === 'lazy' ? 'createLazyFileRoute' : 'createFileRoute'}: ${ + routeNode._fsRouteType === 'lazy' + ? `CreateLazyFileRoute}` + : `CreateFileRoute< + '${routeNode.routePath}', + FileRoutesByPath['${routeNode.routePath}']['parentRoute'], + FileRoutesByPath['${routeNode.routePath}']['id'], + FileRoutesByPath['${routeNode.routePath}']['path'], + FileRoutesByPath['${routeNode.routePath}']['fullPath'] + > + }` + }` + } + return ( + getModuleDeclaration(routeNode) + + getModuleDeclaration( + routePiecesByPath[routeNode.routePath!]?.lazy, + ) + ) + }) + .join('\n'), + ]), '// Create and export the route tree', routeConfigChildrenText, ...(TYPES_DISABLED @@ -703,7 +777,7 @@ export async function generator(config: Config, root: string) { })} }`, `export interface FileRoutesById { - '__root__': typeof rootRoute, + '${rootRouteId}': typeof rootRoute, ${[...createRouteNodesById(routeNodes).entries()].map(([id, routeNode]) => { return `'${id}': typeof ${getResolvedRouteNodeVariableName(routeNode)}` })} @@ -713,7 +787,7 @@ export async function generator(config: Config, root: string) { fullPaths: ${routeNodes.length > 0 ? [...createRouteNodesByFullPath(routeNodes).keys()].map((fullPath) => `'${fullPath}'`).join('|') : 'never'} fileRoutesByTo: FileRoutesByTo to: ${routeNodes.length > 0 ? [...createRouteNodesByTo(routeNodes).keys()].map((to) => `'${to}'`).join('|') : 'never'} - id: ${[`'__root__'`, ...[...createRouteNodesById(routeNodes).keys()].map((id) => `'${id}'`)].join('|')} + id: ${[`'${rootRouteId}'`, ...[...createRouteNodesById(routeNodes).keys()].map((id) => `'${id}'`)].join('|')} fileRoutesById: FileRoutesById }`, `export interface RootRouteChildren { @@ -731,7 +805,7 @@ export async function generator(config: Config, root: string) { const createRouteManifest = () => { const routesManifest = { - __root__: { + [rootRouteId]: { filePath: rootRouteNode.filePath, children: routeTree.map((d) => d.routePath), }, @@ -827,6 +901,22 @@ function removeGroups(s: string) { return s.replace(possiblyNestedRouteGroupPatternRegex, '') } +/** + * Checks if a given RouteNode is valid for augmenting it with typing based on conditions. + * Also asserts that the RouteNode is defined. + * + * @param routeNode - The RouteNode to check. + * @returns A boolean indicating whether the RouteNode is defined. + */ +function isRouteNodeValidForAugmentation( + routeNode?: RouteNode, +): routeNode is RouteNode { + if (!routeNode || routeNode.isVirtual) { + return false + } + return true +} + /** * 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. @@ -847,7 +937,7 @@ function determineNodePath(node: RouteNode) { * @example * removeLastSegmentFromPath('/workspace/_auth/foo') // '/workspace/_auth' */ -export function removeLastSegmentFromPath(routePath: string = '/'): string { +function removeLastSegmentFromPath(routePath: string = '/'): string { const segments = routePath.split('/') segments.pop() // Remove the last segment return segments.join('/') @@ -867,7 +957,7 @@ function removeLayoutSegments(routePath: string = '/'): string { return newSegments.join('/') } -export function hasParentRoute( +function hasParentRoute( routes: Array, node: RouteNode, routePathToCheck: string | undefined, @@ -902,9 +992,7 @@ export function hasParentRoute( /** * Gets the final variable name for a route */ -export const getResolvedRouteNodeVariableName = ( - routeNode: RouteNode, -): string => { +const getResolvedRouteNodeVariableName = (routeNode: RouteNode): string => { return routeNode.children?.length ? `${routeNode.variableName}RouteWithChildren` : `${routeNode.variableName}Route` @@ -913,7 +1001,7 @@ export const getResolvedRouteNodeVariableName = ( /** * Creates a map from fullPath to routeNode */ -export const createRouteNodesByFullPath = ( +const createRouteNodesByFullPath = ( routeNodes: Array, ): Map => { return new Map( @@ -924,7 +1012,7 @@ export const createRouteNodesByFullPath = ( /** * Create a map from 'to' to a routeNode */ -export const createRouteNodesByTo = ( +const createRouteNodesByTo = ( routeNodes: Array, ): Map => { return new Map( @@ -938,7 +1026,7 @@ export const createRouteNodesByTo = ( /** * Create a map from 'id' to a routeNode */ -export const createRouteNodesById = ( +const createRouteNodesById = ( routeNodes: Array, ): Map => { return new Map( @@ -952,7 +1040,7 @@ export const createRouteNodesById = ( /** * Infers the full path for use by TS */ -export const inferFullPath = (routeNode: RouteNode): string => { +const inferFullPath = (routeNode: RouteNode): string => { const fullPath = removeGroups( removeUnderscores(removeLayoutSegments(routeNode.routePath)) ?? '', ) @@ -963,7 +1051,7 @@ export const inferFullPath = (routeNode: RouteNode): string => { /** * Infers the path for use by TS */ -export const inferPath = (routeNode: RouteNode): string => { +const inferPath = (routeNode: RouteNode): string => { return routeNode.cleanedPath === '/' ? routeNode.cleanedPath : (routeNode.cleanedPath?.replace(/\/$/, '') ?? '') @@ -972,7 +1060,7 @@ export const inferPath = (routeNode: RouteNode): string => { /** * Infers to path */ -export const inferTo = (routeNode: RouteNode): string => { +const inferTo = (routeNode: RouteNode): string => { const fullPath = inferFullPath(routeNode) if (fullPath === '/') return fullPath @@ -983,7 +1071,7 @@ export const inferTo = (routeNode: RouteNode): string => { /** * Dedupes branches and index routes */ -export const dedupeBranchesAndIndexRoutes = ( +const dedupeBranchesAndIndexRoutes = ( routes: Array, ): Array => { return routes.filter((route) => { @@ -1022,75 +1110,8 @@ function checkRouteFullPathUniqueness( const errorMessage = `Conflicting configuration paths were found for the following route${conflictingFiles.length > 1 ? 's' : ''}: ${conflictingFiles .map((p) => `"${p.inferredFullPath}"`) .join(', ')}. -Please ensure each route has a unique full path. -Conflicting files: \n ${conflictingFiles.map((d) => path.resolve(config.routesDirectory, d.filePath)).join('\n ')}\n` - throw new Error(errorMessage) - } -} - -function checkStartAPIRoutes(_routes: Array, config: Config) { - if (_routes.length === 0) { - return [] - } - - // Make sure these are valid URLs - // Route Groups and Layout Routes aren't being removed since - // you may want to have an API route that starts with an underscore - // or be wrapped in parentheses - const routes = _routes.map((d) => { - const routePath = removeTrailingSlash(d.routePath ?? '') - return { ...d, routePath } - }) - - const conflictingFiles = checkUnique(routes, 'routePath') - - if (conflictingFiles !== undefined) { - const errorMessage = `Conflicting configuration paths were found for the following API route${conflictingFiles.length > 1 ? 's' : ''}: ${conflictingFiles - .map((p) => `"${p}"`) - .join(', ')}. - Please ensure each API route has a unique route path. +Please ensure each Route has a unique full path. Conflicting files: \n ${conflictingFiles.map((d) => path.resolve(config.routesDirectory, d.filePath)).join('\n ')}\n` throw new Error(errorMessage) } - - return routes -} - -export type StartAPIRoutePathSegment = { - value: string - type: 'path' | 'param' | 'splat' -} - -/** - * This function takes in a path in the format accepted by TanStack Router - * and returns an array of path segments that can be used to generate - * the pathname of the TanStack Start API route. - * - * @param src - * @returns - */ -export function startAPIRouteSegmentsFromTSRFilePath( - src: string, - config: Config, -): Array { - const routePath = determineInitialRoutePath(src) - - const parts = routePath - .replaceAll('.', '/') - .split('/') - .filter((p) => !!p && p !== config.indexToken) - const segments: Array = parts.map((part) => { - if (part.startsWith('$')) { - if (part === '$') { - return { value: part, type: 'splat' } - } - - part.replaceAll('$', '') - return { value: part, type: 'param' } - } - - return { value: part, type: 'path' } - }) - - return segments } diff --git a/packages/router-generator/src/index.ts b/packages/router-generator/src/index.ts index 4f22337a3c..5ba84c6cbc 100644 --- a/packages/router-generator/src/index.ts +++ b/packages/router-generator/src/index.ts @@ -1,9 +1,34 @@ -export { configSchema, getConfig, resolveConfigPath } from './config' -export type { Config } from './config' +export { + configSchema, + getConfig, + resolveConfigPath, + baseConfigSchema, +} from './config' +export type { Config, BaseConfig, ConfigOptions } from './config' + +export { generator } from './generator' export { - generator, - startAPIRouteSegmentsFromTSRFilePath, - CONSTANTS, -} from './generator' -export type { StartAPIRoutePathSegment } from './generator' + logging, + capitalize, + cleanPath, + trimPathLeft, + removeLeadingSlash, + removeTrailingSlash, + determineInitialRoutePath, + replaceBackslash, + routePathToVariable, + removeUnderscores, + resetRegex, + multiSortBy, + writeIfDifferent, + format, + removeExt, +} from './utils' + +export type { RouteNode, GetRouteNodesResult } from './types' + +export { getRouteNodes as physicalGetRouteNodes } from './filesystem/physical/getRouteNodes' +export { getRouteNodes as virtualGetRouteNodes } from './filesystem/virtual/getRouteNodes' + +export { rootPathId } from './filesystem/physical/rootPathId' diff --git a/packages/router-generator/src/template.ts b/packages/router-generator/src/template.ts index 5650844a04..1c8747a97a 100644 --- a/packages/router-generator/src/template.ts +++ b/packages/router-generator/src/template.ts @@ -77,10 +77,8 @@ export function getTargetTemplate(target: Config['target']): TargetTemplate { 'function RouteComponent() { return
Hello "%%tsrPath%%"!
};\n', ].join(''), imports: { - tsrImports: () => - "import { createFileRoute } from '@tanstack/react-router';", - tsrExportStart: (routePath) => - `export const Route = createFileRoute('${routePath}')(`, + tsrImports: () => '', + tsrExportStart: () => `export const Route = createFileRoute(`, tsrExportEnd: () => ');', }, }, @@ -130,10 +128,8 @@ export function getTargetTemplate(target: Config['target']): TargetTemplate { 'function RouteComponent() { return
Hello "%%tsrPath%%"!
};\n', ].join(''), imports: { - tsrImports: () => - "import { createFileRoute } from '@tanstack/solid-router';", - tsrExportStart: (routePath) => - `export const Route = createFileRoute('${routePath}')(`, + tsrImports: () => '', + tsrExportStart: () => `export const Route = createFileRoute(`, tsrExportEnd: () => ');', }, }, @@ -158,10 +154,3 @@ export function getTargetTemplate(target: Config['target']): TargetTemplate { throw new Error(`router-generator: Unknown target type: ${target}`) } } - -export const defaultAPIRouteTemplate = [ - 'import { json } from "@tanstack/react-start";\n', - '%%tsrImports%%', - '\n\n', - '%%tsrExportStart%%{ GET: ({ request, params }) => { return json({ message:\'Hello "%%tsrPath%%"!\' }) }}%%tsrExportEnd%%\n', -].join('') diff --git a/packages/router-generator/src/types.ts b/packages/router-generator/src/types.ts index a8ba30feee..954401bdfe 100644 --- a/packages/router-generator/src/types.ts +++ b/packages/router-generator/src/types.ts @@ -25,7 +25,6 @@ export type FsRouteType = | 'layout' | 'pathless_layout' | 'lazy' - | 'api' | 'loader' // @deprecated | 'component' // @deprecated | 'pendingComponent' // @deprecated diff --git a/packages/router-generator/src/utils.ts b/packages/router-generator/src/utils.ts index 5155bb43ef..76b7fc4a6c 100644 --- a/packages/router-generator/src/utils.ts +++ b/packages/router-generator/src/utils.ts @@ -1,6 +1,5 @@ -import * as fs from 'node:fs' +import * as fsp from 'node:fs/promises' import * as prettier from 'prettier' -import type { Config } from './config' export function multiSortBy( arr: Array, @@ -86,7 +85,55 @@ export function removeTrailingSlash(s: string) { } export function determineInitialRoutePath(routePath: string) { - return cleanPath(`/${routePath.split('.').join('/')}`) || '' + const DISALLOWED_ESCAPE_CHARS = new Set([ + '/', + '\\', + '?', + '#', + ':', + '*', + '<', + '>', + '|', + '!', + '$', + '%', + ]) + + const parts = routePath.split(/(? { + // Check if any disallowed characters are used in brackets + const BRACKET_CONTENT_RE = /\[(.*?)\]/g + + let match + while ((match = BRACKET_CONTENT_RE.exec(part)) !== null) { + const character = match[1] + if (character === undefined) continue + if (DISALLOWED_ESCAPE_CHARS.has(character)) { + console.error( + `Error: Disallowed character "${character}" found in square brackets in route path "${routePath}".\nYou cannot use any of the following characters in square brackets: ${Array.from( + DISALLOWED_ESCAPE_CHARS, + ).join(', ')}\nPlease remove and/or replace them.`, + ) + process.exit(1) + } + } + + // Since this split segment is safe at this point, we can + // remove the brackets and replace them with the content inside + return part.replace(/\[(.)\]/g, '$1') + }) + + // If the syntax for prefix/suffix is different, from the path + // matching internals of router-core, we'd perform those changes here + // on the `escapedParts` array before it is joined back together in + // `final` + + const final = cleanPath(`/${escapedParts.join('/')}`) || '' + + return final } export function replaceBackslash(s: string) { @@ -94,15 +141,43 @@ export function replaceBackslash(s: string) { } export function routePathToVariable(routePath: string): string { + const toVariableSafeChar = (char: string): string => { + if (/[a-zA-Z0-9_]/.test(char)) { + return char // Keep alphanumeric characters and underscores as is + } + + // Replace special characters with meaningful text equivalents + switch (char) { + case '.': + return 'Dot' + case '-': + return 'Dash' + case '@': + return 'At' + case '(': + return '' // Removed since route groups use parentheses + case ')': + return '' // Removed since route groups use parentheses + case ' ': + return '' // Remove spaces + default: + return `Char${char.charCodeAt(0)}` // For any other characters + } + } + return ( removeUnderscores(routePath) ?.replace(/\/\$\//g, '/splat/') .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, '') + .split('') + .map(toVariableSafeChar) + .join('') + // .replace(/([^a-zA-Z0-9]|[.])/gm, '') .replace(/^(\d)/g, 'R$1') ?? '' ) } @@ -137,7 +212,7 @@ export async function writeIfDifferent( ): Promise { if (content !== incomingContent) { callbacks?.beforeWrite?.() - fs.writeFileSync(filepath, incomingContent) + await fsp.writeFile(filepath, incomingContent) callbacks?.afterWrite?.() return true } @@ -151,7 +226,13 @@ export async function writeIfDifferent( * @param config The configuration object * @returns The formatted content */ -export async function format(source: string, config: Config): Promise { +export async function format( + source: string, + config: { + quoteStyle: 'single' | 'double' + semicolons: boolean + }, +): Promise { const prettierOptions: prettier.Config = { semi: config.semicolons, singleQuote: config.quoteStyle === 'single', @@ -172,3 +253,18 @@ export function resetRegex(regex: RegExp) { regex.lastIndex = 0 return } + +/** + * This function checks if a file exists. + * + * @param file The path to the file + * @returns Whether the file exists + */ +export async function checkFileExists(file: string) { + try { + await fsp.access(file, fsp.constants.F_OK) + return true + } catch { + return false + } +} diff --git a/packages/router-generator/tests/generator.test.ts b/packages/router-generator/tests/generator.test.ts index daf787b2ec..6badeecd05 100644 --- a/packages/router-generator/tests/generator.test.ts +++ b/packages/router-generator/tests/generator.test.ts @@ -51,6 +51,7 @@ async function setupConfig( disableLogging: true, routesDirectory: dir + '/routes', generatedRouteTree: dir + generatedRouteTree, + verboseFileRoutes: false, ...rest, }) return config @@ -116,11 +117,6 @@ function rewriteConfigByFolderName(folderName: string, config: Config) { '%%tsrExportStart%%{\n component: RouteComponent\n }%%tsrExportEnd%%\n\n', 'function RouteComponent() { return "Hello %%tsrPath%%!" };\n', ].join(''), - apiTemplate: [ - 'import { json } from "@tanstack/react-start";\n', - '%%tsrImports%%\n\n', - '%%tsrExportStart%%{ GET: ({ request, params }) => { return json({ message: "Hello /api/test" }) }}%%tsrExportEnd%%\n', - ].join(''), lazyRouteTemplate: [ 'import React, { useState } from "react";\n', '%%tsrImports%%\n\n', @@ -128,7 +124,6 @@ function rewriteConfigByFolderName(folderName: string, config: Config) { 'function RouteComponent() { return "Hello %%tsrPath%%!" };\n', ].join(''), } - config.__enableAPIRoutesGeneration = true break default: break diff --git a/packages/router-generator/tests/generator/append-and-prepend/routeTree.snapshot.ts b/packages/router-generator/tests/generator/append-and-prepend/routeTree.snapshot.ts index 7ee554ed03..fb74c36e79 100644 --- a/packages/router-generator/tests/generator/append-and-prepend/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/append-and-prepend/routeTree.snapshot.ts @@ -6,14 +6,16 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -27,12 +29,24 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/packages/router-generator/tests/generator/append-and-prepend/routes/index.tsx b/packages/router-generator/tests/generator/append-and-prepend/routes/index.tsx index a525ebff0c..13c752995e 100644 --- a/packages/router-generator/tests/generator/append-and-prepend/routes/index.tsx +++ b/packages/router-generator/tests/generator/append-and-prepend/routes/index.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, validateSearch: () => ({ indexSearch: 'indexSearch', diff --git a/packages/router-generator/tests/generator/custom-scaffolding/routeTree.snapshot.ts b/packages/router-generator/tests/generator/custom-scaffolding/routeTree.snapshot.ts index 8ba4c94c1b..f8db6d367e 100644 --- a/packages/router-generator/tests/generator/custom-scaffolding/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/custom-scaffolding/routeTree.snapshot.ts @@ -9,30 +9,38 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { createFileRoute } from '@tanstack/react-router' +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' +import { Route as IndexRouteImport } from './routes/index' +import { Route as ApiBarRouteImport } from './routes/api/bar' // Create Virtual Routes -const FooLazyImport = createFileRoute('/foo')() +const FooLazyRouteImport = createFileRoute('/foo')() // Create/Update Routes -const FooLazyRoute = FooLazyImport.update({ +const FooLazyRoute = FooLazyRouteImport.update({ id: '/foo', path: '/foo', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/foo.lazy').then((d) => d.Route)) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) +const ApiBarRoute = ApiBarRouteImport.update({ + id: '/api/bar', + path: '/api/bar', + getParentRoute: () => rootRoute, +} as any) + // Populate the FileRoutesByPath interface declare module '@tanstack/react-router' { @@ -41,54 +49,92 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/foo': { id: '/foo' path: '/foo' fullPath: '/foo' - preLoaderRoute: typeof FooLazyImport + preLoaderRoute: typeof FooLazyRouteImport + parentRoute: typeof rootRoute + } + '/api/bar': { + id: '/api/bar' + path: '/api/bar' + fullPath: '/api/bar' + preLoaderRoute: typeof ApiBarRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/foo.lazy' { + const createLazyFileRoute: CreateLazyFileRoute< + FileRoutesByPath['/foo']['preLoaderRoute'] + > +} +declare module './routes/api/bar' { + const createFileRoute: CreateFileRoute< + '/api/bar', + FileRoutesByPath['/api/bar']['parentRoute'], + FileRoutesByPath['/api/bar']['id'], + FileRoutesByPath['/api/bar']['path'], + FileRoutesByPath['/api/bar']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { '/': typeof IndexRoute '/foo': typeof FooLazyRoute + '/api/bar': typeof ApiBarRoute } export interface FileRoutesByTo { '/': typeof IndexRoute '/foo': typeof FooLazyRoute + '/api/bar': typeof ApiBarRoute } export interface FileRoutesById { __root__: typeof rootRoute '/': typeof IndexRoute '/foo': typeof FooLazyRoute + '/api/bar': typeof ApiBarRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' | '/foo' + fullPaths: '/' | '/foo' | '/api/bar' fileRoutesByTo: FileRoutesByTo - to: '/' | '/foo' - id: '__root__' | '/' | '/foo' + to: '/' | '/foo' | '/api/bar' + id: '__root__' | '/' | '/foo' | '/api/bar' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute FooLazyRoute: typeof FooLazyRoute + ApiBarRoute: typeof ApiBarRoute } const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, FooLazyRoute: FooLazyRoute, + ApiBarRoute: ApiBarRoute, } export const routeTree = rootRoute @@ -102,7 +148,8 @@ export const routeTree = rootRoute "filePath": "__root.tsx", "children": [ "/", - "/foo" + "/foo", + "/api/bar" ] }, "/": { @@ -110,6 +157,9 @@ export const routeTree = rootRoute }, "/foo": { "filePath": "foo.lazy.tsx" + }, + "/api/bar": { + "filePath": "api/bar.tsx" } } } diff --git a/packages/router-generator/tests/generator/custom-scaffolding/routes/api/bar.tsx b/packages/router-generator/tests/generator/custom-scaffolding/routes/api/bar.tsx index 090f4b945a..13867e7bd1 100644 --- a/packages/router-generator/tests/generator/custom-scaffolding/routes/api/bar.tsx +++ b/packages/router-generator/tests/generator/custom-scaffolding/routes/api/bar.tsx @@ -1,8 +1,9 @@ -import { json } from '@tanstack/react-start' -import { createAPIFileRoute } from '@tanstack/react-start/api' +import * as React from 'react' -export const APIRoute = createAPIFileRoute('/api/bar')({ - GET: ({ request, params }) => { - return json({ message: 'Hello /api/test' }) - }, +export const Route = createFileRoute({ + component: RouteComponent, }) + +function RouteComponent() { + return 'Hello /api/bar!' +} diff --git a/packages/router-generator/tests/generator/custom-scaffolding/routes/index.tsx b/packages/router-generator/tests/generator/custom-scaffolding/routes/index.tsx index 8b22ea6bb5..659c416bc4 100644 --- a/packages/router-generator/tests/generator/custom-scaffolding/routes/index.tsx +++ b/packages/router-generator/tests/generator/custom-scaffolding/routes/index.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/custom-scaffolding/snapshot/api/bar.tsx b/packages/router-generator/tests/generator/custom-scaffolding/snapshot/api/bar.tsx index 090f4b945a..13867e7bd1 100644 --- a/packages/router-generator/tests/generator/custom-scaffolding/snapshot/api/bar.tsx +++ b/packages/router-generator/tests/generator/custom-scaffolding/snapshot/api/bar.tsx @@ -1,8 +1,9 @@ -import { json } from '@tanstack/react-start' -import { createAPIFileRoute } from '@tanstack/react-start/api' +import * as React from 'react' -export const APIRoute = createAPIFileRoute('/api/bar')({ - GET: ({ request, params }) => { - return json({ message: 'Hello /api/test' }) - }, +export const Route = createFileRoute({ + component: RouteComponent, }) + +function RouteComponent() { + return 'Hello /api/bar!' +} diff --git a/packages/router-generator/tests/generator/custom-scaffolding/snapshot/index.tsx b/packages/router-generator/tests/generator/custom-scaffolding/snapshot/index.tsx index 8b22ea6bb5..659c416bc4 100644 --- a/packages/router-generator/tests/generator/custom-scaffolding/snapshot/index.tsx +++ b/packages/router-generator/tests/generator/custom-scaffolding/snapshot/index.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/custom-tokens/routeTree.snapshot.ts b/packages/router-generator/tests/generator/custom-tokens/routeTree.snapshot.ts index a9170a93ef..0e6e125d65 100644 --- a/packages/router-generator/tests/generator/custom-tokens/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/custom-tokens/routeTree.snapshot.ts @@ -8,63 +8,65 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PostsR0ut3Import } from './routes/posts/_r0ut3_' -import { Route as BlogR0ut3Import } from './routes/blog/_r0ut3_' -import { Route as R1nd3xImport } from './routes/_1nd3x' -import { Route as Posts1nd3xImport } from './routes/posts/_1nd3x' -import { Route as Blog1nd3xImport } from './routes/blog/_1nd3x' -import { Route as BlogSlugImport } from './routes/blog/$slug' -import { Route as PostsPostId1nd3xImport } from './routes/posts/$postId/_1nd3x' -import { Route as PostsPostIdDeepImport } from './routes/posts/$postId/deep' +import { Route as PostsR0ut3RouteImport } from './routes/posts/_r0ut3_' +import { Route as BlogR0ut3RouteImport } from './routes/blog/_r0ut3_' +import { Route as R1nd3xRouteImport } from './routes/_1nd3x' +import { Route as Posts1nd3xRouteImport } from './routes/posts/_1nd3x' +import { Route as Blog1nd3xRouteImport } from './routes/blog/_1nd3x' +import { Route as BlogSlugRouteImport } from './routes/blog/$slug' +import { Route as PostsPostId1nd3xRouteImport } from './routes/posts/$postId/_1nd3x' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts/$postId/deep' // Create/Update Routes -const PostsR0ut3Route = PostsR0ut3Import.update({ +const PostsR0ut3Route = PostsR0ut3RouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const BlogR0ut3Route = BlogR0ut3Import.update({ +const BlogR0ut3Route = BlogR0ut3RouteImport.update({ id: '/blog', path: '/blog', getParentRoute: () => rootRoute, } as any) -const R1nd3xRoute = R1nd3xImport.update({ +const R1nd3xRoute = R1nd3xRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const Posts1nd3xRoute = Posts1nd3xImport.update({ +const Posts1nd3xRoute = Posts1nd3xRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsR0ut3Route, } as any) -const Blog1nd3xRoute = Blog1nd3xImport.update({ +const Blog1nd3xRoute = Blog1nd3xRouteImport.update({ id: '/', path: '/', getParentRoute: () => BlogR0ut3Route, } as any) -const BlogSlugRoute = BlogSlugImport.update({ +const BlogSlugRoute = BlogSlugRouteImport.update({ id: '/$slug', path: '/$slug', getParentRoute: () => BlogR0ut3Route, } as any) -const PostsPostId1nd3xRoute = PostsPostId1nd3xImport.update({ +const PostsPostId1nd3xRoute = PostsPostId1nd3xRouteImport.update({ id: '/$postId/', path: '/$postId/', getParentRoute: () => PostsR0ut3Route, } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/$postId/deep', path: '/$postId/deep', getParentRoute: () => PostsR0ut3Route, @@ -78,61 +80,136 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof R1nd3xImport + preLoaderRoute: typeof R1nd3xRouteImport parentRoute: typeof rootRoute } '/blog': { id: '/blog' path: '/blog' fullPath: '/blog' - preLoaderRoute: typeof BlogR0ut3Import + preLoaderRoute: typeof BlogR0ut3RouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsR0ut3Import + preLoaderRoute: typeof PostsR0ut3RouteImport parentRoute: typeof rootRoute } '/blog/$slug': { id: '/blog/$slug' path: '/$slug' fullPath: '/blog/$slug' - preLoaderRoute: typeof BlogSlugImport - parentRoute: typeof BlogR0ut3Import + preLoaderRoute: typeof BlogSlugRouteImport + parentRoute: typeof BlogR0ut3RouteImport } '/blog/': { id: '/blog/' path: '/' fullPath: '/blog/' - preLoaderRoute: typeof Blog1nd3xImport - parentRoute: typeof BlogR0ut3Import + preLoaderRoute: typeof Blog1nd3xRouteImport + parentRoute: typeof BlogR0ut3RouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof Posts1nd3xImport - parentRoute: typeof PostsR0ut3Import + preLoaderRoute: typeof Posts1nd3xRouteImport + parentRoute: typeof PostsR0ut3RouteImport } '/posts/$postId/deep': { id: '/posts/$postId/deep' path: '/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport - parentRoute: typeof PostsR0ut3Import + preLoaderRoute: typeof PostsPostIdDeepRouteImport + parentRoute: typeof PostsR0ut3RouteImport } '/posts/$postId/': { id: '/posts/$postId/' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostId1nd3xImport - parentRoute: typeof PostsR0ut3Import + preLoaderRoute: typeof PostsPostId1nd3xRouteImport + parentRoute: typeof PostsR0ut3RouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/_1nd3x' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/blog/_r0ut3_' { + const createFileRoute: CreateFileRoute< + '/blog', + FileRoutesByPath['/blog']['parentRoute'], + FileRoutesByPath['/blog']['id'], + FileRoutesByPath['/blog']['path'], + FileRoutesByPath['/blog']['fullPath'] + > +} +declare module './routes/posts/_r0ut3_' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/blog/$slug' { + const createFileRoute: CreateFileRoute< + '/blog/$slug', + FileRoutesByPath['/blog/$slug']['parentRoute'], + FileRoutesByPath['/blog/$slug']['id'], + FileRoutesByPath['/blog/$slug']['path'], + FileRoutesByPath['/blog/$slug']['fullPath'] + > +} +declare module './routes/blog/_1nd3x' { + const createFileRoute: CreateFileRoute< + '/blog/', + FileRoutesByPath['/blog/']['parentRoute'], + FileRoutesByPath['/blog/']['id'], + FileRoutesByPath['/blog/']['path'], + FileRoutesByPath['/blog/']['fullPath'] + > +} +declare module './routes/posts/_1nd3x' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/posts/$postId/deep' { + const createFileRoute: CreateFileRoute< + '/posts/$postId/deep', + FileRoutesByPath['/posts/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts/$postId/deep']['id'], + FileRoutesByPath['/posts/$postId/deep']['path'], + FileRoutesByPath['/posts/$postId/deep']['fullPath'] + > +} +declare module './routes/posts/$postId/_1nd3x' { + const createFileRoute: CreateFileRoute< + '/posts/$postId/', + FileRoutesByPath['/posts/$postId/']['parentRoute'], + FileRoutesByPath['/posts/$postId/']['id'], + FileRoutesByPath['/posts/$postId/']['path'], + FileRoutesByPath['/posts/$postId/']['fullPath'] + > +} + // Create and export the route tree interface BlogR0ut3RouteChildren { diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/_1nd3x.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/_1nd3x.tsx index a680913ded..22cab82307 100644 --- a/packages/router-generator/tests/generator/custom-tokens/routes/_1nd3x.tsx +++ b/packages/router-generator/tests/generator/custom-tokens/routes/_1nd3x.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: () =>
Hello /!
, }) diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/blog/$slug.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/blog/$slug.tsx index 0389370c39..784c2b78ae 100644 --- a/packages/router-generator/tests/generator/custom-tokens/routes/blog/$slug.tsx +++ b/packages/router-generator/tests/generator/custom-tokens/routes/blog/$slug.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/blog/$slug')({ +export const Route = createFileRoute({ component: () =>
Hello /blog/$slug!
, }) diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/blog/_1nd3x.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/blog/_1nd3x.tsx index 6fab51efb1..0754024ed7 100644 --- a/packages/router-generator/tests/generator/custom-tokens/routes/blog/_1nd3x.tsx +++ b/packages/router-generator/tests/generator/custom-tokens/routes/blog/_1nd3x.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/blog/')({ +export const Route = createFileRoute({ component: () =>
Hello /blog/!
, }) diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/blog/_r0ut3_.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/blog/_r0ut3_.tsx index 2833fcc588..ea94edad49 100644 --- a/packages/router-generator/tests/generator/custom-tokens/routes/blog/_r0ut3_.tsx +++ b/packages/router-generator/tests/generator/custom-tokens/routes/blog/_r0ut3_.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/blog')({ +export const Route = createFileRoute({ component: () =>
Hello /blog!
, }) diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/_1nd3x.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/_1nd3x.tsx index 3b2884f8aa..79316e21bb 100644 --- a/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/_1nd3x.tsx +++ b/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/_1nd3x.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/$postId/')({ +export const Route = createFileRoute({ component: () =>
Hello /posts/$postId/!
, }) diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/deep.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/deep.tsx index 0e0463301d..68ba9095e1 100644 --- a/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/deep.tsx +++ b/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/deep.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/$postId/deep')({ +export const Route = createFileRoute({ component: () =>
Hello /posts/$postId/deep!
, }) diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/posts/_1nd3x.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/posts/_1nd3x.tsx index f3c995416c..2e16af1ca1 100644 --- a/packages/router-generator/tests/generator/custom-tokens/routes/posts/_1nd3x.tsx +++ b/packages/router-generator/tests/generator/custom-tokens/routes/posts/_1nd3x.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: () =>
Hello /posts/!
, }) diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/posts/_r0ut3_.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/posts/_r0ut3_.tsx index c298ab4675..3617558181 100644 --- a/packages/router-generator/tests/generator/custom-tokens/routes/posts/_r0ut3_.tsx +++ b/packages/router-generator/tests/generator/custom-tokens/routes/posts/_r0ut3_.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ component: () =>
Hello /posts!
, }) diff --git a/packages/router-generator/tests/generator/dot-escaped/routeTree.snapshot.ts b/packages/router-generator/tests/generator/dot-escaped/routeTree.snapshot.ts new file mode 100644 index 0000000000..52636fca80 --- /dev/null +++ b/packages/router-generator/tests/generator/dot-escaped/routeTree.snapshot.ts @@ -0,0 +1,226 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + +// Import Routes + +import { Route as rootRoute } from './routes/__root' +import { Route as ScriptDotjsRouteImport } from './routes/script[.]js' +import { Route as NestedDotjsRouteImport } from './routes/nested[.]js' +import { Route as NestedDotjsScriptDotjsRouteImport } from './routes/nested[.]js.script[.]js' +import { Route as NestedDotjsDoubleDotextDotjsRouteImport } from './routes/nested[.]js.double[.]ext[.]js' + +// Create/Update Routes + +const ScriptDotjsRoute = ScriptDotjsRouteImport.update({ + id: '/script.js', + path: '/script.js', + getParentRoute: () => rootRoute, +} as any) + +const NestedDotjsRoute = NestedDotjsRouteImport.update({ + id: '/nested.js', + path: '/nested.js', + getParentRoute: () => rootRoute, +} as any) + +const NestedDotjsScriptDotjsRoute = NestedDotjsScriptDotjsRouteImport.update({ + id: '/script.js', + path: '/script.js', + getParentRoute: () => NestedDotjsRoute, +} as any) + +const NestedDotjsDoubleDotextDotjsRoute = + NestedDotjsDoubleDotextDotjsRouteImport.update({ + id: '/double.ext.js', + path: '/double.ext.js', + getParentRoute: () => NestedDotjsRoute, + } as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/nested.js': { + id: '/nested.js' + path: '/nested.js' + fullPath: '/nested.js' + preLoaderRoute: typeof NestedDotjsRouteImport + parentRoute: typeof rootRoute + } + '/script.js': { + id: '/script.js' + path: '/script.js' + fullPath: '/script.js' + preLoaderRoute: typeof ScriptDotjsRouteImport + parentRoute: typeof rootRoute + } + '/nested.js/double.ext.js': { + id: '/nested.js/double.ext.js' + path: '/double.ext.js' + fullPath: '/nested.js/double.ext.js' + preLoaderRoute: typeof NestedDotjsDoubleDotextDotjsRouteImport + parentRoute: typeof NestedDotjsRouteImport + } + '/nested.js/script.js': { + id: '/nested.js/script.js' + path: '/script.js' + fullPath: '/nested.js/script.js' + preLoaderRoute: typeof NestedDotjsScriptDotjsRouteImport + parentRoute: typeof NestedDotjsRouteImport + } + } +} + +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/nested[.]js' { + const createFileRoute: CreateFileRoute< + '/nested.js', + FileRoutesByPath['/nested.js']['parentRoute'], + FileRoutesByPath['/nested.js']['id'], + FileRoutesByPath['/nested.js']['path'], + FileRoutesByPath['/nested.js']['fullPath'] + > +} +declare module './routes/script[.]js' { + const createFileRoute: CreateFileRoute< + '/script.js', + FileRoutesByPath['/script.js']['parentRoute'], + FileRoutesByPath['/script.js']['id'], + FileRoutesByPath['/script.js']['path'], + FileRoutesByPath['/script.js']['fullPath'] + > +} +declare module './routes/nested[.]js.double[.]ext[.]js' { + const createFileRoute: CreateFileRoute< + '/nested.js/double.ext.js', + FileRoutesByPath['/nested.js/double.ext.js']['parentRoute'], + FileRoutesByPath['/nested.js/double.ext.js']['id'], + FileRoutesByPath['/nested.js/double.ext.js']['path'], + FileRoutesByPath['/nested.js/double.ext.js']['fullPath'] + > +} +declare module './routes/nested[.]js.script[.]js' { + const createFileRoute: CreateFileRoute< + '/nested.js/script.js', + FileRoutesByPath['/nested.js/script.js']['parentRoute'], + FileRoutesByPath['/nested.js/script.js']['id'], + FileRoutesByPath['/nested.js/script.js']['path'], + FileRoutesByPath['/nested.js/script.js']['fullPath'] + > +} + +// Create and export the route tree + +interface NestedDotjsRouteChildren { + NestedDotjsDoubleDotextDotjsRoute: typeof NestedDotjsDoubleDotextDotjsRoute + NestedDotjsScriptDotjsRoute: typeof NestedDotjsScriptDotjsRoute +} + +const NestedDotjsRouteChildren: NestedDotjsRouteChildren = { + NestedDotjsDoubleDotextDotjsRoute: NestedDotjsDoubleDotextDotjsRoute, + NestedDotjsScriptDotjsRoute: NestedDotjsScriptDotjsRoute, +} + +const NestedDotjsRouteWithChildren = NestedDotjsRoute._addFileChildren( + NestedDotjsRouteChildren, +) + +export interface FileRoutesByFullPath { + '/nested.js': typeof NestedDotjsRouteWithChildren + '/script.js': typeof ScriptDotjsRoute + '/nested.js/double.ext.js': typeof NestedDotjsDoubleDotextDotjsRoute + '/nested.js/script.js': typeof NestedDotjsScriptDotjsRoute +} + +export interface FileRoutesByTo { + '/nested.js': typeof NestedDotjsRouteWithChildren + '/script.js': typeof ScriptDotjsRoute + '/nested.js/double.ext.js': typeof NestedDotjsDoubleDotextDotjsRoute + '/nested.js/script.js': typeof NestedDotjsScriptDotjsRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/nested.js': typeof NestedDotjsRouteWithChildren + '/script.js': typeof ScriptDotjsRoute + '/nested.js/double.ext.js': typeof NestedDotjsDoubleDotextDotjsRoute + '/nested.js/script.js': typeof NestedDotjsScriptDotjsRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/nested.js' + | '/script.js' + | '/nested.js/double.ext.js' + | '/nested.js/script.js' + fileRoutesByTo: FileRoutesByTo + to: + | '/nested.js' + | '/script.js' + | '/nested.js/double.ext.js' + | '/nested.js/script.js' + id: + | '__root__' + | '/nested.js' + | '/script.js' + | '/nested.js/double.ext.js' + | '/nested.js/script.js' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + NestedDotjsRoute: typeof NestedDotjsRouteWithChildren + ScriptDotjsRoute: typeof ScriptDotjsRoute +} + +const rootRouteChildren: RootRouteChildren = { + NestedDotjsRoute: NestedDotjsRouteWithChildren, + ScriptDotjsRoute: ScriptDotjsRoute, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/nested.js", + "/script.js" + ] + }, + "/nested.js": { + "filePath": "nested[.]js.tsx", + "children": [ + "/nested.js/double.ext.js", + "/nested.js/script.js" + ] + }, + "/script.js": { + "filePath": "script[.]js.tsx" + }, + "/nested.js/double.ext.js": { + "filePath": "nested[.]js.double[.]ext[.]js.tsx", + "parent": "/nested.js" + }, + "/nested.js/script.js": { + "filePath": "nested[.]js.script[.]js.tsx", + "parent": "/nested.js" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/packages/router-generator/tests/generator/dot-escaped/routes/__root.tsx b/packages/router-generator/tests/generator/dot-escaped/routes/__root.tsx new file mode 100644 index 0000000000..ab504e42e9 --- /dev/null +++ b/packages/router-generator/tests/generator/dot-escaped/routes/__root.tsx @@ -0,0 +1 @@ +/** */ diff --git a/packages/router-generator/tests/generator/dot-escaped/routes/nested[.]js.double[.]ext[.]js.tsx b/packages/router-generator/tests/generator/dot-escaped/routes/nested[.]js.double[.]ext[.]js.tsx new file mode 100644 index 0000000000..a8c4d4c893 --- /dev/null +++ b/packages/router-generator/tests/generator/dot-escaped/routes/nested[.]js.double[.]ext[.]js.tsx @@ -0,0 +1,2 @@ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/dot-escaped/routes/nested[.]js.script[.]js.tsx b/packages/router-generator/tests/generator/dot-escaped/routes/nested[.]js.script[.]js.tsx new file mode 100644 index 0000000000..a8c4d4c893 --- /dev/null +++ b/packages/router-generator/tests/generator/dot-escaped/routes/nested[.]js.script[.]js.tsx @@ -0,0 +1,2 @@ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/dot-escaped/routes/nested[.]js.tsx b/packages/router-generator/tests/generator/dot-escaped/routes/nested[.]js.tsx new file mode 100644 index 0000000000..a8c4d4c893 --- /dev/null +++ b/packages/router-generator/tests/generator/dot-escaped/routes/nested[.]js.tsx @@ -0,0 +1,2 @@ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/dot-escaped/routes/script[.]js.tsx b/packages/router-generator/tests/generator/dot-escaped/routes/script[.]js.tsx new file mode 100644 index 0000000000..a8c4d4c893 --- /dev/null +++ b/packages/router-generator/tests/generator/dot-escaped/routes/script[.]js.tsx @@ -0,0 +1,2 @@ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/duplicate-fullPath/routes/_auth/index.tsx b/packages/router-generator/tests/generator/duplicate-fullPath/routes/_auth/index.tsx index 56b2ebca76..47d07771d4 100644 --- a/packages/router-generator/tests/generator/duplicate-fullPath/routes/_auth/index.tsx +++ b/packages/router-generator/tests/generator/duplicate-fullPath/routes/_auth/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_auth/')({ +export const Route = createFileRoute({ component: () =>
Hello /_auth/!
, }) diff --git a/packages/router-generator/tests/generator/duplicate-fullPath/routes/index.tsx b/packages/router-generator/tests/generator/duplicate-fullPath/routes/index.tsx index a680913ded..22cab82307 100644 --- a/packages/router-generator/tests/generator/duplicate-fullPath/routes/index.tsx +++ b/packages/router-generator/tests/generator/duplicate-fullPath/routes/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: () =>
Hello /!
, }) diff --git a/packages/router-generator/tests/generator/file-modification/post.$postId.tsx b/packages/router-generator/tests/generator/file-modification/post.$postId.tsx index b51b2f5ad4..790146adf0 100644 --- a/packages/router-generator/tests/generator/file-modification/post.$postId.tsx +++ b/packages/router-generator/tests/generator/file-modification/post.$postId.tsx @@ -36,7 +36,7 @@ function PostComponent() { postId: post.id, }} activeProps={{ className: 'text-black font-bold' }} - className="block py-1 text-blue-800 hover:text-blue-600" + className="inline-block py-1 text-blue-800 hover:text-blue-600" > Deep View diff --git a/packages/router-generator/tests/generator/file-modification/routeTree.snapshot.ts b/packages/router-generator/tests/generator/file-modification/routeTree.snapshot.ts index f42e1f086f..6538af0694 100644 --- a/packages/router-generator/tests/generator/file-modification/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/file-modification/routeTree.snapshot.ts @@ -9,21 +9,26 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { createFileRoute } from '@tanstack/react-router' +import type { + CreateFileRoute, + CreateLazyFileRoute, + FileRoutesByPath, +} from '@tanstack/react-router' // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as testInitiallyLazyImport } from './routes/(test)/initiallyLazy' -import { Route as testInitiallyEmptyImport } from './routes/(test)/initiallyEmpty' -import { Route as testFooImport } from './routes/(test)/foo' +import { Route as testInitiallyLazyRouteImport } from './routes/(test)/initiallyLazy' +import { Route as testInitiallyEmptyRouteImport } from './routes/(test)/initiallyEmpty' +import { Route as testFooRouteImport } from './routes/(test)/foo' // Create Virtual Routes -const testBarLazyImport = createFileRoute('/(test)/bar')() +const testBarLazyRouteImport = createFileRoute('/(test)/bar')() // Create/Update Routes -const testBarLazyRoute = testBarLazyImport +const testBarLazyRoute = testBarLazyRouteImport .update({ id: '/(test)/bar', path: '/bar', @@ -31,13 +36,13 @@ const testBarLazyRoute = testBarLazyImport } as any) .lazy(() => import('./routes/(test)/bar.lazy').then((d) => d.Route)) -const testInitiallyLazyRoute = testInitiallyLazyImport.update({ +const testInitiallyLazyRoute = testInitiallyLazyRouteImport.update({ id: '/(test)/initiallyLazy', path: '/initiallyLazy', getParentRoute: () => rootRoute, } as any) -const testInitiallyEmptyRoute = testInitiallyEmptyImport +const testInitiallyEmptyRoute = testInitiallyEmptyRouteImport .update({ id: '/(test)/initiallyEmpty', path: '/initiallyEmpty', @@ -47,7 +52,7 @@ const testInitiallyEmptyRoute = testInitiallyEmptyImport import('./routes/(test)/initiallyEmpty.lazy').then((d) => d.Route), ) -const testFooRoute = testFooImport.update({ +const testFooRoute = testFooRouteImport.update({ id: '/(test)/foo', path: '/foo', getParentRoute: () => rootRoute, @@ -61,33 +66,73 @@ declare module '@tanstack/react-router' { id: '/(test)/foo' path: '/foo' fullPath: '/foo' - preLoaderRoute: typeof testFooImport + preLoaderRoute: typeof testFooRouteImport parentRoute: typeof rootRoute } '/(test)/initiallyEmpty': { id: '/(test)/initiallyEmpty' path: '/initiallyEmpty' fullPath: '/initiallyEmpty' - preLoaderRoute: typeof testInitiallyEmptyImport + preLoaderRoute: typeof testInitiallyEmptyRouteImport parentRoute: typeof rootRoute } '/(test)/initiallyLazy': { id: '/(test)/initiallyLazy' path: '/initiallyLazy' fullPath: '/initiallyLazy' - preLoaderRoute: typeof testInitiallyLazyImport + preLoaderRoute: typeof testInitiallyLazyRouteImport parentRoute: typeof rootRoute } '/(test)/bar': { id: '/(test)/bar' path: '/bar' fullPath: '/bar' - preLoaderRoute: typeof testBarLazyImport + preLoaderRoute: typeof testBarLazyRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/(test)/foo' { + const createFileRoute: CreateFileRoute< + '/(test)/foo', + FileRoutesByPath['/(test)/foo']['parentRoute'], + FileRoutesByPath['/(test)/foo']['id'], + FileRoutesByPath['/(test)/foo']['path'], + FileRoutesByPath['/(test)/foo']['fullPath'] + > +} +declare module './routes/(test)/initiallyEmpty' { + const createFileRoute: CreateFileRoute< + '/(test)/initiallyEmpty', + FileRoutesByPath['/(test)/initiallyEmpty']['parentRoute'], + FileRoutesByPath['/(test)/initiallyEmpty']['id'], + FileRoutesByPath['/(test)/initiallyEmpty']['path'], + FileRoutesByPath['/(test)/initiallyEmpty']['fullPath'] + > +} +declare module './routes/(test)/initiallyEmpty.lazy' { + const createLazyFileRoute: CreateLazyFileRoute< + FileRoutesByPath['/(test)/initiallyEmpty']['preLoaderRoute'] + > +} +declare module './routes/(test)/initiallyLazy' { + const createFileRoute: CreateFileRoute< + '/(test)/initiallyLazy', + FileRoutesByPath['/(test)/initiallyLazy']['parentRoute'], + FileRoutesByPath['/(test)/initiallyLazy']['id'], + FileRoutesByPath['/(test)/initiallyLazy']['path'], + FileRoutesByPath['/(test)/initiallyLazy']['fullPath'] + > +} +declare module './routes/(test)/bar.lazy' { + const createLazyFileRoute: CreateLazyFileRoute< + FileRoutesByPath['/(test)/bar']['preLoaderRoute'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/packages/router-generator/tests/generator/file-modification/snapshot/bar.lazy.tsx b/packages/router-generator/tests/generator/file-modification/snapshot/bar.lazy.tsx index d8a6feca9b..cf174606e1 100644 --- a/packages/router-generator/tests/generator/file-modification/snapshot/bar.lazy.tsx +++ b/packages/router-generator/tests/generator/file-modification/snapshot/bar.lazy.tsx @@ -5,10 +5,9 @@ import { ErrorComponent, ErrorComponentProps, Link, - createFileRoute, } from '@tanstack/react-router' -export const Route = createFileRoute('/(test)/foo')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => ({ postId, title: 'title', @@ -39,7 +38,7 @@ function PostComponent() { postId: post.id, }} activeProps={{ className: 'text-black font-bold' }} - className="block py-1 text-blue-800 hover:text-blue-600" + className="inline-block py-1 text-blue-800 hover:text-blue-600" > Deep View diff --git a/packages/router-generator/tests/generator/file-modification/snapshot/foo.tsx b/packages/router-generator/tests/generator/file-modification/snapshot/foo.tsx index d8a6feca9b..cf174606e1 100644 --- a/packages/router-generator/tests/generator/file-modification/snapshot/foo.tsx +++ b/packages/router-generator/tests/generator/file-modification/snapshot/foo.tsx @@ -5,10 +5,9 @@ import { ErrorComponent, ErrorComponentProps, Link, - createFileRoute, } from '@tanstack/react-router' -export const Route = createFileRoute('/(test)/foo')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => ({ postId, title: 'title', @@ -39,7 +38,7 @@ function PostComponent() { postId: post.id, }} activeProps={{ className: 'text-black font-bold' }} - className="block py-1 text-blue-800 hover:text-blue-600" + className="inline-block py-1 text-blue-800 hover:text-blue-600" > Deep View diff --git a/packages/router-generator/tests/generator/file-modification/snapshot/initiallyEmpty.lazy.tsx b/packages/router-generator/tests/generator/file-modification/snapshot/initiallyEmpty.lazy.tsx index d8a6feca9b..cf174606e1 100644 --- a/packages/router-generator/tests/generator/file-modification/snapshot/initiallyEmpty.lazy.tsx +++ b/packages/router-generator/tests/generator/file-modification/snapshot/initiallyEmpty.lazy.tsx @@ -5,10 +5,9 @@ import { ErrorComponent, ErrorComponentProps, Link, - createFileRoute, } from '@tanstack/react-router' -export const Route = createFileRoute('/(test)/foo')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => ({ postId, title: 'title', @@ -39,7 +38,7 @@ function PostComponent() { postId: post.id, }} activeProps={{ className: 'text-black font-bold' }} - className="block py-1 text-blue-800 hover:text-blue-600" + className="inline-block py-1 text-blue-800 hover:text-blue-600" > Deep View diff --git a/packages/router-generator/tests/generator/file-modification/snapshot/initiallyEmpty.tsx b/packages/router-generator/tests/generator/file-modification/snapshot/initiallyEmpty.tsx index d8a6feca9b..cf174606e1 100644 --- a/packages/router-generator/tests/generator/file-modification/snapshot/initiallyEmpty.tsx +++ b/packages/router-generator/tests/generator/file-modification/snapshot/initiallyEmpty.tsx @@ -5,10 +5,9 @@ import { ErrorComponent, ErrorComponentProps, Link, - createFileRoute, } from '@tanstack/react-router' -export const Route = createFileRoute('/(test)/foo')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => ({ postId, title: 'title', @@ -39,7 +38,7 @@ function PostComponent() { postId: post.id, }} activeProps={{ className: 'text-black font-bold' }} - className="block py-1 text-blue-800 hover:text-blue-600" + className="inline-block py-1 text-blue-800 hover:text-blue-600" > Deep View diff --git a/packages/router-generator/tests/generator/file-modification/snapshot/initiallyLazy.tsx b/packages/router-generator/tests/generator/file-modification/snapshot/initiallyLazy.tsx index d8a6feca9b..cf174606e1 100644 --- a/packages/router-generator/tests/generator/file-modification/snapshot/initiallyLazy.tsx +++ b/packages/router-generator/tests/generator/file-modification/snapshot/initiallyLazy.tsx @@ -5,10 +5,9 @@ import { ErrorComponent, ErrorComponentProps, Link, - createFileRoute, } from '@tanstack/react-router' -export const Route = createFileRoute('/(test)/foo')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => ({ postId, title: 'title', @@ -39,7 +38,7 @@ function PostComponent() { postId: post.id, }} activeProps={{ className: 'text-black font-bold' }} - className="block py-1 text-blue-800 hover:text-blue-600" + className="inline-block py-1 text-blue-800 hover:text-blue-600" > Deep View diff --git a/packages/router-generator/tests/generator/file-modification/template.lazy.tsx b/packages/router-generator/tests/generator/file-modification/template.lazy.tsx index 76dc2c74c3..45a3d5871f 100644 --- a/packages/router-generator/tests/generator/file-modification/template.lazy.tsx +++ b/packages/router-generator/tests/generator/file-modification/template.lazy.tsx @@ -2,7 +2,7 @@ import { createLazyFileRoute, Link } from '@tanstack/react-router' -export const Route = createLazyFileRoute('/(test)/lazy')({ +export const Route = createLazyFileRoute({ component: () => { const post = Route.useLoaderData() diff --git a/packages/router-generator/tests/generator/file-modification/template.tsx b/packages/router-generator/tests/generator/file-modification/template.tsx index 918119d3f0..cf174606e1 100644 --- a/packages/router-generator/tests/generator/file-modification/template.tsx +++ b/packages/router-generator/tests/generator/file-modification/template.tsx @@ -5,10 +5,9 @@ import { ErrorComponent, ErrorComponentProps, Link, - createFileRoute, } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => ({ postId, title: 'title', @@ -39,7 +38,7 @@ function PostComponent() { postId: post.id, }} activeProps={{ className: 'text-black font-bold' }} - className="block py-1 text-blue-800 hover:text-blue-600" + className="inline-block py-1 text-blue-800 hover:text-blue-600" > Deep View diff --git a/packages/router-generator/tests/generator/flat/routeTree.snapshot.ts b/packages/router-generator/tests/generator/flat/routeTree.snapshot.ts index 50840b912e..e4019aaade 100644 --- a/packages/router-generator/tests/generator/flat/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/flat/routeTree.snapshot.ts @@ -8,70 +8,72 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PostsRouteImport } from './routes/posts.route' -import { Route as BlogRouteImport } from './routes/blog.route' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as BlogIndexImport } from './routes/blog.index' -import { Route as BlogStatsImport } from './routes/blog_.stats' -import { Route as PostsPostIdIndexImport } from './routes/posts.$postId.index' -import { Route as BlogSlugIndexImport } from './routes/blog.$slug.index' -import { Route as PostsPostIdDeepImport } from './routes/posts.$postId.deep' +import { Route as PostsRouteRouteImport } from './routes/posts.route' +import { Route as BlogRouteRouteImport } from './routes/blog.route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as BlogIndexRouteImport } from './routes/blog.index' +import { Route as BlogStatsRouteImport } from './routes/blog_.stats' +import { Route as PostsPostIdIndexRouteImport } from './routes/posts.$postId.index' +import { Route as BlogSlugIndexRouteImport } from './routes/blog.$slug.index' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts.$postId.deep' // Create/Update Routes -const PostsRouteRoute = PostsRouteImport.update({ +const PostsRouteRoute = PostsRouteRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const BlogRouteRoute = BlogRouteImport.update({ +const BlogRouteRoute = BlogRouteRouteImport.update({ id: '/blog', path: '/blog', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRouteRoute, } as any) -const BlogIndexRoute = BlogIndexImport.update({ +const BlogIndexRoute = BlogIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => BlogRouteRoute, } as any) -const BlogStatsRoute = BlogStatsImport.update({ +const BlogStatsRoute = BlogStatsRouteImport.update({ id: '/blog_/stats', path: '/blog/stats', getParentRoute: () => rootRoute, } as any) -const PostsPostIdIndexRoute = PostsPostIdIndexImport.update({ +const PostsPostIdIndexRoute = PostsPostIdIndexRouteImport.update({ id: '/$postId/', path: '/$postId/', getParentRoute: () => PostsRouteRoute, } as any) -const BlogSlugIndexRoute = BlogSlugIndexImport.update({ +const BlogSlugIndexRoute = BlogSlugIndexRouteImport.update({ id: '/$slug/', path: '/$slug/', getParentRoute: () => BlogRouteRoute, } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/$postId/deep', path: '/$postId/deep', getParentRoute: () => PostsRouteRoute, @@ -85,68 +87,152 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/blog': { id: '/blog' path: '/blog' fullPath: '/blog' - preLoaderRoute: typeof BlogRouteImport + preLoaderRoute: typeof BlogRouteRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsRouteRouteImport parentRoute: typeof rootRoute } '/blog_/stats': { id: '/blog_/stats' path: '/blog/stats' fullPath: '/blog/stats' - preLoaderRoute: typeof BlogStatsImport + preLoaderRoute: typeof BlogStatsRouteImport parentRoute: typeof rootRoute } '/blog/': { id: '/blog/' path: '/' fullPath: '/blog/' - preLoaderRoute: typeof BlogIndexImport - parentRoute: typeof BlogRouteImport + preLoaderRoute: typeof BlogIndexRouteImport + parentRoute: typeof BlogRouteRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteRouteImport } '/posts/$postId/deep': { id: '/posts/$postId/deep' path: '/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsPostIdDeepRouteImport + parentRoute: typeof PostsRouteRouteImport } '/blog/$slug/': { id: '/blog/$slug/' path: '/$slug' fullPath: '/blog/$slug' - preLoaderRoute: typeof BlogSlugIndexImport - parentRoute: typeof BlogRouteImport + preLoaderRoute: typeof BlogSlugIndexRouteImport + parentRoute: typeof BlogRouteRouteImport } '/posts/$postId/': { id: '/posts/$postId/' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdIndexImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsPostIdIndexRouteImport + parentRoute: typeof PostsRouteRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/blog.route' { + const createFileRoute: CreateFileRoute< + '/blog', + FileRoutesByPath['/blog']['parentRoute'], + FileRoutesByPath['/blog']['id'], + FileRoutesByPath['/blog']['path'], + FileRoutesByPath['/blog']['fullPath'] + > +} +declare module './routes/posts.route' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/blog_.stats' { + const createFileRoute: CreateFileRoute< + '/blog_/stats', + FileRoutesByPath['/blog_/stats']['parentRoute'], + FileRoutesByPath['/blog_/stats']['id'], + FileRoutesByPath['/blog_/stats']['path'], + FileRoutesByPath['/blog_/stats']['fullPath'] + > +} +declare module './routes/blog.index' { + const createFileRoute: CreateFileRoute< + '/blog/', + FileRoutesByPath['/blog/']['parentRoute'], + FileRoutesByPath['/blog/']['id'], + FileRoutesByPath['/blog/']['path'], + FileRoutesByPath['/blog/']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/posts.$postId.deep' { + const createFileRoute: CreateFileRoute< + '/posts/$postId/deep', + FileRoutesByPath['/posts/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts/$postId/deep']['id'], + FileRoutesByPath['/posts/$postId/deep']['path'], + FileRoutesByPath['/posts/$postId/deep']['fullPath'] + > +} +declare module './routes/blog.$slug.index' { + const createFileRoute: CreateFileRoute< + '/blog/$slug/', + FileRoutesByPath['/blog/$slug/']['parentRoute'], + FileRoutesByPath['/blog/$slug/']['id'], + FileRoutesByPath['/blog/$slug/']['path'], + FileRoutesByPath['/blog/$slug/']['fullPath'] + > +} +declare module './routes/posts.$postId.index' { + const createFileRoute: CreateFileRoute< + '/posts/$postId/', + FileRoutesByPath['/posts/$postId/']['parentRoute'], + FileRoutesByPath['/posts/$postId/']['id'], + FileRoutesByPath['/posts/$postId/']['path'], + FileRoutesByPath['/posts/$postId/']['fullPath'] + > +} + // Create and export the route tree interface BlogRouteRouteChildren { diff --git a/packages/router-generator/tests/generator/flat/routes/__root.tsx b/packages/router-generator/tests/generator/flat/routes/__root.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/flat/routes/__root.tsx +++ b/packages/router-generator/tests/generator/flat/routes/__root.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/flat/routes/blog.$slug.index.tsx b/packages/router-generator/tests/generator/flat/routes/blog.$slug.index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/flat/routes/blog.$slug.index.tsx +++ b/packages/router-generator/tests/generator/flat/routes/blog.$slug.index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/flat/routes/blog.index.tsx b/packages/router-generator/tests/generator/flat/routes/blog.index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/flat/routes/blog.index.tsx +++ b/packages/router-generator/tests/generator/flat/routes/blog.index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/flat/routes/blog.route.tsx b/packages/router-generator/tests/generator/flat/routes/blog.route.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/flat/routes/blog.route.tsx +++ b/packages/router-generator/tests/generator/flat/routes/blog.route.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/flat/routes/blog_.stats.tsx b/packages/router-generator/tests/generator/flat/routes/blog_.stats.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/flat/routes/blog_.stats.tsx +++ b/packages/router-generator/tests/generator/flat/routes/blog_.stats.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/flat/routes/index.tsx b/packages/router-generator/tests/generator/flat/routes/index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/flat/routes/index.tsx +++ b/packages/router-generator/tests/generator/flat/routes/index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/flat/routes/posts.$postId.deep.tsx b/packages/router-generator/tests/generator/flat/routes/posts.$postId.deep.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/flat/routes/posts.$postId.deep.tsx +++ b/packages/router-generator/tests/generator/flat/routes/posts.$postId.deep.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/flat/routes/posts.$postId.index.tsx b/packages/router-generator/tests/generator/flat/routes/posts.$postId.index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/flat/routes/posts.$postId.index.tsx +++ b/packages/router-generator/tests/generator/flat/routes/posts.$postId.index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/flat/routes/posts.index.tsx b/packages/router-generator/tests/generator/flat/routes/posts.index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/flat/routes/posts.index.tsx +++ b/packages/router-generator/tests/generator/flat/routes/posts.index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/flat/routes/posts.route.tsx b/packages/router-generator/tests/generator/flat/routes/posts.route.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/flat/routes/posts.route.tsx +++ b/packages/router-generator/tests/generator/flat/routes/posts.route.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts b/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts index 51095a9fea..f63b7e3a1b 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts @@ -9,181 +9,184 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { createFileRoute } from '@tanstack/react-router' +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as LayoutA2Import } from './routes/_layout-a2' -import { Route as LayoutA1Import } from './routes/_layout-a1' -import { Route as JestedRouteImport } from './routes/jested/route' -import { Route as IndexImport } from './routes/index' -import { Route as NestedLayoutB2Import } from './routes/nested/_layout-b2' -import { Route as NestedLayoutB1Import } from './routes/nested/_layout-b1' -import { Route as JestedLayoutB4Import } from './routes/jested/_layout-b4' -import { Route as JestedLayoutB3Import } from './routes/jested/_layout-b3' -import { Route as FooBarImport } from './routes/foo/bar' -import { Route as LayoutA2BarImport } from './routes/_layout-a2/bar' -import { Route as LayoutA1FooImport } from './routes/_layout-a1/foo' -import { Route as folderInFolderImport } from './routes/(folder)/in-folder' -import { Route as FooLayoutB5RouteImport } from './routes/foo/_layout-b5/route' -import { Route as NestedLayoutB1IndexImport } from './routes/nested/_layout-b1/index' -import { Route as JestedLayoutB3IndexImport } from './routes/jested/_layout-b3/index' -import { Route as FooLayoutB5IndexImport } from './routes/foo/_layout-b5/index' -import { Route as NestedLayoutB2FooImport } from './routes/nested/_layout-b2/foo' -import { Route as NestedLayoutB1LayoutC1Import } from './routes/nested/_layout-b1/_layout-c1' -import { Route as JestedLayoutB4FooImport } from './routes/jested/_layout-b4/foo' -import { Route as JestedLayoutB3LayoutC2Import } from './routes/jested/_layout-b3/_layout-c2' -import { Route as FooLayoutB5IdImport } from './routes/foo/_layout-b5/$id' -import { Route as NestedLayoutB1LayoutC1BarImport } from './routes/nested/_layout-b1/_layout-c1/bar' -import { Route as JestedLayoutB3LayoutC2BarImport } from './routes/jested/_layout-b3/_layout-c2/bar' +import { Route as LayoutA2RouteImport } from './routes/_layout-a2' +import { Route as LayoutA1RouteImport } from './routes/_layout-a1' +import { Route as JestedRouteRouteImport } from './routes/jested/route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as NestedLayoutB2RouteImport } from './routes/nested/_layout-b2' +import { Route as NestedLayoutB1RouteImport } from './routes/nested/_layout-b1' +import { Route as JestedLayoutB4RouteImport } from './routes/jested/_layout-b4' +import { Route as JestedLayoutB3RouteImport } from './routes/jested/_layout-b3' +import { Route as FooBarRouteImport } from './routes/foo/bar' +import { Route as LayoutA2BarRouteImport } from './routes/_layout-a2/bar' +import { Route as LayoutA1FooRouteImport } from './routes/_layout-a1/foo' +import { Route as folderInFolderRouteImport } from './routes/(folder)/in-folder' +import { Route as FooLayoutB5RouteRouteImport } from './routes/foo/_layout-b5/route' +import { Route as NestedLayoutB1IndexRouteImport } from './routes/nested/_layout-b1/index' +import { Route as JestedLayoutB3IndexRouteImport } from './routes/jested/_layout-b3/index' +import { Route as FooLayoutB5IndexRouteImport } from './routes/foo/_layout-b5/index' +import { Route as NestedLayoutB2FooRouteImport } from './routes/nested/_layout-b2/foo' +import { Route as NestedLayoutB1LayoutC1RouteImport } from './routes/nested/_layout-b1/_layout-c1' +import { Route as JestedLayoutB4FooRouteImport } from './routes/jested/_layout-b4/foo' +import { Route as JestedLayoutB3LayoutC2RouteImport } from './routes/jested/_layout-b3/_layout-c2' +import { Route as FooLayoutB5IdRouteImport } from './routes/foo/_layout-b5/$id' +import { Route as NestedLayoutB1LayoutC1BarRouteImport } from './routes/nested/_layout-b1/_layout-c1/bar' +import { Route as JestedLayoutB3LayoutC2BarRouteImport } from './routes/jested/_layout-b3/_layout-c2/bar' // Create Virtual Routes -const NestedImport = createFileRoute('/nested')() -const FooImport = createFileRoute('/foo')() +const NestedRouteImport = createFileRoute('/nested')() +const FooRouteImport = createFileRoute('/foo')() // Create/Update Routes -const NestedRoute = NestedImport.update({ +const NestedRoute = NestedRouteImport.update({ id: '/nested', path: '/nested', getParentRoute: () => rootRoute, } as any) -const FooRoute = FooImport.update({ +const FooRoute = FooRouteImport.update({ id: '/foo', path: '/foo', getParentRoute: () => rootRoute, } as any) -const LayoutA2Route = LayoutA2Import.update({ +const LayoutA2Route = LayoutA2RouteImport.update({ id: '/_layout-a2', getParentRoute: () => rootRoute, } as any) -const LayoutA1Route = LayoutA1Import.update({ +const LayoutA1Route = LayoutA1RouteImport.update({ id: '/_layout-a1', getParentRoute: () => rootRoute, } as any) -const JestedRouteRoute = JestedRouteImport.update({ +const JestedRouteRoute = JestedRouteRouteImport.update({ id: '/jested', path: '/jested', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const NestedLayoutB2Route = NestedLayoutB2Import.update({ +const NestedLayoutB2Route = NestedLayoutB2RouteImport.update({ id: '/_layout-b2', getParentRoute: () => NestedRoute, } as any) -const NestedLayoutB1Route = NestedLayoutB1Import.update({ +const NestedLayoutB1Route = NestedLayoutB1RouteImport.update({ id: '/_layout-b1', getParentRoute: () => NestedRoute, } as any) -const JestedLayoutB4Route = JestedLayoutB4Import.update({ +const JestedLayoutB4Route = JestedLayoutB4RouteImport.update({ id: '/_layout-b4', getParentRoute: () => JestedRouteRoute, } as any) -const JestedLayoutB3Route = JestedLayoutB3Import.update({ +const JestedLayoutB3Route = JestedLayoutB3RouteImport.update({ id: '/_layout-b3', getParentRoute: () => JestedRouteRoute, } as any) -const FooBarRoute = FooBarImport.update({ +const FooBarRoute = FooBarRouteImport.update({ id: '/bar', path: '/bar', getParentRoute: () => FooRoute, } as any) -const LayoutA2BarRoute = LayoutA2BarImport.update({ +const LayoutA2BarRoute = LayoutA2BarRouteImport.update({ id: '/bar', path: '/bar', getParentRoute: () => LayoutA2Route, } as any) -const LayoutA1FooRoute = LayoutA1FooImport.update({ +const LayoutA1FooRoute = LayoutA1FooRouteImport.update({ id: '/foo', path: '/foo', getParentRoute: () => LayoutA1Route, } as any) -const folderInFolderRoute = folderInFolderImport.update({ +const folderInFolderRoute = folderInFolderRouteImport.update({ id: '/(folder)/in-folder', path: '/in-folder', getParentRoute: () => rootRoute, } as any) -const FooLayoutB5RouteRoute = FooLayoutB5RouteImport.update({ +const FooLayoutB5RouteRoute = FooLayoutB5RouteRouteImport.update({ id: '/_layout-b5', getParentRoute: () => FooRoute, } as any) -const NestedLayoutB1IndexRoute = NestedLayoutB1IndexImport.update({ +const NestedLayoutB1IndexRoute = NestedLayoutB1IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => NestedLayoutB1Route, } as any) -const JestedLayoutB3IndexRoute = JestedLayoutB3IndexImport.update({ +const JestedLayoutB3IndexRoute = JestedLayoutB3IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => JestedLayoutB3Route, } as any) -const FooLayoutB5IndexRoute = FooLayoutB5IndexImport.update({ +const FooLayoutB5IndexRoute = FooLayoutB5IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => FooLayoutB5RouteRoute, } as any) -const NestedLayoutB2FooRoute = NestedLayoutB2FooImport.update({ +const NestedLayoutB2FooRoute = NestedLayoutB2FooRouteImport.update({ id: '/foo', path: '/foo', getParentRoute: () => NestedLayoutB2Route, } as any) -const NestedLayoutB1LayoutC1Route = NestedLayoutB1LayoutC1Import.update({ +const NestedLayoutB1LayoutC1Route = NestedLayoutB1LayoutC1RouteImport.update({ id: '/_layout-c1', getParentRoute: () => NestedLayoutB1Route, } as any) -const JestedLayoutB4FooRoute = JestedLayoutB4FooImport.update({ +const JestedLayoutB4FooRoute = JestedLayoutB4FooRouteImport.update({ id: '/foo', path: '/foo', getParentRoute: () => JestedLayoutB4Route, } as any) -const JestedLayoutB3LayoutC2Route = JestedLayoutB3LayoutC2Import.update({ +const JestedLayoutB3LayoutC2Route = JestedLayoutB3LayoutC2RouteImport.update({ id: '/_layout-c2', getParentRoute: () => JestedLayoutB3Route, } as any) -const FooLayoutB5IdRoute = FooLayoutB5IdImport.update({ +const FooLayoutB5IdRoute = FooLayoutB5IdRouteImport.update({ id: '/$id', path: '/$id', getParentRoute: () => FooLayoutB5RouteRoute, } as any) -const NestedLayoutB1LayoutC1BarRoute = NestedLayoutB1LayoutC1BarImport.update({ - id: '/bar', - path: '/bar', - getParentRoute: () => NestedLayoutB1LayoutC1Route, -} as any) +const NestedLayoutB1LayoutC1BarRoute = + NestedLayoutB1LayoutC1BarRouteImport.update({ + id: '/bar', + path: '/bar', + getParentRoute: () => NestedLayoutB1LayoutC1Route, + } as any) -const JestedLayoutB3LayoutC2BarRoute = JestedLayoutB3LayoutC2BarImport.update({ - id: '/bar', - path: '/bar', - getParentRoute: () => JestedLayoutB3LayoutC2Route, -} as any) +const JestedLayoutB3LayoutC2BarRoute = + JestedLayoutB3LayoutC2BarRouteImport.update({ + id: '/bar', + path: '/bar', + getParentRoute: () => JestedLayoutB3LayoutC2Route, + } as any) // Populate the FileRoutesByPath interface @@ -193,180 +196,392 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/jested': { id: '/jested' path: '/jested' fullPath: '/jested' - preLoaderRoute: typeof JestedRouteImport + preLoaderRoute: typeof JestedRouteRouteImport parentRoute: typeof rootRoute } '/_layout-a1': { id: '/_layout-a1' path: '' fullPath: '' - preLoaderRoute: typeof LayoutA1Import + preLoaderRoute: typeof LayoutA1RouteImport parentRoute: typeof rootRoute } '/_layout-a2': { id: '/_layout-a2' path: '' fullPath: '' - preLoaderRoute: typeof LayoutA2Import + preLoaderRoute: typeof LayoutA2RouteImport parentRoute: typeof rootRoute } '/foo': { id: '/foo' path: '/foo' fullPath: '/foo' - preLoaderRoute: typeof FooImport + preLoaderRoute: typeof FooRouteImport parentRoute: typeof rootRoute } '/foo/_layout-b5': { id: '/foo/_layout-b5' path: '/foo' fullPath: '/foo' - preLoaderRoute: typeof FooLayoutB5RouteImport + preLoaderRoute: typeof FooLayoutB5RouteRouteImport parentRoute: typeof FooRoute } '/(folder)/in-folder': { id: '/(folder)/in-folder' path: '/in-folder' fullPath: '/in-folder' - preLoaderRoute: typeof folderInFolderImport + preLoaderRoute: typeof folderInFolderRouteImport parentRoute: typeof rootRoute } '/_layout-a1/foo': { id: '/_layout-a1/foo' path: '/foo' fullPath: '/foo' - preLoaderRoute: typeof LayoutA1FooImport - parentRoute: typeof LayoutA1Import + preLoaderRoute: typeof LayoutA1FooRouteImport + parentRoute: typeof LayoutA1RouteImport } '/_layout-a2/bar': { id: '/_layout-a2/bar' path: '/bar' fullPath: '/bar' - preLoaderRoute: typeof LayoutA2BarImport - parentRoute: typeof LayoutA2Import + preLoaderRoute: typeof LayoutA2BarRouteImport + parentRoute: typeof LayoutA2RouteImport } '/foo/bar': { id: '/foo/bar' path: '/bar' fullPath: '/foo/bar' - preLoaderRoute: typeof FooBarImport - parentRoute: typeof FooImport + preLoaderRoute: typeof FooBarRouteImport + parentRoute: typeof FooRouteImport } '/jested/_layout-b3': { id: '/jested/_layout-b3' path: '' fullPath: '/jested' - preLoaderRoute: typeof JestedLayoutB3Import - parentRoute: typeof JestedRouteImport + preLoaderRoute: typeof JestedLayoutB3RouteImport + parentRoute: typeof JestedRouteRouteImport } '/jested/_layout-b4': { id: '/jested/_layout-b4' path: '' fullPath: '/jested' - preLoaderRoute: typeof JestedLayoutB4Import - parentRoute: typeof JestedRouteImport + preLoaderRoute: typeof JestedLayoutB4RouteImport + parentRoute: typeof JestedRouteRouteImport } '/nested': { id: '/nested' path: '/nested' fullPath: '/nested' - preLoaderRoute: typeof NestedImport + preLoaderRoute: typeof NestedRouteImport parentRoute: typeof rootRoute } '/nested/_layout-b1': { id: '/nested/_layout-b1' path: '/nested' fullPath: '/nested' - preLoaderRoute: typeof NestedLayoutB1Import + preLoaderRoute: typeof NestedLayoutB1RouteImport parentRoute: typeof NestedRoute } '/nested/_layout-b2': { id: '/nested/_layout-b2' path: '' fullPath: '/nested' - preLoaderRoute: typeof NestedLayoutB2Import - parentRoute: typeof NestedImport + preLoaderRoute: typeof NestedLayoutB2RouteImport + parentRoute: typeof NestedRouteImport } '/foo/_layout-b5/$id': { id: '/foo/_layout-b5/$id' path: '/$id' fullPath: '/foo/$id' - preLoaderRoute: typeof FooLayoutB5IdImport - parentRoute: typeof FooLayoutB5RouteImport + preLoaderRoute: typeof FooLayoutB5IdRouteImport + parentRoute: typeof FooLayoutB5RouteRouteImport } '/jested/_layout-b3/_layout-c2': { id: '/jested/_layout-b3/_layout-c2' path: '' fullPath: '/jested' - preLoaderRoute: typeof JestedLayoutB3LayoutC2Import - parentRoute: typeof JestedLayoutB3Import + preLoaderRoute: typeof JestedLayoutB3LayoutC2RouteImport + parentRoute: typeof JestedLayoutB3RouteImport } '/jested/_layout-b4/foo': { id: '/jested/_layout-b4/foo' path: '/foo' fullPath: '/jested/foo' - preLoaderRoute: typeof JestedLayoutB4FooImport - parentRoute: typeof JestedLayoutB4Import + preLoaderRoute: typeof JestedLayoutB4FooRouteImport + parentRoute: typeof JestedLayoutB4RouteImport } '/nested/_layout-b1/_layout-c1': { id: '/nested/_layout-b1/_layout-c1' path: '' fullPath: '/nested' - preLoaderRoute: typeof NestedLayoutB1LayoutC1Import - parentRoute: typeof NestedLayoutB1Import + preLoaderRoute: typeof NestedLayoutB1LayoutC1RouteImport + parentRoute: typeof NestedLayoutB1RouteImport } '/nested/_layout-b2/foo': { id: '/nested/_layout-b2/foo' path: '/foo' fullPath: '/nested/foo' - preLoaderRoute: typeof NestedLayoutB2FooImport - parentRoute: typeof NestedLayoutB2Import + preLoaderRoute: typeof NestedLayoutB2FooRouteImport + parentRoute: typeof NestedLayoutB2RouteImport } '/foo/_layout-b5/': { id: '/foo/_layout-b5/' path: '/' fullPath: '/foo/' - preLoaderRoute: typeof FooLayoutB5IndexImport - parentRoute: typeof FooLayoutB5RouteImport + preLoaderRoute: typeof FooLayoutB5IndexRouteImport + parentRoute: typeof FooLayoutB5RouteRouteImport } '/jested/_layout-b3/': { id: '/jested/_layout-b3/' path: '/' fullPath: '/jested/' - preLoaderRoute: typeof JestedLayoutB3IndexImport - parentRoute: typeof JestedLayoutB3Import + preLoaderRoute: typeof JestedLayoutB3IndexRouteImport + parentRoute: typeof JestedLayoutB3RouteImport } '/nested/_layout-b1/': { id: '/nested/_layout-b1/' path: '/' fullPath: '/nested/' - preLoaderRoute: typeof NestedLayoutB1IndexImport - parentRoute: typeof NestedLayoutB1Import + preLoaderRoute: typeof NestedLayoutB1IndexRouteImport + parentRoute: typeof NestedLayoutB1RouteImport } '/jested/_layout-b3/_layout-c2/bar': { id: '/jested/_layout-b3/_layout-c2/bar' path: '/bar' fullPath: '/jested/bar' - preLoaderRoute: typeof JestedLayoutB3LayoutC2BarImport - parentRoute: typeof JestedLayoutB3LayoutC2Import + preLoaderRoute: typeof JestedLayoutB3LayoutC2BarRouteImport + parentRoute: typeof JestedLayoutB3LayoutC2RouteImport } '/nested/_layout-b1/_layout-c1/bar': { id: '/nested/_layout-b1/_layout-c1/bar' path: '/bar' fullPath: '/nested/bar' - preLoaderRoute: typeof NestedLayoutB1LayoutC1BarImport - parentRoute: typeof NestedLayoutB1LayoutC1Import + preLoaderRoute: typeof NestedLayoutB1LayoutC1BarRouteImport + parentRoute: typeof NestedLayoutB1LayoutC1RouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/jested/route' { + const createFileRoute: CreateFileRoute< + '/jested', + FileRoutesByPath['/jested']['parentRoute'], + FileRoutesByPath['/jested']['id'], + FileRoutesByPath['/jested']['path'], + FileRoutesByPath['/jested']['fullPath'] + > +} +declare module './routes/_layout-a1' { + const createFileRoute: CreateFileRoute< + '/_layout-a1', + FileRoutesByPath['/_layout-a1']['parentRoute'], + FileRoutesByPath['/_layout-a1']['id'], + FileRoutesByPath['/_layout-a1']['path'], + FileRoutesByPath['/_layout-a1']['fullPath'] + > +} +declare module './routes/_layout-a2' { + const createFileRoute: CreateFileRoute< + '/_layout-a2', + FileRoutesByPath['/_layout-a2']['parentRoute'], + FileRoutesByPath['/_layout-a2']['id'], + FileRoutesByPath['/_layout-a2']['path'], + FileRoutesByPath['/_layout-a2']['fullPath'] + > +} + +declare module './routes/foo/_layout-b5/route' { + const createFileRoute: CreateFileRoute< + '/foo/_layout-b5', + FileRoutesByPath['/foo/_layout-b5']['parentRoute'], + FileRoutesByPath['/foo/_layout-b5']['id'], + FileRoutesByPath['/foo/_layout-b5']['path'], + FileRoutesByPath['/foo/_layout-b5']['fullPath'] + > +} +declare module './routes/(folder)/in-folder' { + const createFileRoute: CreateFileRoute< + '/(folder)/in-folder', + FileRoutesByPath['/(folder)/in-folder']['parentRoute'], + FileRoutesByPath['/(folder)/in-folder']['id'], + FileRoutesByPath['/(folder)/in-folder']['path'], + FileRoutesByPath['/(folder)/in-folder']['fullPath'] + > +} +declare module './routes/_layout-a1/foo' { + const createFileRoute: CreateFileRoute< + '/_layout-a1/foo', + FileRoutesByPath['/_layout-a1/foo']['parentRoute'], + FileRoutesByPath['/_layout-a1/foo']['id'], + FileRoutesByPath['/_layout-a1/foo']['path'], + FileRoutesByPath['/_layout-a1/foo']['fullPath'] + > +} +declare module './routes/_layout-a2/bar' { + const createFileRoute: CreateFileRoute< + '/_layout-a2/bar', + FileRoutesByPath['/_layout-a2/bar']['parentRoute'], + FileRoutesByPath['/_layout-a2/bar']['id'], + FileRoutesByPath['/_layout-a2/bar']['path'], + FileRoutesByPath['/_layout-a2/bar']['fullPath'] + > +} +declare module './routes/foo/bar' { + const createFileRoute: CreateFileRoute< + '/foo/bar', + FileRoutesByPath['/foo/bar']['parentRoute'], + FileRoutesByPath['/foo/bar']['id'], + FileRoutesByPath['/foo/bar']['path'], + FileRoutesByPath['/foo/bar']['fullPath'] + > +} +declare module './routes/jested/_layout-b3' { + const createFileRoute: CreateFileRoute< + '/jested/_layout-b3', + FileRoutesByPath['/jested/_layout-b3']['parentRoute'], + FileRoutesByPath['/jested/_layout-b3']['id'], + FileRoutesByPath['/jested/_layout-b3']['path'], + FileRoutesByPath['/jested/_layout-b3']['fullPath'] + > +} +declare module './routes/jested/_layout-b4' { + const createFileRoute: CreateFileRoute< + '/jested/_layout-b4', + FileRoutesByPath['/jested/_layout-b4']['parentRoute'], + FileRoutesByPath['/jested/_layout-b4']['id'], + FileRoutesByPath['/jested/_layout-b4']['path'], + FileRoutesByPath['/jested/_layout-b4']['fullPath'] + > +} + +declare module './routes/nested/_layout-b1' { + const createFileRoute: CreateFileRoute< + '/nested/_layout-b1', + FileRoutesByPath['/nested/_layout-b1']['parentRoute'], + FileRoutesByPath['/nested/_layout-b1']['id'], + FileRoutesByPath['/nested/_layout-b1']['path'], + FileRoutesByPath['/nested/_layout-b1']['fullPath'] + > +} +declare module './routes/nested/_layout-b2' { + const createFileRoute: CreateFileRoute< + '/nested/_layout-b2', + FileRoutesByPath['/nested/_layout-b2']['parentRoute'], + FileRoutesByPath['/nested/_layout-b2']['id'], + FileRoutesByPath['/nested/_layout-b2']['path'], + FileRoutesByPath['/nested/_layout-b2']['fullPath'] + > +} +declare module './routes/foo/_layout-b5/$id' { + const createFileRoute: CreateFileRoute< + '/foo/_layout-b5/$id', + FileRoutesByPath['/foo/_layout-b5/$id']['parentRoute'], + FileRoutesByPath['/foo/_layout-b5/$id']['id'], + FileRoutesByPath['/foo/_layout-b5/$id']['path'], + FileRoutesByPath['/foo/_layout-b5/$id']['fullPath'] + > +} +declare module './routes/jested/_layout-b3/_layout-c2' { + const createFileRoute: CreateFileRoute< + '/jested/_layout-b3/_layout-c2', + FileRoutesByPath['/jested/_layout-b3/_layout-c2']['parentRoute'], + FileRoutesByPath['/jested/_layout-b3/_layout-c2']['id'], + FileRoutesByPath['/jested/_layout-b3/_layout-c2']['path'], + FileRoutesByPath['/jested/_layout-b3/_layout-c2']['fullPath'] + > +} +declare module './routes/jested/_layout-b4/foo' { + const createFileRoute: CreateFileRoute< + '/jested/_layout-b4/foo', + FileRoutesByPath['/jested/_layout-b4/foo']['parentRoute'], + FileRoutesByPath['/jested/_layout-b4/foo']['id'], + FileRoutesByPath['/jested/_layout-b4/foo']['path'], + FileRoutesByPath['/jested/_layout-b4/foo']['fullPath'] + > +} +declare module './routes/nested/_layout-b1/_layout-c1' { + const createFileRoute: CreateFileRoute< + '/nested/_layout-b1/_layout-c1', + FileRoutesByPath['/nested/_layout-b1/_layout-c1']['parentRoute'], + FileRoutesByPath['/nested/_layout-b1/_layout-c1']['id'], + FileRoutesByPath['/nested/_layout-b1/_layout-c1']['path'], + FileRoutesByPath['/nested/_layout-b1/_layout-c1']['fullPath'] + > +} +declare module './routes/nested/_layout-b2/foo' { + const createFileRoute: CreateFileRoute< + '/nested/_layout-b2/foo', + FileRoutesByPath['/nested/_layout-b2/foo']['parentRoute'], + FileRoutesByPath['/nested/_layout-b2/foo']['id'], + FileRoutesByPath['/nested/_layout-b2/foo']['path'], + FileRoutesByPath['/nested/_layout-b2/foo']['fullPath'] + > +} +declare module './routes/foo/_layout-b5/index' { + const createFileRoute: CreateFileRoute< + '/foo/_layout-b5/', + FileRoutesByPath['/foo/_layout-b5/']['parentRoute'], + FileRoutesByPath['/foo/_layout-b5/']['id'], + FileRoutesByPath['/foo/_layout-b5/']['path'], + FileRoutesByPath['/foo/_layout-b5/']['fullPath'] + > +} +declare module './routes/jested/_layout-b3/index' { + const createFileRoute: CreateFileRoute< + '/jested/_layout-b3/', + FileRoutesByPath['/jested/_layout-b3/']['parentRoute'], + FileRoutesByPath['/jested/_layout-b3/']['id'], + FileRoutesByPath['/jested/_layout-b3/']['path'], + FileRoutesByPath['/jested/_layout-b3/']['fullPath'] + > +} +declare module './routes/nested/_layout-b1/index' { + const createFileRoute: CreateFileRoute< + '/nested/_layout-b1/', + FileRoutesByPath['/nested/_layout-b1/']['parentRoute'], + FileRoutesByPath['/nested/_layout-b1/']['id'], + FileRoutesByPath['/nested/_layout-b1/']['path'], + FileRoutesByPath['/nested/_layout-b1/']['fullPath'] + > +} +declare module './routes/jested/_layout-b3/_layout-c2/bar' { + const createFileRoute: CreateFileRoute< + '/jested/_layout-b3/_layout-c2/bar', + FileRoutesByPath['/jested/_layout-b3/_layout-c2/bar']['parentRoute'], + FileRoutesByPath['/jested/_layout-b3/_layout-c2/bar']['id'], + FileRoutesByPath['/jested/_layout-b3/_layout-c2/bar']['path'], + FileRoutesByPath['/jested/_layout-b3/_layout-c2/bar']['fullPath'] + > +} +declare module './routes/nested/_layout-b1/_layout-c1/bar' { + const createFileRoute: CreateFileRoute< + '/nested/_layout-b1/_layout-c1/bar', + FileRoutesByPath['/nested/_layout-b1/_layout-c1/bar']['parentRoute'], + FileRoutesByPath['/nested/_layout-b1/_layout-c1/bar']['id'], + FileRoutesByPath['/nested/_layout-b1/_layout-c1/bar']['path'], + FileRoutesByPath['/nested/_layout-b1/_layout-c1/bar']['fullPath'] + > +} + // Create and export the route tree interface JestedLayoutB3LayoutC2RouteChildren { diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/(folder)/in-folder.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/(folder)/in-folder.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/(folder)/in-folder.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/(folder)/in-folder.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/__root.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/__root.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/__root.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/__root.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a1.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a1.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a1.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a1.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a1/foo.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a1/foo.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a1/foo.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a1/foo.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a2.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a2.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a2.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a2.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a2/bar.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a2/bar.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a2/bar.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/_layout-a2/bar.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/foo/_layout-b5/$id.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/foo/_layout-b5/$id.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/foo/_layout-b5/$id.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/foo/_layout-b5/$id.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/foo/_layout-b5/index.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/foo/_layout-b5/index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/foo/_layout-b5/index.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/foo/_layout-b5/index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/foo/_layout-b5/route.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/foo/_layout-b5/route.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/foo/_layout-b5/route.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/foo/_layout-b5/route.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/foo/bar.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/foo/bar.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/foo/bar.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/foo/bar.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/index.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/index.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3/_layout-c2.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3/_layout-c2.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3/_layout-c2.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3/_layout-c2.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3/_layout-c2/bar.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3/_layout-c2/bar.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3/_layout-c2/bar.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3/_layout-c2/bar.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3/index.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3/index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3/index.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b3/index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b4.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b4.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b4.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b4.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b4/foo.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b4/foo.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b4/foo.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/jested/_layout-b4/foo.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/jested/route.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/jested/route.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/jested/route.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/jested/route.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1/_layout-c1.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1/_layout-c1.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1/_layout-c1.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1/_layout-c1.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1/_layout-c1/bar.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1/_layout-c1/bar.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1/_layout-c1/bar.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1/_layout-c1/bar.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1/index.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1/index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1/index.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b1/index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b2.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b2.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b2.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b2.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b2/foo.tsx b/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b2/foo.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b2/foo.tsx +++ b/packages/router-generator/tests/generator/nested-layouts/routes/nested/_layout-b2/foo.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routeTree.snapshot.ts b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routeTree.snapshot.ts index 9a8c43334d..e2cae53235 100644 --- a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routeTree.snapshot.ts @@ -9,75 +9,76 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { createFileRoute } from '@tanstack/react-router' +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as groupCLayoutCImport } from './routes/(group-c)/_layout-c' -import { Route as groupBLayoutBImport } from './routes/(group-b)/_layout-b' -import { Route as groupALayoutAImport } from './routes/(group-a)/_layout-a' -import { Route as groupCLayoutCIndexImport } from './routes/(group-c)/_layout-c/index' -import { Route as groupBLayoutBDashboardImport } from './routes/(group-b)/_layout-b/dashboard' -import { Route as groupALayoutASignupImport } from './routes/(group-a)/_layout-a/signup' -import { Route as groupALayoutALoginImport } from './routes/(group-a)/_layout-a/login' +import { Route as groupCLayoutCRouteImport } from './routes/(group-c)/_layout-c' +import { Route as groupBLayoutBRouteImport } from './routes/(group-b)/_layout-b' +import { Route as groupALayoutARouteImport } from './routes/(group-a)/_layout-a' +import { Route as groupCLayoutCIndexRouteImport } from './routes/(group-c)/_layout-c/index' +import { Route as groupBLayoutBDashboardRouteImport } from './routes/(group-b)/_layout-b/dashboard' +import { Route as groupALayoutASignupRouteImport } from './routes/(group-a)/_layout-a/signup' +import { Route as groupALayoutALoginRouteImport } from './routes/(group-a)/_layout-a/login' // Create Virtual Routes -const groupCImport = createFileRoute('/(group-c)')() -const groupBImport = createFileRoute('/(group-b)')() -const groupAImport = createFileRoute('/(group-a)')() +const groupCRouteImport = createFileRoute('/(group-c)')() +const groupBRouteImport = createFileRoute('/(group-b)')() +const groupARouteImport = createFileRoute('/(group-a)')() // Create/Update Routes -const groupCRoute = groupCImport.update({ +const groupCRoute = groupCRouteImport.update({ id: '/(group-c)', getParentRoute: () => rootRoute, } as any) -const groupBRoute = groupBImport.update({ +const groupBRoute = groupBRouteImport.update({ id: '/(group-b)', getParentRoute: () => rootRoute, } as any) -const groupARoute = groupAImport.update({ +const groupARoute = groupARouteImport.update({ id: '/(group-a)', getParentRoute: () => rootRoute, } as any) -const groupCLayoutCRoute = groupCLayoutCImport.update({ +const groupCLayoutCRoute = groupCLayoutCRouteImport.update({ id: '/_layout-c', getParentRoute: () => groupCRoute, } as any) -const groupBLayoutBRoute = groupBLayoutBImport.update({ +const groupBLayoutBRoute = groupBLayoutBRouteImport.update({ id: '/_layout-b', getParentRoute: () => groupBRoute, } as any) -const groupALayoutARoute = groupALayoutAImport.update({ +const groupALayoutARoute = groupALayoutARouteImport.update({ id: '/_layout-a', getParentRoute: () => groupARoute, } as any) -const groupCLayoutCIndexRoute = groupCLayoutCIndexImport.update({ +const groupCLayoutCIndexRoute = groupCLayoutCIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => groupCLayoutCRoute, } as any) -const groupBLayoutBDashboardRoute = groupBLayoutBDashboardImport.update({ +const groupBLayoutBDashboardRoute = groupBLayoutBDashboardRouteImport.update({ id: '/dashboard', path: '/dashboard', getParentRoute: () => groupBLayoutBRoute, } as any) -const groupALayoutASignupRoute = groupALayoutASignupImport.update({ +const groupALayoutASignupRoute = groupALayoutASignupRouteImport.update({ id: '/signup', path: '/signup', getParentRoute: () => groupALayoutARoute, } as any) -const groupALayoutALoginRoute = groupALayoutALoginImport.update({ +const groupALayoutALoginRoute = groupALayoutALoginRouteImport.update({ id: '/login', path: '/login', getParentRoute: () => groupALayoutARoute, @@ -91,75 +92,143 @@ declare module '@tanstack/react-router' { id: '/(group-a)' path: '/' fullPath: '/' - preLoaderRoute: typeof groupAImport + preLoaderRoute: typeof groupARouteImport parentRoute: typeof rootRoute } '/(group-a)/_layout-a': { id: '/(group-a)/_layout-a' path: '/' fullPath: '/' - preLoaderRoute: typeof groupALayoutAImport + preLoaderRoute: typeof groupALayoutARouteImport parentRoute: typeof groupARoute } '/(group-b)': { id: '/(group-b)' path: '/' fullPath: '/' - preLoaderRoute: typeof groupBImport + preLoaderRoute: typeof groupBRouteImport parentRoute: typeof rootRoute } '/(group-b)/_layout-b': { id: '/(group-b)/_layout-b' path: '/' fullPath: '/' - preLoaderRoute: typeof groupBLayoutBImport + preLoaderRoute: typeof groupBLayoutBRouteImport parentRoute: typeof groupBRoute } '/(group-c)': { id: '/(group-c)' path: '/' fullPath: '/' - preLoaderRoute: typeof groupCImport + preLoaderRoute: typeof groupCRouteImport parentRoute: typeof rootRoute } '/(group-c)/_layout-c': { id: '/(group-c)/_layout-c' path: '/' fullPath: '/' - preLoaderRoute: typeof groupCLayoutCImport + preLoaderRoute: typeof groupCLayoutCRouteImport parentRoute: typeof groupCRoute } '/(group-a)/_layout-a/login': { id: '/(group-a)/_layout-a/login' path: '/login' fullPath: '/login' - preLoaderRoute: typeof groupALayoutALoginImport - parentRoute: typeof groupALayoutAImport + preLoaderRoute: typeof groupALayoutALoginRouteImport + parentRoute: typeof groupALayoutARouteImport } '/(group-a)/_layout-a/signup': { id: '/(group-a)/_layout-a/signup' path: '/signup' fullPath: '/signup' - preLoaderRoute: typeof groupALayoutASignupImport - parentRoute: typeof groupALayoutAImport + preLoaderRoute: typeof groupALayoutASignupRouteImport + parentRoute: typeof groupALayoutARouteImport } '/(group-b)/_layout-b/dashboard': { id: '/(group-b)/_layout-b/dashboard' path: '/dashboard' fullPath: '/dashboard' - preLoaderRoute: typeof groupBLayoutBDashboardImport - parentRoute: typeof groupBLayoutBImport + preLoaderRoute: typeof groupBLayoutBDashboardRouteImport + parentRoute: typeof groupBLayoutBRouteImport } '/(group-c)/_layout-c/': { id: '/(group-c)/_layout-c/' path: '/' fullPath: '/' - preLoaderRoute: typeof groupCLayoutCIndexImport - parentRoute: typeof groupCLayoutCImport + preLoaderRoute: typeof groupCLayoutCIndexRouteImport + parentRoute: typeof groupCLayoutCRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/(group-a)/_layout-a' { + const createFileRoute: CreateFileRoute< + '/(group-a)/_layout-a', + FileRoutesByPath['/(group-a)/_layout-a']['parentRoute'], + FileRoutesByPath['/(group-a)/_layout-a']['id'], + FileRoutesByPath['/(group-a)/_layout-a']['path'], + FileRoutesByPath['/(group-a)/_layout-a']['fullPath'] + > +} + +declare module './routes/(group-b)/_layout-b' { + const createFileRoute: CreateFileRoute< + '/(group-b)/_layout-b', + FileRoutesByPath['/(group-b)/_layout-b']['parentRoute'], + FileRoutesByPath['/(group-b)/_layout-b']['id'], + FileRoutesByPath['/(group-b)/_layout-b']['path'], + FileRoutesByPath['/(group-b)/_layout-b']['fullPath'] + > +} + +declare module './routes/(group-c)/_layout-c' { + const createFileRoute: CreateFileRoute< + '/(group-c)/_layout-c', + FileRoutesByPath['/(group-c)/_layout-c']['parentRoute'], + FileRoutesByPath['/(group-c)/_layout-c']['id'], + FileRoutesByPath['/(group-c)/_layout-c']['path'], + FileRoutesByPath['/(group-c)/_layout-c']['fullPath'] + > +} +declare module './routes/(group-a)/_layout-a/login' { + const createFileRoute: CreateFileRoute< + '/(group-a)/_layout-a/login', + FileRoutesByPath['/(group-a)/_layout-a/login']['parentRoute'], + FileRoutesByPath['/(group-a)/_layout-a/login']['id'], + FileRoutesByPath['/(group-a)/_layout-a/login']['path'], + FileRoutesByPath['/(group-a)/_layout-a/login']['fullPath'] + > +} +declare module './routes/(group-a)/_layout-a/signup' { + const createFileRoute: CreateFileRoute< + '/(group-a)/_layout-a/signup', + FileRoutesByPath['/(group-a)/_layout-a/signup']['parentRoute'], + FileRoutesByPath['/(group-a)/_layout-a/signup']['id'], + FileRoutesByPath['/(group-a)/_layout-a/signup']['path'], + FileRoutesByPath['/(group-a)/_layout-a/signup']['fullPath'] + > +} +declare module './routes/(group-b)/_layout-b/dashboard' { + const createFileRoute: CreateFileRoute< + '/(group-b)/_layout-b/dashboard', + FileRoutesByPath['/(group-b)/_layout-b/dashboard']['parentRoute'], + FileRoutesByPath['/(group-b)/_layout-b/dashboard']['id'], + FileRoutesByPath['/(group-b)/_layout-b/dashboard']['path'], + FileRoutesByPath['/(group-b)/_layout-b/dashboard']['fullPath'] + > +} +declare module './routes/(group-c)/_layout-c/index' { + const createFileRoute: CreateFileRoute< + '/(group-c)/_layout-c/', + FileRoutesByPath['/(group-c)/_layout-c/']['parentRoute'], + FileRoutesByPath['/(group-c)/_layout-c/']['id'], + FileRoutesByPath['/(group-c)/_layout-c/']['path'], + FileRoutesByPath['/(group-c)/_layout-c/']['fullPath'] + > +} + // Create and export the route tree interface groupALayoutARouteChildren { diff --git a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-a)/_layout-a.tsx b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-a)/_layout-a.tsx index e41597bd14..7716800144 100644 --- a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-a)/_layout-a.tsx +++ b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-a)/_layout-a.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/(group-a)/_layout-a')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-a)/_layout-a/login.tsx b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-a)/_layout-a/login.tsx index 100a98b815..81dfefe2c4 100644 --- a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-a)/_layout-a/login.tsx +++ b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-a)/_layout-a/login.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/(group-a)/_layout-a/login')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-a)/_layout-a/signup.tsx b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-a)/_layout-a/signup.tsx index 2214d268e7..705cfd12d6 100644 --- a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-a)/_layout-a/signup.tsx +++ b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-a)/_layout-a/signup.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/(group-a)/_layout-a/signup')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-b)/_layout-b.tsx b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-b)/_layout-b.tsx index 9dc9043617..66bad5884c 100644 --- a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-b)/_layout-b.tsx +++ b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-b)/_layout-b.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/(group-b)/_layout-b')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-b)/_layout-b/dashboard.tsx b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-b)/_layout-b/dashboard.tsx index c265a00158..5e70c639ea 100644 --- a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-b)/_layout-b/dashboard.tsx +++ b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-b)/_layout-b/dashboard.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/(group-b)/_layout-b/dashboard')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-c)/_layout-c.tsx b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-c)/_layout-c.tsx index 37483d2b5d..de71033181 100644 --- a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-c)/_layout-c.tsx +++ b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-c)/_layout-c.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/(group-c)/_layout-c')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-c)/_layout-c/index.tsx b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-c)/_layout-c/index.tsx index 31a16f0515..cac65fa5c4 100644 --- a/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-c)/_layout-c/index.tsx +++ b/packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routes/(group-c)/_layout-c/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/(group-c)/_layout-c/')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/nested/routeTree.snapshot.ts b/packages/router-generator/tests/generator/nested/routeTree.snapshot.ts index 49498ae411..cb6ba3a7dc 100644 --- a/packages/router-generator/tests/generator/nested/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/nested/routeTree.snapshot.ts @@ -8,70 +8,72 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PostsRouteImport } from './routes/posts/route' -import { Route as BlogRouteImport } from './routes/blog/route' -import { Route as IndexImport } from './routes/index' -import { Route as PostsIndexImport } from './routes/posts/index' -import { Route as BlogIndexImport } from './routes/blog/index' -import { Route as BlogStatsImport } from './routes/blog_/stats' -import { Route as BlogSlugImport } from './routes/blog/$slug' -import { Route as PostsPostIdIndexImport } from './routes/posts/$postId/index' -import { Route as PostsPostIdDeepImport } from './routes/posts/$postId/deep' +import { Route as PostsRouteRouteImport } from './routes/posts/route' +import { Route as BlogRouteRouteImport } from './routes/blog/route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as PostsIndexRouteImport } from './routes/posts/index' +import { Route as BlogIndexRouteImport } from './routes/blog/index' +import { Route as BlogStatsRouteImport } from './routes/blog_/stats' +import { Route as BlogSlugRouteImport } from './routes/blog/$slug' +import { Route as PostsPostIdIndexRouteImport } from './routes/posts/$postId/index' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts/$postId/deep' // Create/Update Routes -const PostsRouteRoute = PostsRouteImport.update({ +const PostsRouteRoute = PostsRouteRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const BlogRouteRoute = BlogRouteImport.update({ +const BlogRouteRoute = BlogRouteRouteImport.update({ id: '/blog', path: '/blog', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRouteRoute, } as any) -const BlogIndexRoute = BlogIndexImport.update({ +const BlogIndexRoute = BlogIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => BlogRouteRoute, } as any) -const BlogStatsRoute = BlogStatsImport.update({ +const BlogStatsRoute = BlogStatsRouteImport.update({ id: '/blog_/stats', path: '/blog/stats', getParentRoute: () => rootRoute, } as any) -const BlogSlugRoute = BlogSlugImport.update({ +const BlogSlugRoute = BlogSlugRouteImport.update({ id: '/$slug', path: '/$slug', getParentRoute: () => BlogRouteRoute, } as any) -const PostsPostIdIndexRoute = PostsPostIdIndexImport.update({ +const PostsPostIdIndexRoute = PostsPostIdIndexRouteImport.update({ id: '/$postId/', path: '/$postId/', getParentRoute: () => PostsRouteRoute, } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/$postId/deep', path: '/$postId/deep', getParentRoute: () => PostsRouteRoute, @@ -85,68 +87,152 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/blog': { id: '/blog' path: '/blog' fullPath: '/blog' - preLoaderRoute: typeof BlogRouteImport + preLoaderRoute: typeof BlogRouteRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsRouteRouteImport parentRoute: typeof rootRoute } '/blog/$slug': { id: '/blog/$slug' path: '/$slug' fullPath: '/blog/$slug' - preLoaderRoute: typeof BlogSlugImport - parentRoute: typeof BlogRouteImport + preLoaderRoute: typeof BlogSlugRouteImport + parentRoute: typeof BlogRouteRouteImport } '/blog_/stats': { id: '/blog_/stats' path: '/blog/stats' fullPath: '/blog/stats' - preLoaderRoute: typeof BlogStatsImport + preLoaderRoute: typeof BlogStatsRouteImport parentRoute: typeof rootRoute } '/blog/': { id: '/blog/' path: '/' fullPath: '/blog/' - preLoaderRoute: typeof BlogIndexImport - parentRoute: typeof BlogRouteImport + preLoaderRoute: typeof BlogIndexRouteImport + parentRoute: typeof BlogRouteRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteRouteImport } '/posts/$postId/deep': { id: '/posts/$postId/deep' path: '/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsPostIdDeepRouteImport + parentRoute: typeof PostsRouteRouteImport } '/posts/$postId/': { id: '/posts/$postId/' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdIndexImport - parentRoute: typeof PostsRouteImport + preLoaderRoute: typeof PostsPostIdIndexRouteImport + parentRoute: typeof PostsRouteRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/blog/route' { + const createFileRoute: CreateFileRoute< + '/blog', + FileRoutesByPath['/blog']['parentRoute'], + FileRoutesByPath['/blog']['id'], + FileRoutesByPath['/blog']['path'], + FileRoutesByPath['/blog']['fullPath'] + > +} +declare module './routes/posts/route' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/blog/$slug' { + const createFileRoute: CreateFileRoute< + '/blog/$slug', + FileRoutesByPath['/blog/$slug']['parentRoute'], + FileRoutesByPath['/blog/$slug']['id'], + FileRoutesByPath['/blog/$slug']['path'], + FileRoutesByPath['/blog/$slug']['fullPath'] + > +} +declare module './routes/blog_/stats' { + const createFileRoute: CreateFileRoute< + '/blog_/stats', + FileRoutesByPath['/blog_/stats']['parentRoute'], + FileRoutesByPath['/blog_/stats']['id'], + FileRoutesByPath['/blog_/stats']['path'], + FileRoutesByPath['/blog_/stats']['fullPath'] + > +} +declare module './routes/blog/index' { + const createFileRoute: CreateFileRoute< + '/blog/', + FileRoutesByPath['/blog/']['parentRoute'], + FileRoutesByPath['/blog/']['id'], + FileRoutesByPath['/blog/']['path'], + FileRoutesByPath['/blog/']['fullPath'] + > +} +declare module './routes/posts/index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/posts/$postId/deep' { + const createFileRoute: CreateFileRoute< + '/posts/$postId/deep', + FileRoutesByPath['/posts/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts/$postId/deep']['id'], + FileRoutesByPath['/posts/$postId/deep']['path'], + FileRoutesByPath['/posts/$postId/deep']['fullPath'] + > +} +declare module './routes/posts/$postId/index' { + const createFileRoute: CreateFileRoute< + '/posts/$postId/', + FileRoutesByPath['/posts/$postId/']['parentRoute'], + FileRoutesByPath['/posts/$postId/']['id'], + FileRoutesByPath['/posts/$postId/']['path'], + FileRoutesByPath['/posts/$postId/']['fullPath'] + > +} + // Create and export the route tree interface BlogRouteRouteChildren { diff --git a/packages/router-generator/tests/generator/nested/routes/blog/$slug.tsx b/packages/router-generator/tests/generator/nested/routes/blog/$slug.tsx index 0389370c39..784c2b78ae 100644 --- a/packages/router-generator/tests/generator/nested/routes/blog/$slug.tsx +++ b/packages/router-generator/tests/generator/nested/routes/blog/$slug.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/blog/$slug')({ +export const Route = createFileRoute({ component: () =>
Hello /blog/$slug!
, }) diff --git a/packages/router-generator/tests/generator/nested/routes/blog/index.tsx b/packages/router-generator/tests/generator/nested/routes/blog/index.tsx index 6fab51efb1..0754024ed7 100644 --- a/packages/router-generator/tests/generator/nested/routes/blog/index.tsx +++ b/packages/router-generator/tests/generator/nested/routes/blog/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/blog/')({ +export const Route = createFileRoute({ component: () =>
Hello /blog/!
, }) diff --git a/packages/router-generator/tests/generator/nested/routes/blog/route.tsx b/packages/router-generator/tests/generator/nested/routes/blog/route.tsx index 2833fcc588..ea94edad49 100644 --- a/packages/router-generator/tests/generator/nested/routes/blog/route.tsx +++ b/packages/router-generator/tests/generator/nested/routes/blog/route.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/blog')({ +export const Route = createFileRoute({ component: () =>
Hello /blog!
, }) diff --git a/packages/router-generator/tests/generator/nested/routes/blog_/stats.tsx b/packages/router-generator/tests/generator/nested/routes/blog_/stats.tsx index 3c7f60dc99..16cc7268df 100644 --- a/packages/router-generator/tests/generator/nested/routes/blog_/stats.tsx +++ b/packages/router-generator/tests/generator/nested/routes/blog_/stats.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/blog_/stats')({ +export const Route = createFileRoute({ component: () =>
Hello /blog/stats!
, }) diff --git a/packages/router-generator/tests/generator/nested/routes/index.tsx b/packages/router-generator/tests/generator/nested/routes/index.tsx index a680913ded..22cab82307 100644 --- a/packages/router-generator/tests/generator/nested/routes/index.tsx +++ b/packages/router-generator/tests/generator/nested/routes/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: () =>
Hello /!
, }) diff --git a/packages/router-generator/tests/generator/nested/routes/posts/$postId/deep.tsx b/packages/router-generator/tests/generator/nested/routes/posts/$postId/deep.tsx index eec00feafc..6e634d9098 100644 --- a/packages/router-generator/tests/generator/nested/routes/posts/$postId/deep.tsx +++ b/packages/router-generator/tests/generator/nested/routes/posts/$postId/deep.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/$postId/deep')({ +export const Route = createFileRoute({ context: () => ({ someContext: 'context' }), loaderDeps: () => ({ dep: 1 }), loader: () => ({ data: 'data' }), diff --git a/packages/router-generator/tests/generator/nested/routes/posts/$postId/index.tsx b/packages/router-generator/tests/generator/nested/routes/posts/$postId/index.tsx index 1f0f31b0b2..6e8e65dae7 100644 --- a/packages/router-generator/tests/generator/nested/routes/posts/$postId/index.tsx +++ b/packages/router-generator/tests/generator/nested/routes/posts/$postId/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/$postId/')({ +export const Route = createFileRoute({ validateSearch: () => ({ indexSearch: 'search', }), diff --git a/packages/router-generator/tests/generator/nested/routes/posts/index.tsx b/packages/router-generator/tests/generator/nested/routes/posts/index.tsx index f3c995416c..2e16af1ca1 100644 --- a/packages/router-generator/tests/generator/nested/routes/posts/index.tsx +++ b/packages/router-generator/tests/generator/nested/routes/posts/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: () =>
Hello /posts/!
, }) diff --git a/packages/router-generator/tests/generator/nested/routes/posts/route.tsx b/packages/router-generator/tests/generator/nested/routes/posts/route.tsx index c298ab4675..3617558181 100644 --- a/packages/router-generator/tests/generator/nested/routes/posts/route.tsx +++ b/packages/router-generator/tests/generator/nested/routes/posts/route.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ component: () =>
Hello /posts!
, }) diff --git a/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.snapshot.ts b/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.snapshot.ts index ed2a802515..f51f435e11 100644 --- a/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.snapshot.ts @@ -9,31 +9,32 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { createFileRoute } from '@tanstack/react-router' +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as FooLayoutRouteImport } from './routes/foo/_layout/route' -import { Route as FooLayoutIndexImport } from './routes/foo/_layout/index' +import { Route as FooLayoutRouteRouteImport } from './routes/foo/_layout/route' +import { Route as FooLayoutIndexRouteImport } from './routes/foo/_layout/index' // Create Virtual Routes -const FooImport = createFileRoute('/foo')() +const FooRouteImport = createFileRoute('/foo')() // Create/Update Routes -const FooRoute = FooImport.update({ +const FooRoute = FooRouteImport.update({ id: '/foo', path: '/foo', getParentRoute: () => rootRoute, } as any) -const FooLayoutRouteRoute = FooLayoutRouteImport.update({ +const FooLayoutRouteRoute = FooLayoutRouteRouteImport.update({ id: '/_layout', getParentRoute: () => FooRoute, } as any) -const FooLayoutIndexRoute = FooLayoutIndexImport.update({ +const FooLayoutIndexRoute = FooLayoutIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => FooLayoutRouteRoute, @@ -47,26 +48,47 @@ declare module '@tanstack/react-router' { id: '/foo' path: '/foo' fullPath: '/foo' - preLoaderRoute: typeof FooImport + preLoaderRoute: typeof FooRouteImport parentRoute: typeof rootRoute } '/foo/_layout': { id: '/foo/_layout' path: '/foo' fullPath: '/foo' - preLoaderRoute: typeof FooLayoutRouteImport + preLoaderRoute: typeof FooLayoutRouteRouteImport parentRoute: typeof FooRoute } '/foo/_layout/': { id: '/foo/_layout/' path: '/' fullPath: '/foo/' - preLoaderRoute: typeof FooLayoutIndexImport - parentRoute: typeof FooLayoutRouteImport + preLoaderRoute: typeof FooLayoutIndexRouteImport + parentRoute: typeof FooLayoutRouteRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/foo/_layout/route' { + const createFileRoute: CreateFileRoute< + '/foo/_layout', + FileRoutesByPath['/foo/_layout']['parentRoute'], + FileRoutesByPath['/foo/_layout']['id'], + FileRoutesByPath['/foo/_layout']['path'], + FileRoutesByPath['/foo/_layout']['fullPath'] + > +} +declare module './routes/foo/_layout/index' { + const createFileRoute: CreateFileRoute< + '/foo/_layout/', + FileRoutesByPath['/foo/_layout/']['parentRoute'], + FileRoutesByPath['/foo/_layout/']['id'], + FileRoutesByPath['/foo/_layout/']['path'], + FileRoutesByPath['/foo/_layout/']['fullPath'] + > +} + // Create and export the route tree interface FooLayoutRouteRouteChildren { diff --git a/packages/router-generator/tests/generator/no-duplicate-route-segment/routes/__root.tsx b/packages/router-generator/tests/generator/no-duplicate-route-segment/routes/__root.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/no-duplicate-route-segment/routes/__root.tsx +++ b/packages/router-generator/tests/generator/no-duplicate-route-segment/routes/__root.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/no-duplicate-route-segment/routes/foo/_layout/index.tsx b/packages/router-generator/tests/generator/no-duplicate-route-segment/routes/foo/_layout/index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/no-duplicate-route-segment/routes/foo/_layout/index.tsx +++ b/packages/router-generator/tests/generator/no-duplicate-route-segment/routes/foo/_layout/index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/no-duplicate-route-segment/routes/foo/_layout/route.tsx b/packages/router-generator/tests/generator/no-duplicate-route-segment/routes/foo/_layout/route.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/no-duplicate-route-segment/routes/foo/_layout/route.tsx +++ b/packages/router-generator/tests/generator/no-duplicate-route-segment/routes/foo/_layout/route.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.snapshot.ts b/packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.snapshot.ts index 3caaefda94..22584597bd 100644 --- a/packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.snapshot.ts @@ -8,24 +8,26 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' -import { Route as NestedIndexImport } from './routes/nested/index' -import { Route as NestedChildImport } from './routes/nested/child' +import { Route as IndexRouteImport } from './routes/index' +import { Route as NestedIndexRouteImport } from './routes/nested/index' +import { Route as NestedChildRouteImport } from './routes/nested/child' // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/',path: '/',getParentRoute: () => rootRoute }as any) -const NestedIndexRoute = NestedIndexImport.update({ +const NestedIndexRoute = NestedIndexRouteImport.update({ id: '/nested/',path: '/nested/',getParentRoute: () => rootRoute }as any) -const NestedChildRoute = NestedChildImport.update({ +const NestedChildRoute = NestedChildRouteImport.update({ id: '/nested/child',path: '/nested/child',getParentRoute: () => rootRoute }as any) @@ -37,26 +39,56 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/nested/child': { id: '/nested/child' path: '/nested/child' fullPath: '/nested/child' - preLoaderRoute: typeof NestedChildImport + preLoaderRoute: typeof NestedChildRouteImport parentRoute: typeof rootRoute } '/nested/': { id: '/nested/' path: '/nested' fullPath: '/nested' - preLoaderRoute: typeof NestedIndexImport + preLoaderRoute: typeof NestedIndexRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > + } +declare module './routes/nested/child' { + const createFileRoute: CreateFileRoute< + '/nested/child', + FileRoutesByPath['/nested/child']['parentRoute'], + FileRoutesByPath['/nested/child']['id'], + FileRoutesByPath['/nested/child']['path'], + FileRoutesByPath['/nested/child']['fullPath'] + > + } +declare module './routes/nested/index' { + const createFileRoute: CreateFileRoute< + '/nested/', + FileRoutesByPath['/nested/']['parentRoute'], + FileRoutesByPath['/nested/']['id'], + FileRoutesByPath['/nested/']['path'], + FileRoutesByPath['/nested/']['fullPath'] + > + } + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/packages/router-generator/tests/generator/no-formatted-route-tree/routes/__root.tsx b/packages/router-generator/tests/generator/no-formatted-route-tree/routes/__root.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/no-formatted-route-tree/routes/__root.tsx +++ b/packages/router-generator/tests/generator/no-formatted-route-tree/routes/__root.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/no-formatted-route-tree/routes/index.tsx b/packages/router-generator/tests/generator/no-formatted-route-tree/routes/index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/no-formatted-route-tree/routes/index.tsx +++ b/packages/router-generator/tests/generator/no-formatted-route-tree/routes/index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/no-formatted-route-tree/routes/nested/child.tsx b/packages/router-generator/tests/generator/no-formatted-route-tree/routes/nested/child.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/no-formatted-route-tree/routes/nested/child.tsx +++ b/packages/router-generator/tests/generator/no-formatted-route-tree/routes/nested/child.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/no-formatted-route-tree/routes/nested/index.tsx b/packages/router-generator/tests/generator/no-formatted-route-tree/routes/nested/index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/no-formatted-route-tree/routes/nested/index.tsx +++ b/packages/router-generator/tests/generator/no-formatted-route-tree/routes/nested/index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/no-manifest/routeTree.snapshot.ts b/packages/router-generator/tests/generator/no-manifest/routeTree.snapshot.ts index 8f3a052d06..e19af9a375 100644 --- a/packages/router-generator/tests/generator/no-manifest/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/no-manifest/routeTree.snapshot.ts @@ -8,14 +8,16 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as IndexImport } from './routes/index' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -29,12 +31,24 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/packages/router-generator/tests/generator/no-manifest/routes/__root.tsx b/packages/router-generator/tests/generator/no-manifest/routes/__root.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/no-manifest/routes/__root.tsx +++ b/packages/router-generator/tests/generator/no-manifest/routes/__root.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/no-manifest/routes/index.tsx b/packages/router-generator/tests/generator/no-manifest/routes/index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/no-manifest/routes/index.tsx +++ b/packages/router-generator/tests/generator/no-manifest/routes/index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/numbers-in-path/routeTree.snapshot.ts b/packages/router-generator/tests/generator/numbers-in-path/routeTree.snapshot.ts index b9fe213c44..fe4b1cd310 100644 --- a/packages/router-generator/tests/generator/numbers-in-path/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/numbers-in-path/routeTree.snapshot.ts @@ -8,42 +8,44 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as AboutImport } from './routes/about' -import { Route as R03Import } from './routes/03' -import { Route as IndexImport } from './routes/index' -import { Route as R02IndexImport } from './routes/02.index' -import { Route as R01ExampleIndexImport } from './routes/01-example/index' +import { Route as AboutRouteImport } from './routes/about' +import { Route as R03RouteImport } from './routes/03' +import { Route as IndexRouteImport } from './routes/index' +import { Route as R02IndexRouteImport } from './routes/02.index' +import { Route as R01ExampleIndexRouteImport } from './routes/01-example/index' // Create/Update Routes -const AboutRoute = AboutImport.update({ +const AboutRoute = AboutRouteImport.update({ id: '/about', path: '/about', getParentRoute: () => rootRoute, } as any) -const R03Route = R03Import.update({ +const R03Route = R03RouteImport.update({ id: '/03', path: '/03', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const R02IndexRoute = R02IndexImport.update({ +const R02IndexRoute = R02IndexRouteImport.update({ id: '/02/', path: '/02/', getParentRoute: () => rootRoute, } as any) -const R01ExampleIndexRoute = R01ExampleIndexImport.update({ +const R01ExampleIndexRoute = R01ExampleIndexRouteImport.update({ id: '/01-example/', path: '/01-example/', getParentRoute: () => rootRoute, @@ -57,40 +59,88 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/03': { id: '/03' path: '/03' fullPath: '/03' - preLoaderRoute: typeof R03Import + preLoaderRoute: typeof R03RouteImport parentRoute: typeof rootRoute } '/about': { id: '/about' path: '/about' fullPath: '/about' - preLoaderRoute: typeof AboutImport + preLoaderRoute: typeof AboutRouteImport parentRoute: typeof rootRoute } '/01-example/': { id: '/01-example/' path: '/01-example' fullPath: '/01-example' - preLoaderRoute: typeof R01ExampleIndexImport + preLoaderRoute: typeof R01ExampleIndexRouteImport parentRoute: typeof rootRoute } '/02/': { id: '/02/' path: '/02' fullPath: '/02' - preLoaderRoute: typeof R02IndexImport + preLoaderRoute: typeof R02IndexRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/03' { + const createFileRoute: CreateFileRoute< + '/03', + FileRoutesByPath['/03']['parentRoute'], + FileRoutesByPath['/03']['id'], + FileRoutesByPath['/03']['path'], + FileRoutesByPath['/03']['fullPath'] + > +} +declare module './routes/about' { + const createFileRoute: CreateFileRoute< + '/about', + FileRoutesByPath['/about']['parentRoute'], + FileRoutesByPath['/about']['id'], + FileRoutesByPath['/about']['path'], + FileRoutesByPath['/about']['fullPath'] + > +} +declare module './routes/01-example/index' { + const createFileRoute: CreateFileRoute< + '/01-example/', + FileRoutesByPath['/01-example/']['parentRoute'], + FileRoutesByPath['/01-example/']['id'], + FileRoutesByPath['/01-example/']['path'], + FileRoutesByPath['/01-example/']['fullPath'] + > +} +declare module './routes/02.index' { + const createFileRoute: CreateFileRoute< + '/02/', + FileRoutesByPath['/02/']['parentRoute'], + FileRoutesByPath['/02/']['id'], + FileRoutesByPath['/02/']['path'], + FileRoutesByPath['/02/']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/packages/router-generator/tests/generator/numbers-in-path/routes/01-example/index.tsx b/packages/router-generator/tests/generator/numbers-in-path/routes/01-example/index.tsx index a4d5356ffd..6943669d72 100644 --- a/packages/router-generator/tests/generator/numbers-in-path/routes/01-example/index.tsx +++ b/packages/router-generator/tests/generator/numbers-in-path/routes/01-example/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/01-example/')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/numbers-in-path/routes/02.index.tsx b/packages/router-generator/tests/generator/numbers-in-path/routes/02.index.tsx index 40ec0494ad..445eec92dc 100644 --- a/packages/router-generator/tests/generator/numbers-in-path/routes/02.index.tsx +++ b/packages/router-generator/tests/generator/numbers-in-path/routes/02.index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/02/')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/numbers-in-path/routes/03.tsx b/packages/router-generator/tests/generator/numbers-in-path/routes/03.tsx index 4b6349bf17..3164148a3a 100644 --- a/packages/router-generator/tests/generator/numbers-in-path/routes/03.tsx +++ b/packages/router-generator/tests/generator/numbers-in-path/routes/03.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/03')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/numbers-in-path/routes/about.tsx b/packages/router-generator/tests/generator/numbers-in-path/routes/about.tsx index 1e6c7068e0..32071e180d 100644 --- a/packages/router-generator/tests/generator/numbers-in-path/routes/about.tsx +++ b/packages/router-generator/tests/generator/numbers-in-path/routes/about.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/about')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/numbers-in-path/routes/index.tsx b/packages/router-generator/tests/generator/numbers-in-path/routes/index.tsx index d58928d9ed..7ba4d00719 100644 --- a/packages/router-generator/tests/generator/numbers-in-path/routes/index.tsx +++ b/packages/router-generator/tests/generator/numbers-in-path/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/only-root/routeTree.snapshot.ts b/packages/router-generator/tests/generator/only-root/routeTree.snapshot.ts index 78c694471a..3abbdf6ab0 100644 --- a/packages/router-generator/tests/generator/only-root/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/only-root/routeTree.snapshot.ts @@ -20,6 +20,8 @@ declare module '@tanstack/react-router' { interface FileRoutesByPath {} } +// Add type-safety to the createFileRoute function across the route tree + // Create and export the route tree export interface FileRoutesByFullPath {} diff --git a/packages/router-generator/tests/generator/prefix-suffix/routeTree.snapshot.ts b/packages/router-generator/tests/generator/prefix-suffix/routeTree.snapshot.ts new file mode 100644 index 0000000000..2f292a8fe3 --- /dev/null +++ b/packages/router-generator/tests/generator/prefix-suffix/routeTree.snapshot.ts @@ -0,0 +1,214 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + +// Import Routes + +import { Route as rootRoute } from './routes/__root' +import { Route as WildcardChar123Char125suffixRouteImport } from './routes/wildcard/{$}suffix' +import { Route as WildcardChar123Char125DotsuffixRouteImport } from './routes/wildcard/{$}[.]suffix' +import { Route as WildcardPrefixChar123Char125RouteImport } from './routes/wildcard/prefix{$}' +import { Route as WildcardSplatRouteImport } from './routes/wildcard/$' + +// Create/Update Routes + +const WildcardChar123Char125suffixRoute = + WildcardChar123Char125suffixRouteImport.update({ + id: '/wildcard/{$}suffix', + path: '/wildcard/{$}suffix', + getParentRoute: () => rootRoute, + } as any) + +const WildcardChar123Char125DotsuffixRoute = + WildcardChar123Char125DotsuffixRouteImport.update({ + id: '/wildcard/{$}.suffix', + path: '/wildcard/{$}.suffix', + getParentRoute: () => rootRoute, + } as any) + +const WildcardPrefixChar123Char125Route = + WildcardPrefixChar123Char125RouteImport.update({ + id: '/wildcard/prefix{$}', + path: '/wildcard/prefix{$}', + getParentRoute: () => rootRoute, + } as any) + +const WildcardSplatRoute = WildcardSplatRouteImport.update({ + id: '/wildcard/$', + path: '/wildcard/$', + getParentRoute: () => rootRoute, +} as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/wildcard/$': { + id: '/wildcard/$' + path: '/wildcard/$' + fullPath: '/wildcard/$' + preLoaderRoute: typeof WildcardSplatRouteImport + parentRoute: typeof rootRoute + } + '/wildcard/prefix{$}': { + id: '/wildcard/prefix{$}' + path: '/wildcard/prefix{$}' + fullPath: '/wildcard/prefix{$}' + preLoaderRoute: typeof WildcardPrefixChar123Char125RouteImport + parentRoute: typeof rootRoute + } + '/wildcard/{$}.suffix': { + id: '/wildcard/{$}.suffix' + path: '/wildcard/{$}.suffix' + fullPath: '/wildcard/{$}.suffix' + preLoaderRoute: typeof WildcardChar123Char125DotsuffixRouteImport + parentRoute: typeof rootRoute + } + '/wildcard/{$}suffix': { + id: '/wildcard/{$}suffix' + path: '/wildcard/{$}suffix' + fullPath: '/wildcard/{$}suffix' + preLoaderRoute: typeof WildcardChar123Char125suffixRouteImport + parentRoute: typeof rootRoute + } + } +} + +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/wildcard/$' { + const createFileRoute: CreateFileRoute< + '/wildcard/$', + FileRoutesByPath['/wildcard/$']['parentRoute'], + FileRoutesByPath['/wildcard/$']['id'], + FileRoutesByPath['/wildcard/$']['path'], + FileRoutesByPath['/wildcard/$']['fullPath'] + > +} +declare module './routes/wildcard/prefix{$}' { + const createFileRoute: CreateFileRoute< + '/wildcard/prefix{$}', + FileRoutesByPath['/wildcard/prefix{$}']['parentRoute'], + FileRoutesByPath['/wildcard/prefix{$}']['id'], + FileRoutesByPath['/wildcard/prefix{$}']['path'], + FileRoutesByPath['/wildcard/prefix{$}']['fullPath'] + > +} +declare module './routes/wildcard/{$}[.]suffix' { + const createFileRoute: CreateFileRoute< + '/wildcard/{$}.suffix', + FileRoutesByPath['/wildcard/{$}.suffix']['parentRoute'], + FileRoutesByPath['/wildcard/{$}.suffix']['id'], + FileRoutesByPath['/wildcard/{$}.suffix']['path'], + FileRoutesByPath['/wildcard/{$}.suffix']['fullPath'] + > +} +declare module './routes/wildcard/{$}suffix' { + const createFileRoute: CreateFileRoute< + '/wildcard/{$}suffix', + FileRoutesByPath['/wildcard/{$}suffix']['parentRoute'], + FileRoutesByPath['/wildcard/{$}suffix']['id'], + FileRoutesByPath['/wildcard/{$}suffix']['path'], + FileRoutesByPath['/wildcard/{$}suffix']['fullPath'] + > +} + +// Create and export the route tree + +export interface FileRoutesByFullPath { + '/wildcard/$': typeof WildcardSplatRoute + '/wildcard/prefix{$}': typeof WildcardPrefixChar123Char125Route + '/wildcard/{$}.suffix': typeof WildcardChar123Char125DotsuffixRoute + '/wildcard/{$}suffix': typeof WildcardChar123Char125suffixRoute +} + +export interface FileRoutesByTo { + '/wildcard/$': typeof WildcardSplatRoute + '/wildcard/prefix{$}': typeof WildcardPrefixChar123Char125Route + '/wildcard/{$}.suffix': typeof WildcardChar123Char125DotsuffixRoute + '/wildcard/{$}suffix': typeof WildcardChar123Char125suffixRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/wildcard/$': typeof WildcardSplatRoute + '/wildcard/prefix{$}': typeof WildcardPrefixChar123Char125Route + '/wildcard/{$}.suffix': typeof WildcardChar123Char125DotsuffixRoute + '/wildcard/{$}suffix': typeof WildcardChar123Char125suffixRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/wildcard/$' + | '/wildcard/prefix{$}' + | '/wildcard/{$}.suffix' + | '/wildcard/{$}suffix' + fileRoutesByTo: FileRoutesByTo + to: + | '/wildcard/$' + | '/wildcard/prefix{$}' + | '/wildcard/{$}.suffix' + | '/wildcard/{$}suffix' + id: + | '__root__' + | '/wildcard/$' + | '/wildcard/prefix{$}' + | '/wildcard/{$}.suffix' + | '/wildcard/{$}suffix' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + WildcardSplatRoute: typeof WildcardSplatRoute + WildcardPrefixChar123Char125Route: typeof WildcardPrefixChar123Char125Route + WildcardChar123Char125DotsuffixRoute: typeof WildcardChar123Char125DotsuffixRoute + WildcardChar123Char125suffixRoute: typeof WildcardChar123Char125suffixRoute +} + +const rootRouteChildren: RootRouteChildren = { + WildcardSplatRoute: WildcardSplatRoute, + WildcardPrefixChar123Char125Route: WildcardPrefixChar123Char125Route, + WildcardChar123Char125DotsuffixRoute: WildcardChar123Char125DotsuffixRoute, + WildcardChar123Char125suffixRoute: WildcardChar123Char125suffixRoute, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/wildcard/$", + "/wildcard/prefix{$}", + "/wildcard/{$}.suffix", + "/wildcard/{$}suffix" + ] + }, + "/wildcard/$": { + "filePath": "wildcard/$.tsx" + }, + "/wildcard/prefix{$}": { + "filePath": "wildcard/prefix{$}.tsx" + }, + "/wildcard/{$}.suffix": { + "filePath": "wildcard/{$}[.]suffix.tsx" + }, + "/wildcard/{$}suffix": { + "filePath": "wildcard/{$}suffix.tsx" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/packages/router-generator/tests/generator/prefix-suffix/routes/__root.tsx b/packages/router-generator/tests/generator/prefix-suffix/routes/__root.tsx new file mode 100644 index 0000000000..3797d7bf8c --- /dev/null +++ b/packages/router-generator/tests/generator/prefix-suffix/routes/__root.tsx @@ -0,0 +1,15 @@ +import * as React from 'react' +import { Outlet, createRootRoute } from '@tanstack/react-router' + +export const Route = createRootRoute({ + component: RootComponent, +}) + +function RootComponent() { + return ( + +
Hello "__root"!
+ +
+ ) +} diff --git a/packages/router-generator/tests/generator/prefix-suffix/routes/index.tsx b/packages/router-generator/tests/generator/prefix-suffix/routes/index.tsx new file mode 100644 index 0000000000..ab504e42e9 --- /dev/null +++ b/packages/router-generator/tests/generator/prefix-suffix/routes/index.tsx @@ -0,0 +1 @@ +/** */ diff --git a/packages/router-generator/tests/generator/prefix-suffix/routes/wildcard/$.tsx b/packages/router-generator/tests/generator/prefix-suffix/routes/wildcard/$.tsx new file mode 100644 index 0000000000..5d18ba46cb --- /dev/null +++ b/packages/router-generator/tests/generator/prefix-suffix/routes/wildcard/$.tsx @@ -0,0 +1,7 @@ +export const Route = createFileRoute({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/wildcard/$"!
+} diff --git a/packages/router-generator/tests/generator/prefix-suffix/routes/wildcard/prefix{$}.tsx b/packages/router-generator/tests/generator/prefix-suffix/routes/wildcard/prefix{$}.tsx new file mode 100644 index 0000000000..4d70429bed --- /dev/null +++ b/packages/router-generator/tests/generator/prefix-suffix/routes/wildcard/prefix{$}.tsx @@ -0,0 +1,7 @@ +export const Route = createFileRoute({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/wildcard/prefix"!
+} diff --git a/packages/router-generator/tests/generator/prefix-suffix/routes/wildcard/{$}[.]suffix.tsx b/packages/router-generator/tests/generator/prefix-suffix/routes/wildcard/{$}[.]suffix.tsx new file mode 100644 index 0000000000..6d1a03f2f9 --- /dev/null +++ b/packages/router-generator/tests/generator/prefix-suffix/routes/wildcard/{$}[.]suffix.tsx @@ -0,0 +1,7 @@ +export const Route = createFileRoute({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/wildcard/.suffix"!
+} diff --git a/packages/router-generator/tests/generator/prefix-suffix/routes/wildcard/{$}suffix.tsx b/packages/router-generator/tests/generator/prefix-suffix/routes/wildcard/{$}suffix.tsx new file mode 100644 index 0000000000..02bc57ef6e --- /dev/null +++ b/packages/router-generator/tests/generator/prefix-suffix/routes/wildcard/{$}suffix.tsx @@ -0,0 +1,7 @@ +export const Route = createFileRoute({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/wildcard/suffix"!
+} diff --git a/packages/router-generator/tests/generator/route-groups/routeTree.snapshot.ts b/packages/router-generator/tests/generator/route-groups/routeTree.snapshot.ts index 57a9e6aa8c..470ad28c20 100644 --- a/packages/router-generator/tests/generator/route-groups/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/route-groups/routeTree.snapshot.ts @@ -9,63 +9,65 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { createFileRoute } from '@tanstack/react-router' +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as fooAsdfLayoutImport } from './routes/(foo)/asdf/_layout' -import { Route as fooAsdfLayoutFooImport } from './routes/(foo)/asdf/_layout.foo' -import { Route as fooAsdfbarIdImport } from './routes/(foo)/asdf/(bar)/$id' -import { Route as fooAsdfanotherGroupLayoutImport } from './routes/(foo)/asdf/(another-group)/_layout' -import { Route as fooAsdfbarLayoutAboutImport } from './routes/(foo)/asdf/(bar)/_layout.about' -import { Route as fooAsdfanotherGroupLayoutBazImport } from './routes/(foo)/asdf/(another-group)/_layout.baz' +import { Route as fooAsdfLayoutRouteImport } from './routes/(foo)/asdf/_layout' +import { Route as fooAsdfLayoutFooRouteImport } from './routes/(foo)/asdf/_layout.foo' +import { Route as fooAsdfbarIdRouteImport } from './routes/(foo)/asdf/(bar)/$id' +import { Route as fooAsdfanotherGroupLayoutRouteImport } from './routes/(foo)/asdf/(another-group)/_layout' +import { Route as fooAsdfbarLayoutAboutRouteImport } from './routes/(foo)/asdf/(bar)/_layout.about' +import { Route as fooAsdfanotherGroupLayoutBazRouteImport } from './routes/(foo)/asdf/(another-group)/_layout.baz' // Create Virtual Routes -const fooAsdfImport = createFileRoute('/(foo)/asdf')() -const fooAsdfanotherGroupImport = createFileRoute( +const fooAsdfRouteImport = createFileRoute('/(foo)/asdf')() +const fooAsdfanotherGroupRouteImport = createFileRoute( '/(foo)/asdf/(another-group)', )() -const fooAsdfbarLayoutXyzLazyImport = createFileRoute( +const fooAsdfbarLayoutXyzLazyRouteImport = createFileRoute( '/(foo)/asdf/(bar)/_layout/xyz', )() // Create/Update Routes -const fooAsdfRoute = fooAsdfImport.update({ +const fooAsdfRoute = fooAsdfRouteImport.update({ id: '/(foo)/asdf', path: '/asdf', getParentRoute: () => rootRoute, } as any) -const fooAsdfanotherGroupRoute = fooAsdfanotherGroupImport.update({ +const fooAsdfanotherGroupRoute = fooAsdfanotherGroupRouteImport.update({ id: '/(another-group)', getParentRoute: () => fooAsdfRoute, } as any) -const fooAsdfLayoutRoute = fooAsdfLayoutImport.update({ +const fooAsdfLayoutRoute = fooAsdfLayoutRouteImport.update({ id: '/_layout', getParentRoute: () => fooAsdfRoute, } as any) -const fooAsdfLayoutFooRoute = fooAsdfLayoutFooImport.update({ +const fooAsdfLayoutFooRoute = fooAsdfLayoutFooRouteImport.update({ id: '/foo', path: '/foo', getParentRoute: () => fooAsdfLayoutRoute, } as any) -const fooAsdfbarIdRoute = fooAsdfbarIdImport.update({ +const fooAsdfbarIdRoute = fooAsdfbarIdRouteImport.update({ id: '/(bar)/$id', path: '/$id', getParentRoute: () => fooAsdfRoute, } as any) -const fooAsdfanotherGroupLayoutRoute = fooAsdfanotherGroupLayoutImport.update({ - id: '/_layout', - getParentRoute: () => fooAsdfanotherGroupRoute, -} as any) +const fooAsdfanotherGroupLayoutRoute = + fooAsdfanotherGroupLayoutRouteImport.update({ + id: '/_layout', + getParentRoute: () => fooAsdfanotherGroupRoute, + } as any) -const fooAsdfbarLayoutXyzLazyRoute = fooAsdfbarLayoutXyzLazyImport +const fooAsdfbarLayoutXyzLazyRoute = fooAsdfbarLayoutXyzLazyRouteImport .update({ id: '/(bar)/_layout/xyz', path: '/xyz', @@ -75,14 +77,14 @@ const fooAsdfbarLayoutXyzLazyRoute = fooAsdfbarLayoutXyzLazyImport import('./routes/(foo)/asdf/(bar)/_layout.xyz.lazy').then((d) => d.Route), ) -const fooAsdfbarLayoutAboutRoute = fooAsdfbarLayoutAboutImport.update({ +const fooAsdfbarLayoutAboutRoute = fooAsdfbarLayoutAboutRouteImport.update({ id: '/(bar)/_layout/about', path: '/about', getParentRoute: () => fooAsdfRoute, } as any) const fooAsdfanotherGroupLayoutBazRoute = - fooAsdfanotherGroupLayoutBazImport.update({ + fooAsdfanotherGroupLayoutBazRouteImport.update({ id: '/baz', path: '/baz', getParentRoute: () => fooAsdfanotherGroupLayoutRoute, @@ -96,68 +98,131 @@ declare module '@tanstack/react-router' { id: '/(foo)/asdf' path: '/asdf' fullPath: '/asdf' - preLoaderRoute: typeof fooAsdfImport + preLoaderRoute: typeof fooAsdfRouteImport parentRoute: typeof rootRoute } '/(foo)/asdf/_layout': { id: '/(foo)/asdf/_layout' path: '/asdf' fullPath: '/asdf' - preLoaderRoute: typeof fooAsdfLayoutImport + preLoaderRoute: typeof fooAsdfLayoutRouteImport parentRoute: typeof fooAsdfRoute } '/(foo)/asdf/(another-group)': { id: '/(foo)/asdf/(another-group)' path: '/' fullPath: '/asdf/' - preLoaderRoute: typeof fooAsdfanotherGroupImport - parentRoute: typeof fooAsdfImport + preLoaderRoute: typeof fooAsdfanotherGroupRouteImport + parentRoute: typeof fooAsdfRouteImport } '/(foo)/asdf/(another-group)/_layout': { id: '/(foo)/asdf/(another-group)/_layout' path: '/' fullPath: '/asdf/' - preLoaderRoute: typeof fooAsdfanotherGroupLayoutImport + preLoaderRoute: typeof fooAsdfanotherGroupLayoutRouteImport parentRoute: typeof fooAsdfanotherGroupRoute } '/(foo)/asdf/(bar)/$id': { id: '/(foo)/asdf/(bar)/$id' path: '/$id' fullPath: '/asdf/$id' - preLoaderRoute: typeof fooAsdfbarIdImport - parentRoute: typeof fooAsdfImport + preLoaderRoute: typeof fooAsdfbarIdRouteImport + parentRoute: typeof fooAsdfRouteImport } '/(foo)/asdf/_layout/foo': { id: '/(foo)/asdf/_layout/foo' path: '/foo' fullPath: '/asdf/foo' - preLoaderRoute: typeof fooAsdfLayoutFooImport - parentRoute: typeof fooAsdfLayoutImport + preLoaderRoute: typeof fooAsdfLayoutFooRouteImport + parentRoute: typeof fooAsdfLayoutRouteImport } '/(foo)/asdf/(another-group)/_layout/baz': { id: '/(foo)/asdf/(another-group)/_layout/baz' path: '/baz' fullPath: '/asdf/baz' - preLoaderRoute: typeof fooAsdfanotherGroupLayoutBazImport - parentRoute: typeof fooAsdfanotherGroupLayoutImport + preLoaderRoute: typeof fooAsdfanotherGroupLayoutBazRouteImport + parentRoute: typeof fooAsdfanotherGroupLayoutRouteImport } '/(foo)/asdf/(bar)/_layout/about': { id: '/(foo)/asdf/(bar)/_layout/about' path: '/about' fullPath: '/asdf/about' - preLoaderRoute: typeof fooAsdfbarLayoutAboutImport - parentRoute: typeof fooAsdfImport + preLoaderRoute: typeof fooAsdfbarLayoutAboutRouteImport + parentRoute: typeof fooAsdfRouteImport } '/(foo)/asdf/(bar)/_layout/xyz': { id: '/(foo)/asdf/(bar)/_layout/xyz' path: '/xyz' fullPath: '/asdf/xyz' - preLoaderRoute: typeof fooAsdfbarLayoutXyzLazyImport - parentRoute: typeof fooAsdfImport + preLoaderRoute: typeof fooAsdfbarLayoutXyzLazyRouteImport + parentRoute: typeof fooAsdfRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/(foo)/asdf/_layout' { + const createFileRoute: CreateFileRoute< + '/(foo)/asdf/_layout', + FileRoutesByPath['/(foo)/asdf/_layout']['parentRoute'], + FileRoutesByPath['/(foo)/asdf/_layout']['id'], + FileRoutesByPath['/(foo)/asdf/_layout']['path'], + FileRoutesByPath['/(foo)/asdf/_layout']['fullPath'] + > +} + +declare module './routes/(foo)/asdf/(another-group)/_layout' { + const createFileRoute: CreateFileRoute< + '/(foo)/asdf/(another-group)/_layout', + FileRoutesByPath['/(foo)/asdf/(another-group)/_layout']['parentRoute'], + FileRoutesByPath['/(foo)/asdf/(another-group)/_layout']['id'], + FileRoutesByPath['/(foo)/asdf/(another-group)/_layout']['path'], + FileRoutesByPath['/(foo)/asdf/(another-group)/_layout']['fullPath'] + > +} +declare module './routes/(foo)/asdf/(bar)/$id' { + const createFileRoute: CreateFileRoute< + '/(foo)/asdf/(bar)/$id', + FileRoutesByPath['/(foo)/asdf/(bar)/$id']['parentRoute'], + FileRoutesByPath['/(foo)/asdf/(bar)/$id']['id'], + FileRoutesByPath['/(foo)/asdf/(bar)/$id']['path'], + FileRoutesByPath['/(foo)/asdf/(bar)/$id']['fullPath'] + > +} +declare module './routes/(foo)/asdf/_layout.foo' { + const createFileRoute: CreateFileRoute< + '/(foo)/asdf/_layout/foo', + FileRoutesByPath['/(foo)/asdf/_layout/foo']['parentRoute'], + FileRoutesByPath['/(foo)/asdf/_layout/foo']['id'], + FileRoutesByPath['/(foo)/asdf/_layout/foo']['path'], + FileRoutesByPath['/(foo)/asdf/_layout/foo']['fullPath'] + > +} +declare module './routes/(foo)/asdf/(another-group)/_layout.baz' { + const createFileRoute: CreateFileRoute< + '/(foo)/asdf/(another-group)/_layout/baz', + FileRoutesByPath['/(foo)/asdf/(another-group)/_layout/baz']['parentRoute'], + FileRoutesByPath['/(foo)/asdf/(another-group)/_layout/baz']['id'], + FileRoutesByPath['/(foo)/asdf/(another-group)/_layout/baz']['path'], + FileRoutesByPath['/(foo)/asdf/(another-group)/_layout/baz']['fullPath'] + > +} +declare module './routes/(foo)/asdf/(bar)/_layout.about' { + const createFileRoute: CreateFileRoute< + '/(foo)/asdf/(bar)/_layout/about', + FileRoutesByPath['/(foo)/asdf/(bar)/_layout/about']['parentRoute'], + FileRoutesByPath['/(foo)/asdf/(bar)/_layout/about']['id'], + FileRoutesByPath['/(foo)/asdf/(bar)/_layout/about']['path'], + FileRoutesByPath['/(foo)/asdf/(bar)/_layout/about']['fullPath'] + > +} +declare module './routes/(foo)/asdf/(bar)/_layout.xyz.lazy' { + const createLazyFileRoute: CreateLazyFileRoute< + FileRoutesByPath['/(foo)/asdf/(bar)/_layout/xyz']['preLoaderRoute'] + > +} + // Create and export the route tree interface fooAsdfLayoutRouteChildren { diff --git a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.baz.tsx b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.baz.tsx index ce8ed9a546..6db8036f00 100644 --- a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.baz.tsx +++ b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.baz.tsx @@ -1,7 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/(foo)/asdf/(another-group)/_layout/baz')( - { - component: () =>
Hello /(foo)/asdf/(another-group)/_layout/baz!
, - }, -) +export const Route = createFileRoute({ + component: () =>
Hello /(foo)/asdf/(another-group)/_layout/baz!
, +}) diff --git a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.tsx b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.tsx index c2e5c502fa..f69715bf48 100644 --- a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.tsx +++ b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/(foo)/asdf/(another-group)/_layout')({ +export const Route = createFileRoute({ component: () =>
Hello /(foo)/asdf/(another-group)/_layout!
, }) diff --git a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/$id.tsx b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/$id.tsx index 75cbf8c35e..c46abc16f0 100644 --- a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/$id.tsx +++ b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/$id.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/(foo)/asdf/(bar)/$id')({ +export const Route = createFileRoute({ component: () =>
Hello /(foo)/asdf/(bar)/$id!
, }) diff --git a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.about.tsx b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.about.tsx index 06daaef4e5..8fcb6f5964 100644 --- a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.about.tsx +++ b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.about.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/(foo)/asdf/(bar)/_layout/about')({ +export const Route = createFileRoute({ component: () =>
Hello /(foo)/asdf/(bar)/_layout/about!
, }) diff --git a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.xyz.lazy.tsx b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.xyz.lazy.tsx index 955cd7f9bd..6e5db319eb 100644 --- a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.xyz.lazy.tsx +++ b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.xyz.lazy.tsx @@ -1,5 +1,5 @@ -import { createLazyFileRoute } from '@tanstack/react-router' +// @ts-nocheck -export const Route = createLazyFileRoute('/(foo)/asdf/(bar)/_layout/xyz')({ +export const Route = createLazyFileRoute({ component: () =>
Hello /(foo)/asdf/(bar)/_layout/xyz!
, }) diff --git a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.foo.tsx b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.foo.tsx index a090505278..57551c0b2e 100644 --- a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.foo.tsx +++ b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.foo.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/(foo)/asdf/_layout/foo')({ +export const Route = createFileRoute({ component: () =>
Hello /(foo)/asdf/_layout/foo!
, }) diff --git a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.tsx b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.tsx index 6817284676..a78ffddd1d 100644 --- a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.tsx +++ b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/(foo)/asdf/_layout')({ +export const Route = createFileRoute({ component: () =>
Hello /(foo)/asdf/_layout!
, }) diff --git a/packages/router-generator/tests/generator/single-level/routeTree.snapshot.ts b/packages/router-generator/tests/generator/single-level/routeTree.snapshot.ts index 2f69793c10..39c796491d 100644 --- a/packages/router-generator/tests/generator/single-level/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/single-level/routeTree.snapshot.ts @@ -8,21 +8,23 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router' + // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PostsImport } from './routes/posts' -import { Route as IndexImport } from './routes/index' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as IndexRouteImport } from './routes/index' // Create/Update Routes -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, @@ -36,19 +38,40 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/packages/router-generator/tests/generator/single-level/routes/__root.tsx b/packages/router-generator/tests/generator/single-level/routes/__root.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/single-level/routes/__root.tsx +++ b/packages/router-generator/tests/generator/single-level/routes/__root.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/single-level/routes/index.tsx b/packages/router-generator/tests/generator/single-level/routes/index.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/single-level/routes/index.tsx +++ b/packages/router-generator/tests/generator/single-level/routes/index.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/single-level/routes/posts.tsx b/packages/router-generator/tests/generator/single-level/routes/posts.tsx index ab504e42e9..a8c4d4c893 100644 --- a/packages/router-generator/tests/generator/single-level/routes/posts.tsx +++ b/packages/router-generator/tests/generator/single-level/routes/posts.tsx @@ -1 +1,2 @@ -/** */ +// @ts-nocheck +export const Route = createFileRoute() diff --git a/packages/router-generator/tests/generator/types-disabled/routeTree.snapshot.js b/packages/router-generator/tests/generator/types-disabled/routeTree.snapshot.js index e7e66c3847..10aeffda8c 100644 --- a/packages/router-generator/tests/generator/types-disabled/routeTree.snapshot.js +++ b/packages/router-generator/tests/generator/types-disabled/routeTree.snapshot.js @@ -11,32 +11,32 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as PostsImport } from './routes/posts' -import { Route as IndexImport } from './routes/index' -import { Route as UsersUserIdImport } from './routes/users.$userId' -import { Route as PostsPostIdImport } from './routes/posts/$postId' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as IndexRouteImport } from './routes/index' +import { Route as UsersUserIdRouteImport } from './routes/users.$userId' +import { Route as PostsPostIdRouteImport } from './routes/posts/$postId' // Create/Update Routes -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, }) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, }) -const UsersUserIdRoute = UsersUserIdImport.update({ +const UsersUserIdRoute = UsersUserIdRouteImport.update({ id: '/users/$userId', path: '/users/$userId', getParentRoute: () => rootRoute, }) -const PostsPostIdRoute = PostsPostIdImport.update({ +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, diff --git a/packages/router-generator/tests/generator/types-disabled/routes/index.tsx b/packages/router-generator/tests/generator/types-disabled/routes/index.tsx index cebf9db135..0c6b517ac3 100644 --- a/packages/router-generator/tests/generator/types-disabled/routes/index.tsx +++ b/packages/router-generator/tests/generator/types-disabled/routes/index.tsx @@ -1,6 +1,5 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: () =>
Hello /!
, }) diff --git a/packages/router-generator/tests/generator/types-disabled/routes/posts.tsx b/packages/router-generator/tests/generator/types-disabled/routes/posts.tsx index ec0b3fcee7..bbd5c622a3 100644 --- a/packages/router-generator/tests/generator/types-disabled/routes/posts.tsx +++ b/packages/router-generator/tests/generator/types-disabled/routes/posts.tsx @@ -1,6 +1,5 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ component: () =>
Hello /posts!
, }) diff --git a/packages/router-generator/tests/generator/types-disabled/routes/posts/$postId.tsx b/packages/router-generator/tests/generator/types-disabled/routes/posts/$postId.tsx index 4528667792..0571c41009 100644 --- a/packages/router-generator/tests/generator/types-disabled/routes/posts/$postId.tsx +++ b/packages/router-generator/tests/generator/types-disabled/routes/posts/$postId.tsx @@ -1,6 +1,5 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ component: () =>
Hello /posts/$postId!
, }) diff --git a/packages/router-generator/tests/generator/types-disabled/routes/users.$userId.tsx b/packages/router-generator/tests/generator/types-disabled/routes/users.$userId.tsx index b6553fe98a..32e776ec82 100644 --- a/packages/router-generator/tests/generator/types-disabled/routes/users.$userId.tsx +++ b/packages/router-generator/tests/generator/types-disabled/routes/users.$userId.tsx @@ -1,6 +1,5 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/users/$userId')({ +export const Route = createFileRoute({ component: () =>
Hello /users/$userId!
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-default-export/routeTree.snapshot.ts b/packages/router-generator/tests/generator/virtual-config-file-default-export/routeTree.snapshot.ts index ef967d5c21..d62466ed3b 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-default-export/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/virtual-config-file-default-export/routeTree.snapshot.ts @@ -9,94 +9,95 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { createFileRoute } from '@tanstack/react-router' +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-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 pagesImport } from './routes/pages' -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' +import { Route as layoutRouteImport } from './routes/layout' +import { Route as indexRouteImport } from './routes/index' +import { Route as dbDashboardRouteImport } from './routes/db/dashboard' +import { Route as pagesRouteImport } from './routes/pages' +import { Route as HelloIndexRouteImport } from './routes/subtree/index' +import { Route as dbDashboardInvoicesRouteImport } from './routes/db/dashboard-invoices' +import { Route as dbDashboardIndexRouteImport } from './routes/db/dashboard-index' +import { Route as HelloFooIndexRouteImport } from './routes/subtree/foo/index' +import { Route as HelloFooIdRouteImport } from './routes/subtree/foo/$id' +import { Route as dbInvoiceDetailRouteImport } from './routes/db/invoice-detail' +import { Route as dbInvoicesIndexRouteImport } from './routes/db/invoices-index' // Create Virtual Routes -const LangImport = createFileRoute('/$lang')() +const LangRouteImport = createFileRoute('/$lang')() // Create/Update Routes -const layoutRoute = layoutImport.update({ +const layoutRoute = layoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const LangRoute = LangImport.update({ +const LangRoute = LangRouteImport.update({ id: '/$lang', path: '/$lang', getParentRoute: () => rootRoute, } as any) -const indexRoute = indexImport.update({ +const indexRoute = indexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const dbDashboardRoute = dbDashboardImport.update({ +const dbDashboardRoute = dbDashboardRouteImport.update({ id: '/dashboard', path: '/dashboard', getParentRoute: () => layoutRoute, } as any) -const pagesRoute = pagesImport.update({ +const pagesRoute = pagesRouteImport.update({ id: '/', path: '/', getParentRoute: () => LangRoute, } as any) -const HelloIndexRoute = HelloIndexImport.update({ +const HelloIndexRoute = HelloIndexRouteImport.update({ id: '/hello/', path: '/hello/', getParentRoute: () => layoutRoute, } as any) -const dbDashboardInvoicesRoute = dbDashboardInvoicesImport.update({ +const dbDashboardInvoicesRoute = dbDashboardInvoicesRouteImport.update({ id: '/invoices', path: '/invoices', getParentRoute: () => dbDashboardRoute, } as any) -const dbDashboardIndexRoute = dbDashboardIndexImport.update({ +const dbDashboardIndexRoute = dbDashboardIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => dbDashboardRoute, } as any) -const HelloFooIndexRoute = HelloFooIndexImport.update({ +const HelloFooIndexRoute = HelloFooIndexRouteImport.update({ id: '/hello/foo/', path: '/hello/foo/', getParentRoute: () => layoutRoute, } as any) -const HelloFooIdRoute = HelloFooIdImport.update({ +const HelloFooIdRoute = HelloFooIdRouteImport.update({ id: '/hello/foo/$id', path: '/hello/foo/$id', getParentRoute: () => layoutRoute, } as any) -const dbInvoiceDetailRoute = dbInvoiceDetailImport.update({ +const dbInvoiceDetailRoute = dbInvoiceDetailRouteImport.update({ id: '/$id', path: '/$id', getParentRoute: () => dbDashboardInvoicesRoute, } as any) -const dbInvoicesIndexRoute = dbInvoicesIndexImport.update({ +const dbInvoicesIndexRoute = dbInvoicesIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => dbDashboardInvoicesRoute, @@ -110,89 +111,192 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof indexImport + preLoaderRoute: typeof indexRouteImport parentRoute: typeof rootRoute } '/$lang': { id: '/$lang' path: '/$lang' fullPath: '/$lang' - preLoaderRoute: typeof LangImport + preLoaderRoute: typeof LangRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof layoutImport + preLoaderRoute: typeof layoutRouteImport parentRoute: typeof rootRoute } '/$lang/': { id: '/$lang/' path: '/' fullPath: '/$lang/' - preLoaderRoute: typeof pagesImport - parentRoute: typeof LangImport + preLoaderRoute: typeof pagesRouteImport + parentRoute: typeof LangRouteImport } '/_layout/dashboard': { id: '/_layout/dashboard' path: '/dashboard' fullPath: '/dashboard' - preLoaderRoute: typeof dbDashboardImport - parentRoute: typeof layoutImport + preLoaderRoute: typeof dbDashboardRouteImport + parentRoute: typeof layoutRouteImport } '/_layout/dashboard/': { id: '/_layout/dashboard/' path: '/' fullPath: '/dashboard/' - preLoaderRoute: typeof dbDashboardIndexImport - parentRoute: typeof dbDashboardImport + preLoaderRoute: typeof dbDashboardIndexRouteImport + parentRoute: typeof dbDashboardRouteImport } '/_layout/dashboard/invoices': { id: '/_layout/dashboard/invoices' path: '/invoices' fullPath: '/dashboard/invoices' - preLoaderRoute: typeof dbDashboardInvoicesImport - parentRoute: typeof dbDashboardImport + preLoaderRoute: typeof dbDashboardInvoicesRouteImport + parentRoute: typeof dbDashboardRouteImport } '/_layout/hello/': { id: '/_layout/hello/' path: '/hello' fullPath: '/hello' - preLoaderRoute: typeof HelloIndexImport - parentRoute: typeof layoutImport + preLoaderRoute: typeof HelloIndexRouteImport + parentRoute: typeof layoutRouteImport } '/_layout/dashboard/invoices/': { id: '/_layout/dashboard/invoices/' path: '/' fullPath: '/dashboard/invoices/' - preLoaderRoute: typeof dbInvoicesIndexImport - parentRoute: typeof dbDashboardInvoicesImport + preLoaderRoute: typeof dbInvoicesIndexRouteImport + parentRoute: typeof dbDashboardInvoicesRouteImport } '/_layout/dashboard/invoices/$id': { id: '/_layout/dashboard/invoices/$id' path: '/$id' fullPath: '/dashboard/invoices/$id' - preLoaderRoute: typeof dbInvoiceDetailImport - parentRoute: typeof dbDashboardInvoicesImport + preLoaderRoute: typeof dbInvoiceDetailRouteImport + parentRoute: typeof dbDashboardInvoicesRouteImport } '/_layout/hello/foo/$id': { id: '/_layout/hello/foo/$id' path: '/hello/foo/$id' fullPath: '/hello/foo/$id' - preLoaderRoute: typeof HelloFooIdImport - parentRoute: typeof layoutImport + preLoaderRoute: typeof HelloFooIdRouteImport + parentRoute: typeof layoutRouteImport } '/_layout/hello/foo/': { id: '/_layout/hello/foo/' path: '/hello/foo' fullPath: '/hello/foo' - preLoaderRoute: typeof HelloFooIndexImport - parentRoute: typeof layoutImport + preLoaderRoute: typeof HelloFooIndexRouteImport + parentRoute: typeof layoutRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} + +declare module './routes/layout' { + const createFileRoute: CreateFileRoute< + '/_layout', + FileRoutesByPath['/_layout']['parentRoute'], + FileRoutesByPath['/_layout']['id'], + FileRoutesByPath['/_layout']['path'], + FileRoutesByPath['/_layout']['fullPath'] + > +} +declare module './routes/pages' { + const createFileRoute: CreateFileRoute< + '/$lang/', + FileRoutesByPath['/$lang/']['parentRoute'], + FileRoutesByPath['/$lang/']['id'], + FileRoutesByPath['/$lang/']['path'], + FileRoutesByPath['/$lang/']['fullPath'] + > +} +declare module './routes/db/dashboard' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard', + FileRoutesByPath['/_layout/dashboard']['parentRoute'], + FileRoutesByPath['/_layout/dashboard']['id'], + FileRoutesByPath['/_layout/dashboard']['path'], + FileRoutesByPath['/_layout/dashboard']['fullPath'] + > +} +declare module './routes/db/dashboard-index' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard/', + FileRoutesByPath['/_layout/dashboard/']['parentRoute'], + FileRoutesByPath['/_layout/dashboard/']['id'], + FileRoutesByPath['/_layout/dashboard/']['path'], + FileRoutesByPath['/_layout/dashboard/']['fullPath'] + > +} +declare module './routes/db/dashboard-invoices' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard/invoices', + FileRoutesByPath['/_layout/dashboard/invoices']['parentRoute'], + FileRoutesByPath['/_layout/dashboard/invoices']['id'], + FileRoutesByPath['/_layout/dashboard/invoices']['path'], + FileRoutesByPath['/_layout/dashboard/invoices']['fullPath'] + > +} +declare module './routes/subtree/index' { + const createFileRoute: CreateFileRoute< + '/_layout/hello/', + FileRoutesByPath['/_layout/hello/']['parentRoute'], + FileRoutesByPath['/_layout/hello/']['id'], + FileRoutesByPath['/_layout/hello/']['path'], + FileRoutesByPath['/_layout/hello/']['fullPath'] + > +} +declare module './routes/db/invoices-index' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard/invoices/', + FileRoutesByPath['/_layout/dashboard/invoices/']['parentRoute'], + FileRoutesByPath['/_layout/dashboard/invoices/']['id'], + FileRoutesByPath['/_layout/dashboard/invoices/']['path'], + FileRoutesByPath['/_layout/dashboard/invoices/']['fullPath'] + > +} +declare module './routes/db/invoice-detail' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard/invoices/$id', + FileRoutesByPath['/_layout/dashboard/invoices/$id']['parentRoute'], + FileRoutesByPath['/_layout/dashboard/invoices/$id']['id'], + FileRoutesByPath['/_layout/dashboard/invoices/$id']['path'], + FileRoutesByPath['/_layout/dashboard/invoices/$id']['fullPath'] + > +} +declare module './routes/subtree/foo/$id' { + const createFileRoute: CreateFileRoute< + '/_layout/hello/foo/$id', + FileRoutesByPath['/_layout/hello/foo/$id']['parentRoute'], + FileRoutesByPath['/_layout/hello/foo/$id']['id'], + FileRoutesByPath['/_layout/hello/foo/$id']['path'], + FileRoutesByPath['/_layout/hello/foo/$id']['fullPath'] + > +} +declare module './routes/subtree/foo/index' { + const createFileRoute: CreateFileRoute< + '/_layout/hello/foo/', + FileRoutesByPath['/_layout/hello/foo/']['parentRoute'], + FileRoutesByPath['/_layout/hello/foo/']['id'], + FileRoutesByPath['/_layout/hello/foo/']['path'], + FileRoutesByPath['/_layout/hello/foo/']['fullPath'] + > +} + // Create and export the route tree interface LangRouteChildren { diff --git a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/dashboard-index.tsx b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/dashboard-index.tsx index a92fc772c3..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/dashboard-index.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/dashboard-index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard/')({ +export const Route = createFileRoute({ component: () =>
Hello !
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/dashboard-invoices.tsx b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/dashboard-invoices.tsx index bf7e5a02b2..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/dashboard-invoices.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/dashboard-invoices.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard/invoices')({ +export const Route = createFileRoute({ component: () =>
Hello !
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/dashboard.tsx b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/dashboard.tsx index d5b4f49706..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/dashboard.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/dashboard.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard')({ +export const Route = createFileRoute({ component: () =>
Hello !
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/invoice-detail.tsx b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/invoice-detail.tsx index e7be6c1910..a1ed3d4a28 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/invoice-detail.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/invoice-detail.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard/invoices/$id')({ +export const Route = createFileRoute({ component: () =>
Hello /_layout/dashboard/invoices/$id!
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/invoices-index.tsx b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/invoices-index.tsx index f2e56721b6..960e382af9 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/invoices-index.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/db/invoices-index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard/invoices/')({ +export const Route = createFileRoute({ component: () =>
Hello /_layout/dashboard/invoices/!
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/index.tsx b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/index.tsx index a294139860..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/index.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: () =>
Hello !
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/layout.tsx b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/layout.tsx index 2e48e48410..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/layout.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/layout.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout')({ +export const Route = createFileRoute({ component: () =>
Hello !
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/pages.tsx b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/pages.tsx index a942c7ce75..488a59a55a 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/pages.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/pages.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/$lang/')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/subtree/foo/$id.tsx b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/subtree/foo/$id.tsx index d8cbd795a7..8418001767 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/subtree/foo/$id.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/subtree/foo/$id.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/hello/foo/$id')({ +export const Route = createFileRoute({ component: () =>
Hello /foo/$id!
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/subtree/foo/index.tsx b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/subtree/foo/index.tsx index 10233de496..84660c4d04 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/subtree/foo/index.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/subtree/foo/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/hello/foo/')({ +export const Route = createFileRoute({ component: () =>
Hello /foo/!
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/subtree/index.tsx b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/subtree/index.tsx index 3367799b96..22cab82307 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/subtree/index.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-default-export/routes/subtree/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/hello/')({ +export const Route = createFileRoute({ component: () =>
Hello /!
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-named-export/routeTree.snapshot.ts b/packages/router-generator/tests/generator/virtual-config-file-named-export/routeTree.snapshot.ts index ef967d5c21..d62466ed3b 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-named-export/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/virtual-config-file-named-export/routeTree.snapshot.ts @@ -9,94 +9,95 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { createFileRoute } from '@tanstack/react-router' +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-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 pagesImport } from './routes/pages' -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' +import { Route as layoutRouteImport } from './routes/layout' +import { Route as indexRouteImport } from './routes/index' +import { Route as dbDashboardRouteImport } from './routes/db/dashboard' +import { Route as pagesRouteImport } from './routes/pages' +import { Route as HelloIndexRouteImport } from './routes/subtree/index' +import { Route as dbDashboardInvoicesRouteImport } from './routes/db/dashboard-invoices' +import { Route as dbDashboardIndexRouteImport } from './routes/db/dashboard-index' +import { Route as HelloFooIndexRouteImport } from './routes/subtree/foo/index' +import { Route as HelloFooIdRouteImport } from './routes/subtree/foo/$id' +import { Route as dbInvoiceDetailRouteImport } from './routes/db/invoice-detail' +import { Route as dbInvoicesIndexRouteImport } from './routes/db/invoices-index' // Create Virtual Routes -const LangImport = createFileRoute('/$lang')() +const LangRouteImport = createFileRoute('/$lang')() // Create/Update Routes -const layoutRoute = layoutImport.update({ +const layoutRoute = layoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const LangRoute = LangImport.update({ +const LangRoute = LangRouteImport.update({ id: '/$lang', path: '/$lang', getParentRoute: () => rootRoute, } as any) -const indexRoute = indexImport.update({ +const indexRoute = indexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const dbDashboardRoute = dbDashboardImport.update({ +const dbDashboardRoute = dbDashboardRouteImport.update({ id: '/dashboard', path: '/dashboard', getParentRoute: () => layoutRoute, } as any) -const pagesRoute = pagesImport.update({ +const pagesRoute = pagesRouteImport.update({ id: '/', path: '/', getParentRoute: () => LangRoute, } as any) -const HelloIndexRoute = HelloIndexImport.update({ +const HelloIndexRoute = HelloIndexRouteImport.update({ id: '/hello/', path: '/hello/', getParentRoute: () => layoutRoute, } as any) -const dbDashboardInvoicesRoute = dbDashboardInvoicesImport.update({ +const dbDashboardInvoicesRoute = dbDashboardInvoicesRouteImport.update({ id: '/invoices', path: '/invoices', getParentRoute: () => dbDashboardRoute, } as any) -const dbDashboardIndexRoute = dbDashboardIndexImport.update({ +const dbDashboardIndexRoute = dbDashboardIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => dbDashboardRoute, } as any) -const HelloFooIndexRoute = HelloFooIndexImport.update({ +const HelloFooIndexRoute = HelloFooIndexRouteImport.update({ id: '/hello/foo/', path: '/hello/foo/', getParentRoute: () => layoutRoute, } as any) -const HelloFooIdRoute = HelloFooIdImport.update({ +const HelloFooIdRoute = HelloFooIdRouteImport.update({ id: '/hello/foo/$id', path: '/hello/foo/$id', getParentRoute: () => layoutRoute, } as any) -const dbInvoiceDetailRoute = dbInvoiceDetailImport.update({ +const dbInvoiceDetailRoute = dbInvoiceDetailRouteImport.update({ id: '/$id', path: '/$id', getParentRoute: () => dbDashboardInvoicesRoute, } as any) -const dbInvoicesIndexRoute = dbInvoicesIndexImport.update({ +const dbInvoicesIndexRoute = dbInvoicesIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => dbDashboardInvoicesRoute, @@ -110,89 +111,192 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof indexImport + preLoaderRoute: typeof indexRouteImport parentRoute: typeof rootRoute } '/$lang': { id: '/$lang' path: '/$lang' fullPath: '/$lang' - preLoaderRoute: typeof LangImport + preLoaderRoute: typeof LangRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof layoutImport + preLoaderRoute: typeof layoutRouteImport parentRoute: typeof rootRoute } '/$lang/': { id: '/$lang/' path: '/' fullPath: '/$lang/' - preLoaderRoute: typeof pagesImport - parentRoute: typeof LangImport + preLoaderRoute: typeof pagesRouteImport + parentRoute: typeof LangRouteImport } '/_layout/dashboard': { id: '/_layout/dashboard' path: '/dashboard' fullPath: '/dashboard' - preLoaderRoute: typeof dbDashboardImport - parentRoute: typeof layoutImport + preLoaderRoute: typeof dbDashboardRouteImport + parentRoute: typeof layoutRouteImport } '/_layout/dashboard/': { id: '/_layout/dashboard/' path: '/' fullPath: '/dashboard/' - preLoaderRoute: typeof dbDashboardIndexImport - parentRoute: typeof dbDashboardImport + preLoaderRoute: typeof dbDashboardIndexRouteImport + parentRoute: typeof dbDashboardRouteImport } '/_layout/dashboard/invoices': { id: '/_layout/dashboard/invoices' path: '/invoices' fullPath: '/dashboard/invoices' - preLoaderRoute: typeof dbDashboardInvoicesImport - parentRoute: typeof dbDashboardImport + preLoaderRoute: typeof dbDashboardInvoicesRouteImport + parentRoute: typeof dbDashboardRouteImport } '/_layout/hello/': { id: '/_layout/hello/' path: '/hello' fullPath: '/hello' - preLoaderRoute: typeof HelloIndexImport - parentRoute: typeof layoutImport + preLoaderRoute: typeof HelloIndexRouteImport + parentRoute: typeof layoutRouteImport } '/_layout/dashboard/invoices/': { id: '/_layout/dashboard/invoices/' path: '/' fullPath: '/dashboard/invoices/' - preLoaderRoute: typeof dbInvoicesIndexImport - parentRoute: typeof dbDashboardInvoicesImport + preLoaderRoute: typeof dbInvoicesIndexRouteImport + parentRoute: typeof dbDashboardInvoicesRouteImport } '/_layout/dashboard/invoices/$id': { id: '/_layout/dashboard/invoices/$id' path: '/$id' fullPath: '/dashboard/invoices/$id' - preLoaderRoute: typeof dbInvoiceDetailImport - parentRoute: typeof dbDashboardInvoicesImport + preLoaderRoute: typeof dbInvoiceDetailRouteImport + parentRoute: typeof dbDashboardInvoicesRouteImport } '/_layout/hello/foo/$id': { id: '/_layout/hello/foo/$id' path: '/hello/foo/$id' fullPath: '/hello/foo/$id' - preLoaderRoute: typeof HelloFooIdImport - parentRoute: typeof layoutImport + preLoaderRoute: typeof HelloFooIdRouteImport + parentRoute: typeof layoutRouteImport } '/_layout/hello/foo/': { id: '/_layout/hello/foo/' path: '/hello/foo' fullPath: '/hello/foo' - preLoaderRoute: typeof HelloFooIndexImport - parentRoute: typeof layoutImport + preLoaderRoute: typeof HelloFooIndexRouteImport + parentRoute: typeof layoutRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} + +declare module './routes/layout' { + const createFileRoute: CreateFileRoute< + '/_layout', + FileRoutesByPath['/_layout']['parentRoute'], + FileRoutesByPath['/_layout']['id'], + FileRoutesByPath['/_layout']['path'], + FileRoutesByPath['/_layout']['fullPath'] + > +} +declare module './routes/pages' { + const createFileRoute: CreateFileRoute< + '/$lang/', + FileRoutesByPath['/$lang/']['parentRoute'], + FileRoutesByPath['/$lang/']['id'], + FileRoutesByPath['/$lang/']['path'], + FileRoutesByPath['/$lang/']['fullPath'] + > +} +declare module './routes/db/dashboard' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard', + FileRoutesByPath['/_layout/dashboard']['parentRoute'], + FileRoutesByPath['/_layout/dashboard']['id'], + FileRoutesByPath['/_layout/dashboard']['path'], + FileRoutesByPath['/_layout/dashboard']['fullPath'] + > +} +declare module './routes/db/dashboard-index' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard/', + FileRoutesByPath['/_layout/dashboard/']['parentRoute'], + FileRoutesByPath['/_layout/dashboard/']['id'], + FileRoutesByPath['/_layout/dashboard/']['path'], + FileRoutesByPath['/_layout/dashboard/']['fullPath'] + > +} +declare module './routes/db/dashboard-invoices' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard/invoices', + FileRoutesByPath['/_layout/dashboard/invoices']['parentRoute'], + FileRoutesByPath['/_layout/dashboard/invoices']['id'], + FileRoutesByPath['/_layout/dashboard/invoices']['path'], + FileRoutesByPath['/_layout/dashboard/invoices']['fullPath'] + > +} +declare module './routes/subtree/index' { + const createFileRoute: CreateFileRoute< + '/_layout/hello/', + FileRoutesByPath['/_layout/hello/']['parentRoute'], + FileRoutesByPath['/_layout/hello/']['id'], + FileRoutesByPath['/_layout/hello/']['path'], + FileRoutesByPath['/_layout/hello/']['fullPath'] + > +} +declare module './routes/db/invoices-index' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard/invoices/', + FileRoutesByPath['/_layout/dashboard/invoices/']['parentRoute'], + FileRoutesByPath['/_layout/dashboard/invoices/']['id'], + FileRoutesByPath['/_layout/dashboard/invoices/']['path'], + FileRoutesByPath['/_layout/dashboard/invoices/']['fullPath'] + > +} +declare module './routes/db/invoice-detail' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard/invoices/$id', + FileRoutesByPath['/_layout/dashboard/invoices/$id']['parentRoute'], + FileRoutesByPath['/_layout/dashboard/invoices/$id']['id'], + FileRoutesByPath['/_layout/dashboard/invoices/$id']['path'], + FileRoutesByPath['/_layout/dashboard/invoices/$id']['fullPath'] + > +} +declare module './routes/subtree/foo/$id' { + const createFileRoute: CreateFileRoute< + '/_layout/hello/foo/$id', + FileRoutesByPath['/_layout/hello/foo/$id']['parentRoute'], + FileRoutesByPath['/_layout/hello/foo/$id']['id'], + FileRoutesByPath['/_layout/hello/foo/$id']['path'], + FileRoutesByPath['/_layout/hello/foo/$id']['fullPath'] + > +} +declare module './routes/subtree/foo/index' { + const createFileRoute: CreateFileRoute< + '/_layout/hello/foo/', + FileRoutesByPath['/_layout/hello/foo/']['parentRoute'], + FileRoutesByPath['/_layout/hello/foo/']['id'], + FileRoutesByPath['/_layout/hello/foo/']['path'], + FileRoutesByPath['/_layout/hello/foo/']['fullPath'] + > +} + // Create and export the route tree interface LangRouteChildren { diff --git a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/dashboard-index.tsx b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/dashboard-index.tsx index a92fc772c3..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/dashboard-index.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/dashboard-index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard/')({ +export const Route = createFileRoute({ component: () =>
Hello !
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/dashboard-invoices.tsx b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/dashboard-invoices.tsx index bf7e5a02b2..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/dashboard-invoices.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/dashboard-invoices.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard/invoices')({ +export const Route = createFileRoute({ component: () =>
Hello !
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/dashboard.tsx b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/dashboard.tsx index d5b4f49706..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/dashboard.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/dashboard.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard')({ +export const Route = createFileRoute({ component: () =>
Hello !
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/invoice-detail.tsx b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/invoice-detail.tsx index e7be6c1910..a1ed3d4a28 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/invoice-detail.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/invoice-detail.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard/invoices/$id')({ +export const Route = createFileRoute({ component: () =>
Hello /_layout/dashboard/invoices/$id!
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/invoices-index.tsx b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/invoices-index.tsx index f2e56721b6..960e382af9 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/invoices-index.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/db/invoices-index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard/invoices/')({ +export const Route = createFileRoute({ component: () =>
Hello /_layout/dashboard/invoices/!
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/index.tsx b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/index.tsx index a294139860..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/index.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: () =>
Hello !
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/layout.tsx b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/layout.tsx index 2e48e48410..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/layout.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/layout.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout')({ +export const Route = createFileRoute({ component: () =>
Hello !
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/pages.tsx b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/pages.tsx index a942c7ce75..488a59a55a 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/pages.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/pages.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/$lang/')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/subtree/foo/$id.tsx b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/subtree/foo/$id.tsx index d8cbd795a7..8418001767 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/subtree/foo/$id.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/subtree/foo/$id.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/hello/foo/$id')({ +export const Route = createFileRoute({ component: () =>
Hello /foo/$id!
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/subtree/foo/index.tsx b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/subtree/foo/index.tsx index 10233de496..84660c4d04 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/subtree/foo/index.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/subtree/foo/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/hello/foo/')({ +export const Route = createFileRoute({ component: () =>
Hello /foo/!
, }) diff --git a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/subtree/index.tsx b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/subtree/index.tsx index 3367799b96..22cab82307 100644 --- a/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/subtree/index.tsx +++ b/packages/router-generator/tests/generator/virtual-config-file-named-export/routes/subtree/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/hello/')({ +export const Route = createFileRoute({ component: () =>
Hello /!
, }) 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 index ca38556b08..3dda40aba6 100644 --- a/packages/router-generator/tests/generator/virtual-inside-nested/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/virtual-inside-nested/routeTree.snapshot.ts @@ -8,35 +8,37 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-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' +import { Route as IndexRouteImport } from './routes/index' +import { Route as FooBarRouteImport } from './routes/foo/bar' +import { Route as fooBarDetailsRouteImport } from './routes/foo/bar/details' +import { Route as fooBarHomeRouteImport } from './routes/foo/bar/home' // Create/Update Routes -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const FooBarRoute = FooBarImport.update({ +const FooBarRoute = FooBarRouteImport.update({ id: '/foo/bar', path: '/foo/bar', getParentRoute: () => rootRoute, } as any) -const fooBarDetailsRoute = fooBarDetailsImport.update({ +const fooBarDetailsRoute = fooBarDetailsRouteImport.update({ id: '/$id', path: '/$id', getParentRoute: () => FooBarRoute, } as any) -const fooBarHomeRoute = fooBarHomeImport.update({ +const fooBarHomeRoute = fooBarHomeRouteImport.update({ id: '/', path: '/', getParentRoute: () => FooBarRoute, @@ -50,33 +52,72 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/foo/bar': { id: '/foo/bar' path: '/foo/bar' fullPath: '/foo/bar' - preLoaderRoute: typeof FooBarImport + preLoaderRoute: typeof FooBarRouteImport parentRoute: typeof rootRoute } '/foo/bar/': { id: '/foo/bar/' path: '/' fullPath: '/foo/bar/' - preLoaderRoute: typeof fooBarHomeImport - parentRoute: typeof FooBarImport + preLoaderRoute: typeof fooBarHomeRouteImport + parentRoute: typeof FooBarRouteImport } '/foo/bar/$id': { id: '/foo/bar/$id' path: '/$id' fullPath: '/foo/bar/$id' - preLoaderRoute: typeof fooBarDetailsImport - parentRoute: typeof FooBarImport + preLoaderRoute: typeof fooBarDetailsRouteImport + parentRoute: typeof FooBarRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/foo/bar' { + const createFileRoute: CreateFileRoute< + '/foo/bar', + FileRoutesByPath['/foo/bar']['parentRoute'], + FileRoutesByPath['/foo/bar']['id'], + FileRoutesByPath['/foo/bar']['path'], + FileRoutesByPath['/foo/bar']['fullPath'] + > +} +declare module './routes/foo/bar/home' { + const createFileRoute: CreateFileRoute< + '/foo/bar/', + FileRoutesByPath['/foo/bar/']['parentRoute'], + FileRoutesByPath['/foo/bar/']['id'], + FileRoutesByPath['/foo/bar/']['path'], + FileRoutesByPath['/foo/bar/']['fullPath'] + > +} +declare module './routes/foo/bar/details' { + const createFileRoute: CreateFileRoute< + '/foo/bar/$id', + FileRoutesByPath['/foo/bar/$id']['parentRoute'], + FileRoutesByPath['/foo/bar/$id']['id'], + FileRoutesByPath['/foo/bar/$id']['path'], + FileRoutesByPath['/foo/bar/$id']['fullPath'] + > +} + // Create and export the route tree interface FooBarRouteChildren { 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 index 6ef5a1ca27..dc891bb587 100644 --- 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 @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/foo/bar')({ +export const Route = createFileRoute({ component: () =>
Hello /foo/bar!
, }) 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 index 59c29910fe..4b4c9d6de1 100644 --- 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 @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/foo/bar/$id')({ +export const Route = createFileRoute({ 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 index b7a0742abf..a2d2a7e838 100644 --- 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 @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/foo/bar/')({ +export const Route = createFileRoute({ component: () =>
Hello /foo/bar/!
, }) 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 index a680913ded..22cab82307 100644 --- a/packages/router-generator/tests/generator/virtual-inside-nested/routes/index.tsx +++ b/packages/router-generator/tests/generator/virtual-inside-nested/routes/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: () =>
Hello /!
, }) diff --git a/packages/router-generator/tests/generator/virtual/routeTree.snapshot.ts b/packages/router-generator/tests/generator/virtual/routeTree.snapshot.ts index ef967d5c21..d62466ed3b 100644 --- a/packages/router-generator/tests/generator/virtual/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/virtual/routeTree.snapshot.ts @@ -9,94 +9,95 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { createFileRoute } from '@tanstack/react-router' +import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-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 pagesImport } from './routes/pages' -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' +import { Route as layoutRouteImport } from './routes/layout' +import { Route as indexRouteImport } from './routes/index' +import { Route as dbDashboardRouteImport } from './routes/db/dashboard' +import { Route as pagesRouteImport } from './routes/pages' +import { Route as HelloIndexRouteImport } from './routes/subtree/index' +import { Route as dbDashboardInvoicesRouteImport } from './routes/db/dashboard-invoices' +import { Route as dbDashboardIndexRouteImport } from './routes/db/dashboard-index' +import { Route as HelloFooIndexRouteImport } from './routes/subtree/foo/index' +import { Route as HelloFooIdRouteImport } from './routes/subtree/foo/$id' +import { Route as dbInvoiceDetailRouteImport } from './routes/db/invoice-detail' +import { Route as dbInvoicesIndexRouteImport } from './routes/db/invoices-index' // Create Virtual Routes -const LangImport = createFileRoute('/$lang')() +const LangRouteImport = createFileRoute('/$lang')() // Create/Update Routes -const layoutRoute = layoutImport.update({ +const layoutRoute = layoutRouteImport.update({ id: '/_layout', getParentRoute: () => rootRoute, } as any) -const LangRoute = LangImport.update({ +const LangRoute = LangRouteImport.update({ id: '/$lang', path: '/$lang', getParentRoute: () => rootRoute, } as any) -const indexRoute = indexImport.update({ +const indexRoute = indexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const dbDashboardRoute = dbDashboardImport.update({ +const dbDashboardRoute = dbDashboardRouteImport.update({ id: '/dashboard', path: '/dashboard', getParentRoute: () => layoutRoute, } as any) -const pagesRoute = pagesImport.update({ +const pagesRoute = pagesRouteImport.update({ id: '/', path: '/', getParentRoute: () => LangRoute, } as any) -const HelloIndexRoute = HelloIndexImport.update({ +const HelloIndexRoute = HelloIndexRouteImport.update({ id: '/hello/', path: '/hello/', getParentRoute: () => layoutRoute, } as any) -const dbDashboardInvoicesRoute = dbDashboardInvoicesImport.update({ +const dbDashboardInvoicesRoute = dbDashboardInvoicesRouteImport.update({ id: '/invoices', path: '/invoices', getParentRoute: () => dbDashboardRoute, } as any) -const dbDashboardIndexRoute = dbDashboardIndexImport.update({ +const dbDashboardIndexRoute = dbDashboardIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => dbDashboardRoute, } as any) -const HelloFooIndexRoute = HelloFooIndexImport.update({ +const HelloFooIndexRoute = HelloFooIndexRouteImport.update({ id: '/hello/foo/', path: '/hello/foo/', getParentRoute: () => layoutRoute, } as any) -const HelloFooIdRoute = HelloFooIdImport.update({ +const HelloFooIdRoute = HelloFooIdRouteImport.update({ id: '/hello/foo/$id', path: '/hello/foo/$id', getParentRoute: () => layoutRoute, } as any) -const dbInvoiceDetailRoute = dbInvoiceDetailImport.update({ +const dbInvoiceDetailRoute = dbInvoiceDetailRouteImport.update({ id: '/$id', path: '/$id', getParentRoute: () => dbDashboardInvoicesRoute, } as any) -const dbInvoicesIndexRoute = dbInvoicesIndexImport.update({ +const dbInvoicesIndexRoute = dbInvoicesIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => dbDashboardInvoicesRoute, @@ -110,89 +111,192 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof indexImport + preLoaderRoute: typeof indexRouteImport parentRoute: typeof rootRoute } '/$lang': { id: '/$lang' path: '/$lang' fullPath: '/$lang' - preLoaderRoute: typeof LangImport + preLoaderRoute: typeof LangRouteImport parentRoute: typeof rootRoute } '/_layout': { id: '/_layout' path: '' fullPath: '' - preLoaderRoute: typeof layoutImport + preLoaderRoute: typeof layoutRouteImport parentRoute: typeof rootRoute } '/$lang/': { id: '/$lang/' path: '/' fullPath: '/$lang/' - preLoaderRoute: typeof pagesImport - parentRoute: typeof LangImport + preLoaderRoute: typeof pagesRouteImport + parentRoute: typeof LangRouteImport } '/_layout/dashboard': { id: '/_layout/dashboard' path: '/dashboard' fullPath: '/dashboard' - preLoaderRoute: typeof dbDashboardImport - parentRoute: typeof layoutImport + preLoaderRoute: typeof dbDashboardRouteImport + parentRoute: typeof layoutRouteImport } '/_layout/dashboard/': { id: '/_layout/dashboard/' path: '/' fullPath: '/dashboard/' - preLoaderRoute: typeof dbDashboardIndexImport - parentRoute: typeof dbDashboardImport + preLoaderRoute: typeof dbDashboardIndexRouteImport + parentRoute: typeof dbDashboardRouteImport } '/_layout/dashboard/invoices': { id: '/_layout/dashboard/invoices' path: '/invoices' fullPath: '/dashboard/invoices' - preLoaderRoute: typeof dbDashboardInvoicesImport - parentRoute: typeof dbDashboardImport + preLoaderRoute: typeof dbDashboardInvoicesRouteImport + parentRoute: typeof dbDashboardRouteImport } '/_layout/hello/': { id: '/_layout/hello/' path: '/hello' fullPath: '/hello' - preLoaderRoute: typeof HelloIndexImport - parentRoute: typeof layoutImport + preLoaderRoute: typeof HelloIndexRouteImport + parentRoute: typeof layoutRouteImport } '/_layout/dashboard/invoices/': { id: '/_layout/dashboard/invoices/' path: '/' fullPath: '/dashboard/invoices/' - preLoaderRoute: typeof dbInvoicesIndexImport - parentRoute: typeof dbDashboardInvoicesImport + preLoaderRoute: typeof dbInvoicesIndexRouteImport + parentRoute: typeof dbDashboardInvoicesRouteImport } '/_layout/dashboard/invoices/$id': { id: '/_layout/dashboard/invoices/$id' path: '/$id' fullPath: '/dashboard/invoices/$id' - preLoaderRoute: typeof dbInvoiceDetailImport - parentRoute: typeof dbDashboardInvoicesImport + preLoaderRoute: typeof dbInvoiceDetailRouteImport + parentRoute: typeof dbDashboardInvoicesRouteImport } '/_layout/hello/foo/$id': { id: '/_layout/hello/foo/$id' path: '/hello/foo/$id' fullPath: '/hello/foo/$id' - preLoaderRoute: typeof HelloFooIdImport - parentRoute: typeof layoutImport + preLoaderRoute: typeof HelloFooIdRouteImport + parentRoute: typeof layoutRouteImport } '/_layout/hello/foo/': { id: '/_layout/hello/foo/' path: '/hello/foo' fullPath: '/hello/foo' - preLoaderRoute: typeof HelloFooIndexImport - parentRoute: typeof layoutImport + preLoaderRoute: typeof HelloFooIndexRouteImport + parentRoute: typeof layoutRouteImport } } } +// Add type-safety to the createFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} + +declare module './routes/layout' { + const createFileRoute: CreateFileRoute< + '/_layout', + FileRoutesByPath['/_layout']['parentRoute'], + FileRoutesByPath['/_layout']['id'], + FileRoutesByPath['/_layout']['path'], + FileRoutesByPath['/_layout']['fullPath'] + > +} +declare module './routes/pages' { + const createFileRoute: CreateFileRoute< + '/$lang/', + FileRoutesByPath['/$lang/']['parentRoute'], + FileRoutesByPath['/$lang/']['id'], + FileRoutesByPath['/$lang/']['path'], + FileRoutesByPath['/$lang/']['fullPath'] + > +} +declare module './routes/db/dashboard' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard', + FileRoutesByPath['/_layout/dashboard']['parentRoute'], + FileRoutesByPath['/_layout/dashboard']['id'], + FileRoutesByPath['/_layout/dashboard']['path'], + FileRoutesByPath['/_layout/dashboard']['fullPath'] + > +} +declare module './routes/db/dashboard-index' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard/', + FileRoutesByPath['/_layout/dashboard/']['parentRoute'], + FileRoutesByPath['/_layout/dashboard/']['id'], + FileRoutesByPath['/_layout/dashboard/']['path'], + FileRoutesByPath['/_layout/dashboard/']['fullPath'] + > +} +declare module './routes/db/dashboard-invoices' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard/invoices', + FileRoutesByPath['/_layout/dashboard/invoices']['parentRoute'], + FileRoutesByPath['/_layout/dashboard/invoices']['id'], + FileRoutesByPath['/_layout/dashboard/invoices']['path'], + FileRoutesByPath['/_layout/dashboard/invoices']['fullPath'] + > +} +declare module './routes/subtree/index' { + const createFileRoute: CreateFileRoute< + '/_layout/hello/', + FileRoutesByPath['/_layout/hello/']['parentRoute'], + FileRoutesByPath['/_layout/hello/']['id'], + FileRoutesByPath['/_layout/hello/']['path'], + FileRoutesByPath['/_layout/hello/']['fullPath'] + > +} +declare module './routes/db/invoices-index' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard/invoices/', + FileRoutesByPath['/_layout/dashboard/invoices/']['parentRoute'], + FileRoutesByPath['/_layout/dashboard/invoices/']['id'], + FileRoutesByPath['/_layout/dashboard/invoices/']['path'], + FileRoutesByPath['/_layout/dashboard/invoices/']['fullPath'] + > +} +declare module './routes/db/invoice-detail' { + const createFileRoute: CreateFileRoute< + '/_layout/dashboard/invoices/$id', + FileRoutesByPath['/_layout/dashboard/invoices/$id']['parentRoute'], + FileRoutesByPath['/_layout/dashboard/invoices/$id']['id'], + FileRoutesByPath['/_layout/dashboard/invoices/$id']['path'], + FileRoutesByPath['/_layout/dashboard/invoices/$id']['fullPath'] + > +} +declare module './routes/subtree/foo/$id' { + const createFileRoute: CreateFileRoute< + '/_layout/hello/foo/$id', + FileRoutesByPath['/_layout/hello/foo/$id']['parentRoute'], + FileRoutesByPath['/_layout/hello/foo/$id']['id'], + FileRoutesByPath['/_layout/hello/foo/$id']['path'], + FileRoutesByPath['/_layout/hello/foo/$id']['fullPath'] + > +} +declare module './routes/subtree/foo/index' { + const createFileRoute: CreateFileRoute< + '/_layout/hello/foo/', + FileRoutesByPath['/_layout/hello/foo/']['parentRoute'], + FileRoutesByPath['/_layout/hello/foo/']['id'], + FileRoutesByPath['/_layout/hello/foo/']['path'], + FileRoutesByPath['/_layout/hello/foo/']['fullPath'] + > +} + // Create and export the route tree interface LangRouteChildren { 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 index a92fc772c3..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual/routes/db/dashboard-index.tsx +++ b/packages/router-generator/tests/generator/virtual/routes/db/dashboard-index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard/')({ +export const Route = createFileRoute({ 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 index bf7e5a02b2..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual/routes/db/dashboard-invoices.tsx +++ b/packages/router-generator/tests/generator/virtual/routes/db/dashboard-invoices.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard/invoices')({ +export const Route = createFileRoute({ 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 index d5b4f49706..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual/routes/db/dashboard.tsx +++ b/packages/router-generator/tests/generator/virtual/routes/db/dashboard.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard')({ +export const Route = createFileRoute({ 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 index e7be6c1910..a1ed3d4a28 100644 --- a/packages/router-generator/tests/generator/virtual/routes/db/invoice-detail.tsx +++ b/packages/router-generator/tests/generator/virtual/routes/db/invoice-detail.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard/invoices/$id')({ +export const Route = createFileRoute({ 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 index f2e56721b6..960e382af9 100644 --- a/packages/router-generator/tests/generator/virtual/routes/db/invoices-index.tsx +++ b/packages/router-generator/tests/generator/virtual/routes/db/invoices-index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/dashboard/invoices/')({ +export const Route = createFileRoute({ 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 index a294139860..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual/routes/index.tsx +++ b/packages/router-generator/tests/generator/virtual/routes/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/')({ +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 index 2e48e48410..67e477a70a 100644 --- a/packages/router-generator/tests/generator/virtual/routes/layout.tsx +++ b/packages/router-generator/tests/generator/virtual/routes/layout.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout')({ +export const Route = createFileRoute({ component: () =>
Hello !
, }) diff --git a/packages/router-generator/tests/generator/virtual/routes/pages.tsx b/packages/router-generator/tests/generator/virtual/routes/pages.tsx index a942c7ce75..488a59a55a 100644 --- a/packages/router-generator/tests/generator/virtual/routes/pages.tsx +++ b/packages/router-generator/tests/generator/virtual/routes/pages.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/$lang/')({ +export const Route = createFileRoute({ component: RouteComponent, }) 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 index d8cbd795a7..8418001767 100644 --- a/packages/router-generator/tests/generator/virtual/routes/subtree/foo/$id.tsx +++ b/packages/router-generator/tests/generator/virtual/routes/subtree/foo/$id.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/hello/foo/$id')({ +export const Route = createFileRoute({ 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 index 10233de496..84660c4d04 100644 --- a/packages/router-generator/tests/generator/virtual/routes/subtree/foo/index.tsx +++ b/packages/router-generator/tests/generator/virtual/routes/subtree/foo/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/hello/foo/')({ +export const Route = createFileRoute({ 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 index 3367799b96..22cab82307 100644 --- a/packages/router-generator/tests/generator/virtual/routes/subtree/index.tsx +++ b/packages/router-generator/tests/generator/virtual/routes/subtree/index.tsx @@ -1,5 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_layout/hello/')({ +export const Route = createFileRoute({ component: () =>
Hello /!
, }) diff --git a/packages/router-plugin/package.json b/packages/router-plugin/package.json index 1b0e9ebefc..fdecca8cbc 100644 --- a/packages/router-plugin/package.json +++ b/packages/router-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/router-plugin", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/router-plugin/src/core/code-splitter/compilers.ts b/packages/router-plugin/src/core/code-splitter/compilers.ts index 91ca8ccf79..71243f30a1 100644 --- a/packages/router-plugin/src/core/code-splitter/compilers.ts +++ b/packages/router-plugin/src/core/code-splitter/compilers.ts @@ -7,33 +7,13 @@ import { } from 'babel-dead-code-elimination' import { generateFromAst, parseAst } from '@tanstack/router-utils' import { tsrSplit } from '../constants' +import { routeHmrStatement } from '../route-hmr-statement' import { createIdentifier } from './path-ids' import { getFrameworkOptions } from './framework-options' import type { GeneratorResult, ParseAstOptions } from '@tanstack/router-utils' import type { CodeSplitGroupings, SplitRouteIdentNodes } from '../constants' import type { Config } from '../config' -// eslint-disable-next-line unused-imports/no-unused-vars -const debug = process.env.TSR_VITE_DEBUG - -type SplitModulesById = Record< - string, - { id: string; node: t.FunctionExpression } -> - -interface State { - filename: string - opts: { - minify: boolean - root: string - } - imported: Record - refs: Set - serverIndex: number - splitIndex: number - splitModulesById: SplitModulesById -} - type SplitNodeMeta = { routeIdent: SplitRouteIdentNodes splitStrategy: 'lazyFn' | 'lazyRouteComponent' @@ -117,6 +97,8 @@ export function compileCodeSplitReferenceRoute( runtimeEnv: 'dev' | 'prod' codeSplitGroupings: CodeSplitGroupings targetFramework: Config['target'] + filename: string + id: string }, ): GeneratorResult { const ast = parseAst(opts) @@ -136,9 +118,7 @@ export function compileCodeSplitReferenceRoute( babel.traverse(ast, { Program: { - enter(programPath, programState) { - const state = programState as unknown as State - + enter(programPath) { /** * If the component for the route is being imported from * another file, this is to track the path to that file @@ -150,229 +130,228 @@ export function compileCodeSplitReferenceRoute( */ const removableImportPaths = new Set([]) - programPath.traverse( - { - CallExpression: (path) => { - if (!t.isIdentifier(path.node.callee)) { - return - } - - if ( - !( - path.node.callee.name === 'createRoute' || - path.node.callee.name === 'createFileRoute' - ) - ) { - return - } + programPath.traverse({ + CallExpression: (path) => { + if (!t.isIdentifier(path.node.callee)) { + return + } - if (t.isCallExpression(path.parentPath.node)) { - const options = resolveIdentifier( - path, - path.parentPath.node.arguments[0], - ) + if ( + !( + path.node.callee.name === 'createRoute' || + path.node.callee.name === 'createFileRoute' + ) + ) { + return + } - const hasImportedOrDefinedIdentifier = (name: string) => { - return programPath.scope.hasBinding(name) - } + function babelHandleReference(routeOptions: t.Node | undefined) { + const hasImportedOrDefinedIdentifier = (name: string) => { + return programPath.scope.hasBinding(name) + } - if (t.isObjectExpression(options)) { - options.properties.forEach((prop) => { - if (t.isObjectProperty(prop)) { - if (t.isIdentifier(prop.key)) { - // If the user has not specified a split grouping for this key - // then we should not split it - const codeSplitGroupingByKey = findIndexForSplitNode( - prop.key.name, - ) - if (codeSplitGroupingByKey === -1) { - return - } - const codeSplitGroup = [ - ...new Set( - opts.codeSplitGroupings[codeSplitGroupingByKey], - ), - ] - - const key = prop.key.name - // find key in nodeSplitConfig - const isNodeConfigAvailable = SPLIT_NODES_CONFIG.has( - key as any, - ) - - if (!isNodeConfigAvailable) { - return - } + if (t.isObjectExpression(routeOptions)) { + routeOptions.properties.forEach((prop) => { + if (t.isObjectProperty(prop)) { + if (t.isIdentifier(prop.key)) { + // If the user has not specified a split grouping for this key + // then we should not split it + const codeSplitGroupingByKey = findIndexForSplitNode( + prop.key.name, + ) + if (codeSplitGroupingByKey === -1) { + return + } + const codeSplitGroup = [ + ...new Set( + opts.codeSplitGroupings[codeSplitGroupingByKey], + ), + ] + + const key = prop.key.name + // find key in nodeSplitConfig + const isNodeConfigAvailable = SPLIT_NODES_CONFIG.has( + key as any, + ) + + if (!isNodeConfigAvailable) { + return + } - const splitNodeMeta = SPLIT_NODES_CONFIG.get( - key as any, - )! + const splitNodeMeta = SPLIT_NODES_CONFIG.get(key as any)! - // We need to extract the existing search params from the filename, if any - // and add the relevant codesplitPrefix to them, then write them back to the filename - const splitUrl = addSplitSearchParamToFilename( - opts.filename, - codeSplitGroup, - ) + // We need to extract the existing search params from the filename, if any + // and add the relevant codesplitPrefix to them, then write them back to the filename + const splitUrl = addSplitSearchParamToFilename( + opts.filename, + codeSplitGroup, + ) - if ( - splitNodeMeta.splitStrategy === 'lazyRouteComponent' - ) { - const value = prop.value - - let shouldSplit = true - - if (t.isIdentifier(value)) { - const existingImportPath = - getImportSpecifierAndPathFromLocalName( - programPath, - value.name, - ).path - if (existingImportPath) { - removableImportPaths.add(existingImportPath) - } + if ( + splitNodeMeta.splitStrategy === 'lazyRouteComponent' + ) { + const value = prop.value - // exported identifiers should not be split - // since they are already being imported - // and need to be retained in the compiled file - const isExported = hasExport(ast, value) - shouldSplit = !isExported + let shouldSplit = true - if (shouldSplit) { - removeIdentifierLiteral(path, value) - } - } - - if (!shouldSplit) { - return + if (t.isIdentifier(value)) { + const existingImportPath = + getImportSpecifierAndPathFromLocalName( + programPath, + value.name, + ).path + if (existingImportPath) { + removableImportPaths.add(existingImportPath) } - // Prepend the import statement to the program along with the importer function - // Check to see if lazyRouteComponent is already imported before attempting - // to import it again + // exported identifiers should not be split + // since they are already being imported + // and need to be retained in the compiled file + const isExported = hasExport(ast, value) + shouldSplit = !isExported - if ( - !hasImportedOrDefinedIdentifier( - LAZY_ROUTE_COMPONENT_IDENT, - ) - ) { - programPath.unshiftContainer('body', [ - template.statement( - `import { ${LAZY_ROUTE_COMPONENT_IDENT} } from '${PACKAGE}'`, - )(), - ]) + if (shouldSplit) { + removeIdentifierLiteral(path, value) } + } - // Check to see if the importer function is already defined - // If not, define it with the dynamic import statement - if ( - !hasImportedOrDefinedIdentifier( - splitNodeMeta.localImporterIdent, - ) - ) { - programPath.unshiftContainer('body', [ - template.statement( - `const ${splitNodeMeta.localImporterIdent} = () => import('${splitUrl}')`, - )(), - ]) - } + if (!shouldSplit) { + return + } - // If it's a component, we need to pass the function to check the Route.ssr value - if (key === 'component') { - prop.value = template.expression( - `${LAZY_ROUTE_COMPONENT_IDENT}(${splitNodeMeta.localImporterIdent}, '${splitNodeMeta.exporterIdent}', () => Route.ssr)`, - )() - } else { - prop.value = template.expression( - `${LAZY_ROUTE_COMPONENT_IDENT}(${splitNodeMeta.localImporterIdent}, '${splitNodeMeta.exporterIdent}')`, - )() - } + // Prepend the import statement to the program along with the importer function + // Check to see if lazyRouteComponent is already imported before attempting + // to import it again - // If the TSRDummyComponent is not defined, define it - if ( - opts.runtimeEnv !== 'prod' && // only in development - !hasImportedOrDefinedIdentifier( - frameworkOptions.idents.dummyHMRComponent, - ) - ) { - programPath.pushContainer('body', [ - template.statement( - frameworkOptions.dummyHMRComponent, - )(), - ]) - } + if ( + !hasImportedOrDefinedIdentifier( + LAZY_ROUTE_COMPONENT_IDENT, + ) + ) { + programPath.unshiftContainer('body', [ + template.statement( + `import { ${LAZY_ROUTE_COMPONENT_IDENT} } from '${PACKAGE}'`, + )(), + ]) } - if (splitNodeMeta.splitStrategy === 'lazyFn') { - const value = prop.value + // Check to see if the importer function is already defined + // If not, define it with the dynamic import statement + if ( + !hasImportedOrDefinedIdentifier( + splitNodeMeta.localImporterIdent, + ) + ) { + programPath.unshiftContainer('body', [ + template.statement( + `const ${splitNodeMeta.localImporterIdent} = () => import('${splitUrl}')`, + )(), + ]) + } - let shouldSplit = true + // If it's a component, we need to pass the function to check the Route.ssr value + if (key === 'component') { + prop.value = template.expression( + `${LAZY_ROUTE_COMPONENT_IDENT}(${splitNodeMeta.localImporterIdent}, '${splitNodeMeta.exporterIdent}', () => Route.ssr)`, + )() + } else { + prop.value = template.expression( + `${LAZY_ROUTE_COMPONENT_IDENT}(${splitNodeMeta.localImporterIdent}, '${splitNodeMeta.exporterIdent}')`, + )() + } - if (t.isIdentifier(value)) { - const existingImportPath = - getImportSpecifierAndPathFromLocalName( - programPath, - value.name, - ).path - if (existingImportPath) { - removableImportPaths.add(existingImportPath) - } + // add HMR handling + if (opts.runtimeEnv !== 'prod') { + programPath.pushContainer('body', routeHmrStatement) + } + } - // exported identifiers should not be split - // since they are already being imported - // and need to be retained in the compiled file - const isExported = hasExport(ast, value) - shouldSplit = !isExported + if (splitNodeMeta.splitStrategy === 'lazyFn') { + const value = prop.value - if (shouldSplit) { - removeIdentifierLiteral(path, value) - } - } + let shouldSplit = true - if (!shouldSplit) { - return + if (t.isIdentifier(value)) { + const existingImportPath = + getImportSpecifierAndPathFromLocalName( + programPath, + value.name, + ).path + if (existingImportPath) { + removableImportPaths.add(existingImportPath) } - // Prepend the import statement to the program along with the importer function - if (!hasImportedOrDefinedIdentifier(LAZY_FN_IDENT)) { - programPath.unshiftContainer( - 'body', - template.smart( - `import { ${LAZY_FN_IDENT} } from '${PACKAGE}'`, - )(), - ) - } + // exported identifiers should not be split + // since they are already being imported + // and need to be retained in the compiled file + const isExported = hasExport(ast, value) + shouldSplit = !isExported - // Check to see if the importer function is already defined - // If not, define it with the dynamic import statement - if ( - !hasImportedOrDefinedIdentifier( - splitNodeMeta.localImporterIdent, - ) - ) { - programPath.unshiftContainer('body', [ - template.statement( - `const ${splitNodeMeta.localImporterIdent} = () => import('${splitUrl}')`, - )(), - ]) + if (shouldSplit) { + removeIdentifierLiteral(path, value) } + } - // Add the lazyFn call with the dynamic import to the prop value - prop.value = template.expression( - `${LAZY_FN_IDENT}(${splitNodeMeta.localImporterIdent}, '${splitNodeMeta.exporterIdent}')`, - )() + if (!shouldSplit) { + return + } + + // Prepend the import statement to the program along with the importer function + if (!hasImportedOrDefinedIdentifier(LAZY_FN_IDENT)) { + programPath.unshiftContainer( + 'body', + template.smart( + `import { ${LAZY_FN_IDENT} } from '${PACKAGE}'`, + )(), + ) + } + + // Check to see if the importer function is already defined + // If not, define it with the dynamic import statement + if ( + !hasImportedOrDefinedIdentifier( + splitNodeMeta.localImporterIdent, + ) + ) { + programPath.unshiftContainer('body', [ + template.statement( + `const ${splitNodeMeta.localImporterIdent} = () => import('${splitUrl}')`, + )(), + ]) } + + // Add the lazyFn call with the dynamic import to the prop value + prop.value = template.expression( + `${LAZY_FN_IDENT}(${splitNodeMeta.localImporterIdent}, '${splitNodeMeta.exporterIdent}')`, + )() } } + } - programPath.scope.crawl() - }) - } + programPath.scope.crawl() + }) } - }, + } + + if (t.isCallExpression(path.parentPath.node)) { + // createFileRoute('/')({ ... }) + const options = resolveIdentifier( + path, + path.parentPath.node.arguments[0], + ) + + babelHandleReference(options) + } else if (t.isVariableDeclarator(path.parentPath.node)) { + // createFileRoute({ ... }) + const caller = resolveIdentifier(path, path.parentPath.node.init) + + if (t.isCallExpression(caller)) { + const options = resolveIdentifier(path, caller.arguments[0]) + babelHandleReference(options) + } + } }, - state, - ) + }) /** * If the component for the route is being imported, @@ -406,6 +385,7 @@ export function compileCodeSplitReferenceRoute( export function compileCodeSplitVirtualRoute( opts: ParseAstOptions & { splitTargets: Array + filename: string }, ): GeneratorResult { const ast = parseAst(opts) @@ -417,9 +397,7 @@ export function compileCodeSplitVirtualRoute( babel.traverse(ast, { Program: { - enter(programPath, programState) { - const state = programState as unknown as State - + enter(programPath) { const trackedNodesToSplitByType: Record< SplitRouteIdentNodes, { node: t.Node | undefined; meta: SplitNodeMeta } | undefined @@ -432,75 +410,85 @@ export function compileCodeSplitVirtualRoute( } // Find and track all the known split-able nodes - programPath.traverse( - { - CallExpression: (path) => { - if (!t.isIdentifier(path.node.callee)) { - return - } - - if ( - !( - path.node.callee.name === 'createRoute' || - path.node.callee.name === 'createFileRoute' - ) - ) { - return - } + programPath.traverse({ + CallExpression: (path) => { + if (!t.isIdentifier(path.node.callee)) { + return + } - if (t.isCallExpression(path.parentPath.node)) { - const options = resolveIdentifier( - path, - path.parentPath.node.arguments[0], - ) + if ( + !( + path.node.callee.name === 'createRoute' || + path.node.callee.name === 'createFileRoute' + ) + ) { + return + } - if (t.isObjectExpression(options)) { - options.properties.forEach((prop) => { - if (t.isObjectProperty(prop)) { - // do not use `intendedSplitNodes` here - // since we have special considerations that need - // to be accounted for like (not splitting exported identifiers) - KNOWN_SPLIT_ROUTE_IDENTS.forEach((splitType) => { - if ( - !t.isIdentifier(prop.key) || - prop.key.name !== splitType - ) { - return - } + function babelHandleVirtual(options: t.Node | undefined) { + if (t.isObjectExpression(options)) { + options.properties.forEach((prop) => { + if (t.isObjectProperty(prop)) { + // do not use `intendedSplitNodes` here + // since we have special considerations that need + // to be accounted for like (not splitting exported identifiers) + KNOWN_SPLIT_ROUTE_IDENTS.forEach((splitType) => { + if ( + !t.isIdentifier(prop.key) || + prop.key.name !== splitType + ) { + return + } - const value = prop.value + const value = prop.value - let isExported = false - if (t.isIdentifier(value)) { - isExported = hasExport(ast, value) - if (isExported) { - knownExportedIdents.add(value.name) - } + let isExported = false + if (t.isIdentifier(value)) { + isExported = hasExport(ast, value) + if (isExported) { + knownExportedIdents.add(value.name) } + } - // If the node is exported, we need to remove - // the export from the split file - if (isExported && t.isIdentifier(value)) { - removeExports(ast, value) - } else { - const meta = SPLIT_NODES_CONFIG.get(splitType)! - trackedNodesToSplitByType[splitType] = { - node: prop.value, - meta, - } + // If the node is exported, we need to remove + // the export from the split file + if (isExported && t.isIdentifier(value)) { + removeExports(ast, value) + } else { + const meta = SPLIT_NODES_CONFIG.get(splitType)! + trackedNodesToSplitByType[splitType] = { + node: prop.value, + meta, } - }) - } - }) + } + }) + } + }) - // Remove all of the options - options.properties = [] - } + // Remove all of the options + options.properties = [] } - }, + } + + if (t.isCallExpression(path.parentPath.node)) { + // createFileRoute('/')({ ... }) + const options = resolveIdentifier( + path, + path.parentPath.node.arguments[0], + ) + + babelHandleVirtual(options) + } else if (t.isVariableDeclarator(path.parentPath.node)) { + // createFileRoute({ ... }) + const caller = resolveIdentifier(path, path.parentPath.node.init) + + if (t.isCallExpression(caller)) { + const options = resolveIdentifier(path, caller.arguments[0]) + babelHandleVirtual(options) + } + } }, - state, - ) + }) // Start the transformation to only exported the intended split nodes intendedSplitNodes.forEach((SPLIT_TYPE) => { @@ -841,7 +829,7 @@ function getImportSpecifierAndPathFromLocalName( } // Reusable function to get literal value or resolve variable to literal -function resolveIdentifier(path: any, node: any) { +function resolveIdentifier(path: any, node: any): t.Node | undefined { if (t.isIdentifier(node)) { const binding = path.scope.getBinding(node.name) if ( diff --git a/packages/router-plugin/src/core/code-splitter/framework-options.ts b/packages/router-plugin/src/core/code-splitter/framework-options.ts index 909f7607d6..860178b1f1 100644 --- a/packages/router-plugin/src/core/code-splitter/framework-options.ts +++ b/packages/router-plugin/src/core/code-splitter/framework-options.ts @@ -4,9 +4,7 @@ type FrameworkOptions = { createFileRoute: string lazyFn: string lazyRouteComponent: string - dummyHMRComponent: string } - dummyHMRComponent: string } export function getFrameworkOptions(framework: string): FrameworkOptions { @@ -20,9 +18,7 @@ export function getFrameworkOptions(framework: string): FrameworkOptions { createFileRoute: 'createFileRoute', lazyFn: 'lazyFn', lazyRouteComponent: 'lazyRouteComponent', - dummyHMRComponent: 'TSRDummyComponent', }, - dummyHMRComponent: `export function TSRDummyComponent() { return null }`, } break case 'solid': @@ -32,9 +28,7 @@ export function getFrameworkOptions(framework: string): FrameworkOptions { createFileRoute: 'createFileRoute', lazyFn: 'lazyFn', lazyRouteComponent: 'lazyRouteComponent', - dummyHMRComponent: 'TSRDummyComponent', }, - dummyHMRComponent: `export function TSRDummyComponent() { return null }`, } break default: diff --git a/packages/router-plugin/src/core/config.ts b/packages/router-plugin/src/core/config.ts index cdcbac4414..b6934c3e10 100644 --- a/packages/router-plugin/src/core/config.ts +++ b/packages/router-plugin/src/core/config.ts @@ -3,6 +3,7 @@ import { configSchema as generatorConfigSchema, getConfig as getGeneratorConfig, } from '@tanstack/router-generator' +import type { ConfigOptions as GeneratorConfigOptions } from '@tanstack/router-generator'; import type { RegisteredRouter, RouteIds } from '@tanstack/router-core' import type { CodeSplitGroupings } from './constants' @@ -62,6 +63,18 @@ const codeSplittingOptionsSchema = z.object({ defaultBehavior: splitGroupingsSchema.optional(), }) +export interface ConfigOptions extends GeneratorConfigOptions { + /** + * Enables route generation. + * @default true + */ + enableRouteGeneration?: boolean + /** + * Additional fine grained control for splitting. + */ + codeSplittingOptions?: CodeSplittingOptions +} + export const configSchema = generatorConfigSchema.extend({ enableRouteGeneration: z.boolean().optional(), codeSplittingOptions: z @@ -69,12 +82,14 @@ export const configSchema = generatorConfigSchema.extend({ return codeSplittingOptionsSchema.parse(v) }) .optional(), -}) +}) satisfies z.ZodType -export const getConfig = (inlineConfig: Partial, root: string) => { +export const getConfig = (inlineConfig: ConfigOptions, root: string) => { const config = getGeneratorConfig(inlineConfig, root) return configSchema.parse({ ...config, ...inlineConfig }) } export type Config = z.infer +export type ConfigInput = z.input +export type ConfigOutput = z.output diff --git a/packages/router-plugin/src/core/route-autoimport-plugin.ts b/packages/router-plugin/src/core/route-autoimport-plugin.ts new file mode 100644 index 0000000000..fb7e59a786 --- /dev/null +++ b/packages/router-plugin/src/core/route-autoimport-plugin.ts @@ -0,0 +1,102 @@ +import { generateFromAst, logDiff, parseAst } from '@tanstack/router-utils' +import babel from '@babel/core' +import * as template from '@babel/template' +import { getConfig } from './config' +import { debug, fileIsInRoutesDirectory } from './utils' +import type { Config, ConfigOptions } from './config' +import type { UnpluginFactory } from 'unplugin' + +/** + * This plugin adds imports for createFileRoute and createLazyFileRoute to the file route. + */ +export const unpluginRouteAutoImportFactory: UnpluginFactory< + ConfigOptions | undefined +> = (options = {}) => { + let ROOT: string = process.cwd() + let userConfig = options as Config + + return { + name: 'router-autoimport-plugin', + enforce: 'pre', + + transform(code, id) { + let routeType: 'createFileRoute' | 'createLazyFileRoute' + if (code.includes('export const Route = createFileRoute(')) { + routeType = 'createFileRoute' + } else if (code.includes('export const Route = createLazyFileRoute(')) { + routeType = 'createLazyFileRoute' + } else { + return null + } + + const routerImportPath = `@tanstack/${userConfig.target}-router` + + const ast = parseAst({ code }) + + let isCreateRouteFunctionImported = false as boolean + + babel.traverse(ast, { + Program: { + enter(programPath) { + programPath.traverse({ + ImportDeclaration(path) { + const importedSpecifiers = path.node.specifiers.map( + (specifier) => specifier.local.name, + ) + if ( + importedSpecifiers.includes(routeType) && + path.node.source.value === routerImportPath + ) { + isCreateRouteFunctionImported = true + } + }, + }) + }, + }, + }) + + if (!isCreateRouteFunctionImported) { + if (debug) console.info('Adding autoimports to route ', id) + + const autoImportStatement = template.statement( + `import { ${routeType} } from '${routerImportPath}'`, + )() + ast.program.body.unshift(autoImportStatement) + + const result = generateFromAst(ast, { + sourceMaps: true, + filename: id, + sourceFileName: id, + }) + if (debug) { + logDiff(code, result.code) + console.log('Output:\n', result.code + '\n\n') + } + return result + } + + return null + }, + + transformInclude(id) { + return fileIsInRoutesDirectory(id, userConfig.routesDirectory) + }, + + vite: { + configResolved(config) { + ROOT = config.root + userConfig = getConfig(options, ROOT) + }, + }, + + rspack() { + ROOT = process.cwd() + userConfig = getConfig(options, ROOT) + }, + + webpack() { + ROOT = process.cwd() + userConfig = getConfig(options, ROOT) + }, + } +} diff --git a/packages/router-plugin/src/core/route-hmr-statement.ts b/packages/router-plugin/src/core/route-hmr-statement.ts new file mode 100644 index 0000000000..73e66cf4cb --- /dev/null +++ b/packages/router-plugin/src/core/route-hmr-statement.ts @@ -0,0 +1,13 @@ +import * as template from '@babel/template' + +export const routeHmrStatement = template.statement( + ` +if (import.meta.hot) { + import.meta.hot.accept((newModule) => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route) + } + }) +} +`, +)() diff --git a/packages/router-plugin/src/core/router-code-splitter-plugin.ts b/packages/router-plugin/src/core/router-code-splitter-plugin.ts index 7c1ecc17a8..b98dfbb6a5 100644 --- a/packages/router-plugin/src/core/router-code-splitter-plugin.ts +++ b/packages/router-plugin/src/core/router-code-splitter-plugin.ts @@ -3,7 +3,6 @@ * https://github.com/TanStack/router/pull/3355 */ -import { isAbsolute, join, normalize } from 'node:path' import { fileURLToPath, pathToFileURL } from 'node:url' import { logDiff } from '@tanstack/router-utils' import { getConfig, splitGroupingsSchema } from './config' @@ -18,36 +17,20 @@ import { tsrSplit, } from './constants' import { decodeIdentifier } from './code-splitter/path-ids' +import { debug, fileIsInRoutesDirectory } from './utils' +import type { Config, ConfigOptions } from './config' import type { CodeSplitGroupings, SplitRouteIdentNodes } from './constants' -import type { Config } from './config' import type { UnpluginContextMeta, UnpluginFactory, TransformResult as UnpluginTransformResult, } from 'unplugin' -const debug = - process.env.TSR_VITE_DEBUG && - ['true', 'router-plugin'].includes(process.env.TSR_VITE_DEBUG) - function capitalizeFirst(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1) } -function fileIsInRoutesDirectory( - filePath: string, - routesDirectory: string, -): boolean { - const routesDirectoryPath = isAbsolute(routesDirectory) - ? routesDirectory - : join(process.cwd(), routesDirectory) - - const path = normalize(filePath) - - return path.startsWith(routesDirectoryPath) -} - type BannedBeforeExternalPlugin = { identifier: string pkg: string @@ -66,7 +49,7 @@ const bannedBeforeExternalPlugins: Array = [ class FoundPluginInBeforeCode extends Error { constructor(externalPlugin: BannedBeforeExternalPlugin, framework: string) { - super(`We detected that the '${externalPlugin.pkg}' was passed before '@tanstack/router-plugin'. Please make sure that '@tanstack/router-plugin' is passed before '${externalPlugin.pkg}' and try again: + super(`We detected that the '${externalPlugin.pkg}' was passed before '@tanstack/router-plugin'. Please make sure that '@tanstack/router-plugin' is passed before '${externalPlugin.pkg}' and try again: e.g. plugins: [ TanStackRouter${capitalizeFirst(framework)}(), // Place this before ${externalPlugin.usage} @@ -79,7 +62,7 @@ plugins: [ const PLUGIN_NAME = 'unplugin:router-code-splitter' export const unpluginRouterCodeSplitterFactory: UnpluginFactory< - Partial | undefined + ConfigOptions | undefined > = (options = {}, { framework }) => { let ROOT: string = process.cwd() let userConfig = options as Config @@ -104,8 +87,6 @@ export const unpluginRouterCodeSplitterFactory: UnpluginFactory< const fromCode = detectCodeSplitGroupingsFromRoute({ code, - root: ROOT, - filename: id, }) if (fromCode.groupings) { @@ -139,11 +120,11 @@ export const unpluginRouterCodeSplitterFactory: UnpluginFactory< const compiledReferenceRoute = compileCodeSplitReferenceRoute({ code, - root: ROOT, - filename: id, runtimeEnv: isProduction ? 'prod' : 'dev', codeSplitGroupings: splitGroupings, targetFramework: userConfig.target, + filename: id, + id, }) if (debug) { @@ -178,7 +159,6 @@ export const unpluginRouterCodeSplitterFactory: UnpluginFactory< const result = compileCodeSplitVirtualRoute({ code, - root: ROOT, filename: id, splitTargets: grouping, }) diff --git a/packages/router-plugin/src/core/router-composed-plugin.ts b/packages/router-plugin/src/core/router-composed-plugin.ts index a8256f8b4b..87ec590cac 100644 --- a/packages/router-plugin/src/core/router-composed-plugin.ts +++ b/packages/router-plugin/src/core/router-composed-plugin.ts @@ -1,22 +1,33 @@ import { unpluginRouterGeneratorFactory } from './router-generator-plugin' import { unpluginRouterCodeSplitterFactory } from './router-code-splitter-plugin' +import { unpluginRouterHmrFactory } from './router-hmr-plugin' +import { unpluginRouteAutoImportFactory } from './route-autoimport-plugin' +import type { ConfigOptions } from './config' -import type { Config } from './config' import type { UnpluginFactory } from 'unplugin' export const unpluginRouterComposedFactory: UnpluginFactory< - Partial | undefined + ConfigOptions | undefined > = (options = {}, meta) => { - const routerGenerator = unpluginRouterGeneratorFactory(options, meta) + const getPlugin = (pluginFactory: UnpluginFactory>) => { + const plugin = pluginFactory(options, meta) + if (!Array.isArray(plugin)) { + return [plugin] + } + return plugin + } - const routerGeneratorOptions = Array.isArray(routerGenerator) - ? routerGenerator - : [routerGenerator] + const routerGenerator = getPlugin(unpluginRouterGeneratorFactory) + const routerCodeSplitter = getPlugin(unpluginRouterCodeSplitterFactory) + const routeAutoImport = getPlugin(unpluginRouteAutoImportFactory) - const routerCodeSplitter = unpluginRouterCodeSplitterFactory(options, meta) - const routerCodeSplitterOptions = Array.isArray(routerCodeSplitter) - ? routerCodeSplitter - : [routerCodeSplitter] + const result = [...routerGenerator, ...routerCodeSplitter, ...routeAutoImport] - return [...routerGeneratorOptions, ...routerCodeSplitterOptions] + const isProduction = process.env.NODE_ENV === 'production' + + if (!isProduction && !options.autoCodeSplitting) { + const routerHmr = getPlugin(unpluginRouterHmrFactory) + result.push(...routerHmr) + } + return result } diff --git a/packages/router-plugin/src/core/router-generator-plugin.ts b/packages/router-plugin/src/core/router-generator-plugin.ts index f4cec60235..2933114878 100644 --- a/packages/router-plugin/src/core/router-generator-plugin.ts +++ b/packages/router-plugin/src/core/router-generator-plugin.ts @@ -2,9 +2,9 @@ import { isAbsolute, join, normalize, resolve } from 'node:path' import { generator, resolveConfigPath } from '@tanstack/router-generator' import { getConfig } from './config' +import type { Config, ConfigOptions } from './config'; import type { FSWatcher } from 'chokidar' import type { UnpluginFactory } from 'unplugin' -import type { Config } from './config' let lock = false const checkLock = () => lock @@ -15,7 +15,7 @@ const setLock = (bool: boolean) => { const PLUGIN_NAME = 'unplugin:router-generator' export const unpluginRouterGeneratorFactory: UnpluginFactory< - Partial | undefined + ConfigOptions | undefined > = (options = {}) => { let ROOT: string = process.cwd() let userConfig = options as Config @@ -82,12 +82,23 @@ export const unpluginRouterGeneratorFactory: UnpluginFactory< }) }, vite: { - async configResolved(config) { + configResolved(config) { ROOT = config.root userConfig = getConfig(options, ROOT) + // if (config.command === 'serve') { + // await run(generate) + // } + }, + async buildStart() { + if (this.environment.config.consumer === 'server') { + // When building in environment mode, we only need to generate routes + // for the client environment + return + } await run(generate) }, + sharedDuringBuild: true, }, rspack(compiler) { userConfig = getConfig(options, ROOT) diff --git a/packages/router-plugin/src/core/router-hmr-plugin.ts b/packages/router-plugin/src/core/router-hmr-plugin.ts new file mode 100644 index 0000000000..31be50648d --- /dev/null +++ b/packages/router-plugin/src/core/router-hmr-plugin.ts @@ -0,0 +1,65 @@ +import { generateFromAst, logDiff, parseAst } from '@tanstack/router-utils' +import { getConfig } from './config' +import { routeHmrStatement } from './route-hmr-statement' +import { debug, fileIsInRoutesDirectory } from './utils' +import type { Config, ConfigOptions } from './config' +import type { UnpluginFactory } from 'unplugin' + +/** + * This plugin adds HMR support for file routes. + * It is only added to the composed plugin in dev when autoCodeSplitting is disabled, since the code splitting plugin + * handles HMR for code-split routes itself. + */ +export const unpluginRouterHmrFactory: UnpluginFactory< + ConfigOptions | undefined +> = (options = {}) => { + let ROOT: string = process.cwd() + let userConfig = options as Config + + return { + name: 'router-hmr-plugin', + enforce: 'pre', + + transform(code, id) { + if (!code.includes('export const Route = createFileRoute(')) { + return null + } + + if (debug) console.info('Adding HMR handling to route ', id) + + const ast = parseAst({ code }) + ast.program.body.push(routeHmrStatement) + const result = generateFromAst(ast, { + sourceMaps: true, + filename: id, + sourceFileName: id, + }) + if (debug) { + logDiff(code, result.code) + console.log('Output:\n', result.code + '\n\n') + } + return result + }, + + transformInclude(id) { + return fileIsInRoutesDirectory(id, userConfig.routesDirectory) + }, + + vite: { + configResolved(config) { + ROOT = config.root + userConfig = getConfig(options, ROOT) + }, + }, + + rspack() { + ROOT = process.cwd() + userConfig = getConfig(options, ROOT) + }, + + webpack() { + ROOT = process.cwd() + userConfig = getConfig(options, ROOT) + }, + } +} diff --git a/packages/router-plugin/src/core/utils.ts b/packages/router-plugin/src/core/utils.ts new file mode 100644 index 0000000000..d866a2241f --- /dev/null +++ b/packages/router-plugin/src/core/utils.ts @@ -0,0 +1,18 @@ +import { isAbsolute, join, normalize } from 'node:path' + +export const debug = + process.env.TSR_VITE_DEBUG && + ['true', 'router-plugin'].includes(process.env.TSR_VITE_DEBUG) + +export function fileIsInRoutesDirectory( + filePath: string, + routesDirectory: string, +): boolean { + const routesDirectoryPath = isAbsolute(routesDirectory) + ? routesDirectory + : join(process.cwd(), routesDirectory) + + const path = normalize(filePath) + + return path.startsWith(routesDirectoryPath) +} diff --git a/packages/router-plugin/src/esbuild.ts b/packages/router-plugin/src/esbuild.ts index 10ffdaae57..c29c0e4d85 100644 --- a/packages/router-plugin/src/esbuild.ts +++ b/packages/router-plugin/src/esbuild.ts @@ -37,13 +37,13 @@ const TanStackRouterCodeSplitterEsbuild = createEsbuildPlugin( * @example * ```ts * export default { - * plugins: [TanStackRouterEsbuild()], + * plugins: [tanstackRouter()], * // ... * } * ``` */ const TanStackRouterEsbuild = createEsbuildPlugin(unpluginRouterComposedFactory) - +const tanstackRouter = TanStackRouterEsbuild export default TanStackRouterEsbuild export { @@ -51,6 +51,7 @@ export { TanStackRouterGeneratorEsbuild, TanStackRouterCodeSplitterEsbuild, TanStackRouterEsbuild, + tanstackRouter, } export type { Config } diff --git a/packages/router-plugin/src/index.ts b/packages/router-plugin/src/index.ts index 43e52c85d7..49d96dd9a6 100644 --- a/packages/router-plugin/src/index.ts +++ b/packages/router-plugin/src/index.ts @@ -1,4 +1,4 @@ -export { configSchema } from './core/config' +export { configSchema, getConfig } from './core/config' export { unpluginRouterCodeSplitterFactory } from './core/router-code-splitter-plugin' export { unpluginRouterGeneratorFactory } from './core/router-generator-plugin' -export type { Config } from './core/config' +export type { Config, ConfigInput, ConfigOutput } from './core/config' diff --git a/packages/router-plugin/src/rspack.ts b/packages/router-plugin/src/rspack.ts index ebcafb8b30..4f82e24560 100644 --- a/packages/router-plugin/src/rspack.ts +++ b/packages/router-plugin/src/rspack.ts @@ -47,7 +47,7 @@ const TanStackRouterCodeSplitterRspack = /* #__PURE__ */ createRspackPlugin( * // ... * tools: { * rspack: { - * plugins: [TanStackRouterRspack()], + * plugins: [tanstackRouter()], * }, * }, * }) @@ -56,12 +56,13 @@ const TanStackRouterCodeSplitterRspack = /* #__PURE__ */ createRspackPlugin( const TanStackRouterRspack = /* #__PURE__ */ createRspackPlugin( unpluginRouterComposedFactory, ) - +const tanstackRouter = TanStackRouterRspack export default TanStackRouterRspack export { configSchema, TanStackRouterRspack, TanStackRouterGeneratorRspack, TanStackRouterCodeSplitterRspack, + tanstackRouter, } export type { Config } diff --git a/packages/router-plugin/src/vite.ts b/packages/router-plugin/src/vite.ts index a66e942419..155f8ad159 100644 --- a/packages/router-plugin/src/vite.ts +++ b/packages/router-plugin/src/vite.ts @@ -4,32 +4,34 @@ import { configSchema } from './core/config' import { unpluginRouterCodeSplitterFactory } from './core/router-code-splitter-plugin' import { unpluginRouterGeneratorFactory } from './core/router-generator-plugin' import { unpluginRouterComposedFactory } from './core/router-composed-plugin' - +import { unpluginRouteAutoImportFactory } from './core/route-autoimport-plugin' import type { Config } from './core/config' +const tanstackRouterAutoImport = createVitePlugin( + unpluginRouteAutoImportFactory, +) + /** * @example * ```ts * export default defineConfig({ - * plugins: [TanStackRouterGeneratorVite()], + * plugins: [tanstackRouterGenerator()], * // ... * }) * ``` */ -const TanStackRouterGeneratorVite = createVitePlugin( - unpluginRouterGeneratorFactory, -) +const tanstackRouterGenerator = createVitePlugin(unpluginRouterGeneratorFactory) /** * @example * ```ts * export default defineConfig({ - * plugins: [TanStackRouterCodeSplitterVite()], + * plugins: [tanStackRouterCodeSplitter()], * // ... * }) * ``` */ -const TanStackRouterCodeSplitterVite = createVitePlugin( +const tanStackRouterCodeSplitter = createVitePlugin( unpluginRouterCodeSplitterFactory, ) @@ -37,18 +39,26 @@ const TanStackRouterCodeSplitterVite = createVitePlugin( * @example * ```ts * export default defineConfig({ - * plugins: [TanStackRouterVite()], + * plugins: [tanstackRouter()], * // ... * }) * ``` */ -const TanStackRouterVite = createVitePlugin(unpluginRouterComposedFactory) +const tanstackRouter = createVitePlugin(unpluginRouterComposedFactory) -export default TanStackRouterVite +/** + * @deprecated Use `tanstackRouter` instead. + */ +const TanStackRouterVite = tanstackRouter + +export default tanstackRouter export { configSchema, - TanStackRouterGeneratorVite, - TanStackRouterCodeSplitterVite, + tanstackRouterAutoImport, + tanStackRouterCodeSplitter, + tanstackRouterGenerator, TanStackRouterVite, + tanstackRouter, } + export type { Config } diff --git a/packages/router-plugin/src/webpack.ts b/packages/router-plugin/src/webpack.ts index 45e8c173eb..3b44448aa5 100644 --- a/packages/router-plugin/src/webpack.ts +++ b/packages/router-plugin/src/webpack.ts @@ -37,7 +37,7 @@ const TanStackRouterCodeSplitterWebpack = /* #__PURE__ */ createWebpackPlugin( * ```ts * export default { * // ... - * plugins: [TanStackRouterWebpack()], + * plugins: [tanstackRouter()], * } * ``` */ @@ -45,11 +45,13 @@ const TanStackRouterWebpack = /* #__PURE__ */ createWebpackPlugin( unpluginRouterComposedFactory, ) +const tanstackRouter = TanStackRouterWebpack export default TanStackRouterWebpack export { configSchema, TanStackRouterWebpack, TanStackRouterGeneratorWebpack, TanStackRouterCodeSplitterWebpack, + tanstackRouter, } export type { Config } diff --git a/packages/router-plugin/tests/code-splitter.test.ts b/packages/router-plugin/tests/code-splitter.test.ts index ec1bbec5e9..c4fa076cec 100644 --- a/packages/router-plugin/tests/code-splitter.test.ts +++ b/packages/router-plugin/tests/code-splitter.test.ts @@ -67,8 +67,8 @@ describe('code-splitter works', () => { const compileResult = compileCodeSplitReferenceRoute({ code, - root: dirs.files, filename, + id: filename, runtimeEnv: NODE_ENV === 'production' ? 'prod' : 'dev', codeSplitGroupings: grouping, targetFramework: framework, @@ -91,7 +91,6 @@ describe('code-splitter works', () => { const splitResult = compileCodeSplitVirtualRoute({ code, - root: dirs.files, filename: `${filename}?${ident}`, splitTargets: targets, }) diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/arrow-function.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/arrow-function.tsx index 0e48584a4a..d13fdc0a9a 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/arrow-function.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/arrow-function.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/posts')({ loader: fetchPosts, component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/chinese.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/chinese.tsx index dffbd70c4d..abe95e1645 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/chinese.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/chinese.tsx @@ -8,6 +8,10 @@ export const Route = createFileRoute('/')({ interface DemoProps { title: string; } -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/conditional-properties.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/conditional-properties.tsx index 26de4ca825..45da5048e8 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/conditional-properties.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/conditional-properties.tsx @@ -8,6 +8,10 @@ export const Route = createFileRoute('/posts')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: isEnabled ? TrueImport.loader : falseLoader }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/destructured-react-memo-imported-component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/destructured-react-memo-imported-component.tsx index 0fbc312626..7b57f3ebd9 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/destructured-react-memo-imported-component.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/destructured-react-memo-imported-component.tsx @@ -6,6 +6,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: importedLoader }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/export-default-component-and-normal-notFound.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/export-default-component-and-normal-notFound.tsx index 0c88bfe0ad..a0ab6c5ab1 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/export-default-component-and-normal-notFound.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/export-default-component-and-normal-notFound.tsx @@ -12,6 +12,10 @@ export default function Home() {

{one}

; } -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/function-declaration.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/function-declaration.tsx index c395bc44ee..ae10058a91 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/function-declaration.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/function-declaration.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/posts')({ loader: fetchPosts, component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/importAttribute.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/importAttribute.tsx index 8a221122d7..1207dee6d6 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/importAttribute.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/importAttribute.tsx @@ -4,6 +4,10 @@ import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-default-component-destructured-loader.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-default-component-destructured-loader.tsx index e23a496a74..f33aef1023 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-default-component-destructured-loader.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-default-component-destructured-loader.tsx @@ -6,6 +6,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: importedLoader }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-default-component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-default-component.tsx index 968e6633d4..19b8875997 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-default-component.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-default-component.tsx @@ -4,6 +4,10 @@ import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-errorComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-errorComponent.tsx index 0701029aa3..21a9069938 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-errorComponent.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-errorComponent.tsx @@ -6,6 +6,17 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), errorComponent: lazyRouteComponent($$splitErrorComponentImporter, 'errorComponent') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); +} +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-notFoundComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-notFoundComponent.tsx index 63787a44d6..9f608978f5 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-notFoundComponent.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-notFoundComponent.tsx @@ -6,6 +6,17 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), notFoundComponent: lazyRouteComponent($$splitNotFoundComponentImporter, 'notFoundComponent') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); +} +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-pendingComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-pendingComponent.tsx index 13cfc22f7b..763d8ff26c 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-pendingComponent.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported-pendingComponent.tsx @@ -6,6 +6,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), pendingComponent: importedPendingComponent }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported.tsx index c4a5d9dbc4..7baa2e3057 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/imported.tsx @@ -6,6 +6,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: importedLoader }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/inline.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/inline.tsx index 931f6bce74..c19e2898d5 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/inline.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/inline.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/')({ }); Route.addChildren([]); export const test = 'test'; -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/random-number.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/random-number.tsx index b229826efb..8b00e0aa9c 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/random-number.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/random-number.tsx @@ -30,6 +30,10 @@ export const Route = createFileRoute('/')({ }, component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/react-memo-component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/react-memo-component.tsx index dc266fa611..c5f946a469 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/react-memo-component.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/react-memo-component.tsx @@ -6,6 +6,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: importedLoader }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/react-memo-imported-component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/react-memo-imported-component.tsx index b1df7f4cf9..49922c6c9d 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/react-memo-imported-component.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/react-memo-imported-component.tsx @@ -6,6 +6,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: importedLoader }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/retain-exports-loader.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/retain-exports-loader.tsx index 2d40731c37..047970676d 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/retain-exports-loader.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/retain-exports-loader.tsx @@ -14,6 +14,10 @@ export const Route = createFileRoute('/_layout')({ export const SIDEBAR_WIDTH = '150px'; export const SIDEBAR_MINI_WIDTH = '80px'; const ASIDE_WIDTH = '250px'; -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/useStateDestructure.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/useStateDestructure.tsx index 6cfb35e525..103067c81a 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/useStateDestructure.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/useStateDestructure.tsx @@ -116,9 +116,9 @@ export default function VersionIndex() {

Full-document SSR, Streaming, Server Functions, bundling and more, - powered by TanStack Router, Vinxi,{' '} - Nitro and Vite. Ready to deploy to - your favorite hosting provider. + powered by TanStack Router, Nitro{' '} + and Vite. Ready to deploy to your favorite hosting + provider.

diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/using.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/using.tsx new file mode 100644 index 0000000000..abe0e68a9b --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/using.tsx @@ -0,0 +1,18 @@ +const DummyPostResource = (postId: string) => ({ + postData: { + id: postId, + title: 'dummy', + body: 'dummy' + }, + [Symbol.dispose]: () => console.log('disposing!') +}); +export const Route = createFileRoute({ + loader: ({ + params: { + postId + } + }) => { + using dummyPost = DummyPostResource(postId); + return dummyPost.postData; + } +}); \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/using@component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/using@component.tsx new file mode 100644 index 0000000000..ac756d42a8 --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/using@component.tsx @@ -0,0 +1 @@ +import { Route } from "using.tsx"; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/using@errorComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/using@errorComponent.tsx new file mode 100644 index 0000000000..ac756d42a8 --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/using@errorComponent.tsx @@ -0,0 +1 @@ +import { Route } from "using.tsx"; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/using@notFoundComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/using@notFoundComponent.tsx new file mode 100644 index 0000000000..ac756d42a8 --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/development/using@notFoundComponent.tsx @@ -0,0 +1 @@ +import { Route } from "using.tsx"; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/useStateDestructure.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/useStateDestructure.tsx index 6cfb35e525..103067c81a 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/useStateDestructure.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/useStateDestructure.tsx @@ -116,9 +116,9 @@ export default function VersionIndex() {

Full-document SSR, Streaming, Server Functions, bundling and more, - powered by TanStack Router, Vinxi,{' '} - Nitro and Vite. Ready to deploy to - your favorite hosting provider. + powered by TanStack Router, Nitro{' '} + and Vite. Ready to deploy to your favorite hosting + provider.

diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/using.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/using.tsx new file mode 100644 index 0000000000..abe0e68a9b --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/using.tsx @@ -0,0 +1,18 @@ +const DummyPostResource = (postId: string) => ({ + postData: { + id: postId, + title: 'dummy', + body: 'dummy' + }, + [Symbol.dispose]: () => console.log('disposing!') +}); +export const Route = createFileRoute({ + loader: ({ + params: { + postId + } + }) => { + using dummyPost = DummyPostResource(postId); + return dummyPost.postData; + } +}); \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/using@component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/using@component.tsx new file mode 100644 index 0000000000..ac756d42a8 --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/using@component.tsx @@ -0,0 +1 @@ +import { Route } from "using.tsx"; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/using@errorComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/using@errorComponent.tsx new file mode 100644 index 0000000000..ac756d42a8 --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/using@errorComponent.tsx @@ -0,0 +1 @@ +import { Route } from "using.tsx"; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/using@notFoundComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/using@notFoundComponent.tsx new file mode 100644 index 0000000000..ac756d42a8 --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/1-default/production/using@notFoundComponent.tsx @@ -0,0 +1 @@ +import { Route } from "using.tsx"; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/arrow-function.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/arrow-function.tsx index 7104674b73..99fdcb621a 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/arrow-function.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/arrow-function.tsx @@ -8,6 +8,10 @@ export const Route = createFileRoute('/posts')({ loader: lazyFn($$splitLoaderImporter, 'loader'), component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/chinese.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/chinese.tsx index 3efbe3595d..5dc9c6c39c 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/chinese.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/chinese.tsx @@ -8,6 +8,10 @@ export const Route = createFileRoute('/')({ interface DemoProps { title: string; } -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/conditional-properties.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/conditional-properties.tsx index a126bb6807..e59fb6b170 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/conditional-properties.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/conditional-properties.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/posts')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: lazyFn($$splitLoaderImporter, 'loader') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/destructured-react-memo-imported-component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/destructured-react-memo-imported-component.tsx index 65f2bfb918..1a97263515 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/destructured-react-memo-imported-component.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/destructured-react-memo-imported-component.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: lazyFn($$splitLoaderImporter, 'loader') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/export-default-component-and-normal-notFound.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/export-default-component-and-normal-notFound.tsx index 762ac36b1d..fc60c1de1c 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/export-default-component-and-normal-notFound.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/export-default-component-and-normal-notFound.tsx @@ -12,6 +12,10 @@ export default function Home() {

{one}

; } -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/function-declaration.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/function-declaration.tsx index d6e6fa8152..0c2b2f0f7f 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/function-declaration.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/function-declaration.tsx @@ -8,6 +8,10 @@ export const Route = createFileRoute('/posts')({ loader: lazyFn($$splitLoaderImporter, 'loader'), component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/importAttribute.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/importAttribute.tsx index b89aede427..c189737cc9 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/importAttribute.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/importAttribute.tsx @@ -4,6 +4,10 @@ import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-default-component-destructured-loader.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-default-component-destructured-loader.tsx index 9169f0b966..1519ca0183 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-default-component-destructured-loader.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-default-component-destructured-loader.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: lazyFn($$splitLoaderImporter, 'loader') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-default-component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-default-component.tsx index 9b38429966..27aa2140f6 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-default-component.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-default-component.tsx @@ -4,6 +4,10 @@ import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-errorComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-errorComponent.tsx index 108ad65fde..7111e86e76 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-errorComponent.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-errorComponent.tsx @@ -6,6 +6,17 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), errorComponent: lazyRouteComponent($$splitErrorComponentImporter, 'errorComponent') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); +} +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-notFoundComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-notFoundComponent.tsx index 4df3a0edc2..5622edf3e8 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-notFoundComponent.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-notFoundComponent.tsx @@ -6,6 +6,17 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), notFoundComponent: lazyRouteComponent($$splitNotFoundComponentImporter, 'notFoundComponent') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); +} +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-pendingComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-pendingComponent.tsx index 8a12860d09..b01e0aec42 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-pendingComponent.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported-pendingComponent.tsx @@ -6,6 +6,17 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), pendingComponent: lazyRouteComponent($$splitPendingComponentImporter, 'pendingComponent') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); +} +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported.tsx index b8c6e8c0ff..f2947f2004 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/imported.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: lazyFn($$splitLoaderImporter, 'loader') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/inline.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/inline.tsx index a179d36c0b..12626addb0 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/inline.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/inline.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/')({ }); Route.addChildren([]); export const test = 'test'; -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/random-number.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/random-number.tsx index 92f502edde..bb9a25ce5b 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/random-number.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/random-number.tsx @@ -26,6 +26,10 @@ export const Route = createFileRoute('/')({ loader: lazyFn($$splitLoaderImporter, 'loader'), component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/react-memo-component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/react-memo-component.tsx index bf8ae8af25..f99d37f872 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/react-memo-component.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/react-memo-component.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: lazyFn($$splitLoaderImporter, 'loader') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/react-memo-imported-component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/react-memo-imported-component.tsx index 5987f84c0a..6f5453d797 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/react-memo-imported-component.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/react-memo-imported-component.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: lazyFn($$splitLoaderImporter, 'loader') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/retain-exports-loader.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/retain-exports-loader.tsx index c8da9752f0..9f37f2c2ba 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/retain-exports-loader.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/retain-exports-loader.tsx @@ -14,6 +14,10 @@ export const Route = createFileRoute('/_layout')({ export const SIDEBAR_WIDTH = '150px'; export const SIDEBAR_MINI_WIDTH = '80px'; const ASIDE_WIDTH = '250px'; -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/useStateDestructure.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/useStateDestructure.tsx index 6cfb35e525..103067c81a 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/useStateDestructure.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/useStateDestructure.tsx @@ -116,9 +116,9 @@ export default function VersionIndex() {

Full-document SSR, Streaming, Server Functions, bundling and more, - powered by TanStack Router, Vinxi,{' '} - Nitro and Vite. Ready to deploy to - your favorite hosting provider. + powered by TanStack Router, Nitro{' '} + and Vite. Ready to deploy to your favorite hosting + provider.

diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/using.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/using.tsx new file mode 100644 index 0000000000..c58f0f663b --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/using.tsx @@ -0,0 +1,5 @@ +const $$splitLoaderImporter = () => import('using.tsx?tsr-split=loader'); +import { lazyFn } from '@tanstack/react-router'; +export const Route = createFileRoute({ + loader: lazyFn($$splitLoaderImporter, 'loader') +}); \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/using@component---errorComponent---notFoundComponent---pendingComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/using@component---errorComponent---notFoundComponent---pendingComponent.tsx new file mode 100644 index 0000000000..ac756d42a8 --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/using@component---errorComponent---notFoundComponent---pendingComponent.tsx @@ -0,0 +1 @@ +import { Route } from "using.tsx"; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/using@loader.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/using@loader.tsx new file mode 100644 index 0000000000..ae4bc0c74c --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/development/using@loader.tsx @@ -0,0 +1,18 @@ +const DummyPostResource = (postId: string) => ({ + postData: { + id: postId, + title: 'dummy', + body: 'dummy' + }, + [Symbol.dispose]: () => console.log('disposing!') +}); +import { Route } from "using.tsx"; +const SplitLoader = ({ + params: { + postId + } +}) => { + using dummyPost = DummyPostResource(postId); + return dummyPost.postData; +}; +export { SplitLoader as loader }; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/production/useStateDestructure.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/production/useStateDestructure.tsx index 6cfb35e525..103067c81a 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/production/useStateDestructure.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/production/useStateDestructure.tsx @@ -116,9 +116,9 @@ export default function VersionIndex() {

Full-document SSR, Streaming, Server Functions, bundling and more, - powered by TanStack Router, Vinxi,{' '} - Nitro and Vite. Ready to deploy to - your favorite hosting provider. + powered by TanStack Router, Nitro{' '} + and Vite. Ready to deploy to your favorite hosting + provider.

diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/production/using.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/production/using.tsx new file mode 100644 index 0000000000..c58f0f663b --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/production/using.tsx @@ -0,0 +1,5 @@ +const $$splitLoaderImporter = () => import('using.tsx?tsr-split=loader'); +import { lazyFn } from '@tanstack/react-router'; +export const Route = createFileRoute({ + loader: lazyFn($$splitLoaderImporter, 'loader') +}); \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/production/using@component---errorComponent---notFoundComponent---pendingComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/production/using@component---errorComponent---notFoundComponent---pendingComponent.tsx new file mode 100644 index 0000000000..ac756d42a8 --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/production/using@component---errorComponent---notFoundComponent---pendingComponent.tsx @@ -0,0 +1 @@ +import { Route } from "using.tsx"; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/production/using@loader.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/production/using@loader.tsx new file mode 100644 index 0000000000..ae4bc0c74c --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/2-components-combined-loader-separate/production/using@loader.tsx @@ -0,0 +1,18 @@ +const DummyPostResource = (postId: string) => ({ + postData: { + id: postId, + title: 'dummy', + body: 'dummy' + }, + [Symbol.dispose]: () => console.log('disposing!') +}); +import { Route } from "using.tsx"; +const SplitLoader = ({ + params: { + postId + } +}) => { + using dummyPost = DummyPostResource(postId); + return dummyPost.postData; +}; +export { SplitLoader as loader }; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/arrow-function.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/arrow-function.tsx index 25bae96925..26e6cb91cf 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/arrow-function.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/arrow-function.tsx @@ -8,6 +8,10 @@ export const Route = createFileRoute('/posts')({ loader: lazyFn($$splitLoaderImporter, 'loader'), component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/chinese.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/chinese.tsx index 9abb4a9d61..c26129ff26 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/chinese.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/chinese.tsx @@ -8,6 +8,10 @@ export const Route = createFileRoute('/')({ interface DemoProps { title: string; } -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/conditional-properties.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/conditional-properties.tsx index 279773de15..6f59f24540 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/conditional-properties.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/conditional-properties.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/posts')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: lazyFn($$splitLoaderImporter, 'loader') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/destructured-react-memo-imported-component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/destructured-react-memo-imported-component.tsx index 0fe0b8418d..b0e77520d1 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/destructured-react-memo-imported-component.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/destructured-react-memo-imported-component.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: lazyFn($$splitLoaderImporter, 'loader') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/export-default-component-and-normal-notFound.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/export-default-component-and-normal-notFound.tsx index 77e009583c..027607711c 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/export-default-component-and-normal-notFound.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/export-default-component-and-normal-notFound.tsx @@ -12,6 +12,10 @@ export default function Home() {

{one}

; } -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/function-declaration.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/function-declaration.tsx index 01360ef869..41dd964317 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/function-declaration.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/function-declaration.tsx @@ -8,6 +8,10 @@ export const Route = createFileRoute('/posts')({ loader: lazyFn($$splitLoaderImporter, 'loader'), component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/importAttribute.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/importAttribute.tsx index d8355986bf..a79f652e83 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/importAttribute.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/importAttribute.tsx @@ -4,6 +4,10 @@ import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-default-component-destructured-loader.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-default-component-destructured-loader.tsx index 4e0beddab5..abfa009cb3 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-default-component-destructured-loader.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-default-component-destructured-loader.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: lazyFn($$splitLoaderImporter, 'loader') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-default-component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-default-component.tsx index b749bed2ea..d7af841661 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-default-component.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-default-component.tsx @@ -4,6 +4,10 @@ import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-errorComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-errorComponent.tsx index 26951c2d0a..3fd46aa9ae 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-errorComponent.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-errorComponent.tsx @@ -6,6 +6,17 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), errorComponent: lazyRouteComponent($$splitErrorComponentImporter, 'errorComponent') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); +} +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-notFoundComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-notFoundComponent.tsx index 54565ca6f1..9bfc309859 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-notFoundComponent.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-notFoundComponent.tsx @@ -6,6 +6,17 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), notFoundComponent: lazyRouteComponent($$splitNotFoundComponentImporter, 'notFoundComponent') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); +} +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-pendingComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-pendingComponent.tsx index 02997dc053..de977998cf 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-pendingComponent.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported-pendingComponent.tsx @@ -6,6 +6,17 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), pendingComponent: lazyRouteComponent($$splitPendingComponentImporter, 'pendingComponent') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); +} +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported.tsx index c397f9dccc..a6c20d87ad 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/imported.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: lazyFn($$splitLoaderImporter, 'loader') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/inline.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/inline.tsx index ff044594ad..b452135b17 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/inline.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/inline.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/')({ }); Route.addChildren([]); export const test = 'test'; -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/random-number.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/random-number.tsx index 05f26ecf0d..769c2b9f63 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/random-number.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/random-number.tsx @@ -26,6 +26,10 @@ export const Route = createFileRoute('/')({ loader: lazyFn($$splitLoaderImporter, 'loader'), component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/react-memo-component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/react-memo-component.tsx index 66da0c232a..37d9d53304 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/react-memo-component.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/react-memo-component.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: lazyFn($$splitLoaderImporter, 'loader') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/react-memo-imported-component.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/react-memo-imported-component.tsx index 8db833f30c..a5c16d16d3 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/react-memo-imported-component.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/react-memo-imported-component.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/')({ component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr), loader: lazyFn($$splitLoaderImporter, 'loader') }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/retain-exports-loader.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/retain-exports-loader.tsx index eb4fd485bb..fec84f0be8 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/retain-exports-loader.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/retain-exports-loader.tsx @@ -14,6 +14,10 @@ export const Route = createFileRoute('/_layout')({ export const SIDEBAR_WIDTH = '150px'; export const SIDEBAR_MINI_WIDTH = '80px'; const ASIDE_WIDTH = '250px'; -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/useStateDestructure.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/useStateDestructure.tsx index 6cfb35e525..103067c81a 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/useStateDestructure.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/useStateDestructure.tsx @@ -116,9 +116,9 @@ export default function VersionIndex() {

Full-document SSR, Streaming, Server Functions, bundling and more, - powered by TanStack Router, Vinxi,{' '} - Nitro and Vite. Ready to deploy to - your favorite hosting provider. + powered by TanStack Router, Nitro{' '} + and Vite. Ready to deploy to your favorite hosting + provider.

diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/using.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/using.tsx new file mode 100644 index 0000000000..140f394f60 --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/using.tsx @@ -0,0 +1,5 @@ +const $$splitLoaderImporter = () => import('using.tsx?tsr-split=component---loader---notFoundComponent---pendingComponent'); +import { lazyFn } from '@tanstack/react-router'; +export const Route = createFileRoute({ + loader: lazyFn($$splitLoaderImporter, 'loader') +}); \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/using@component---loader---notFoundComponent---pendingComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/using@component---loader---notFoundComponent---pendingComponent.tsx new file mode 100644 index 0000000000..ae4bc0c74c --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/using@component---loader---notFoundComponent---pendingComponent.tsx @@ -0,0 +1,18 @@ +const DummyPostResource = (postId: string) => ({ + postData: { + id: postId, + title: 'dummy', + body: 'dummy' + }, + [Symbol.dispose]: () => console.log('disposing!') +}); +import { Route } from "using.tsx"; +const SplitLoader = ({ + params: { + postId + } +}) => { + using dummyPost = DummyPostResource(postId); + return dummyPost.postData; +}; +export { SplitLoader as loader }; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/using@errorComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/using@errorComponent.tsx new file mode 100644 index 0000000000..ac756d42a8 --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/development/using@errorComponent.tsx @@ -0,0 +1 @@ +import { Route } from "using.tsx"; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/production/useStateDestructure.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/production/useStateDestructure.tsx index 6cfb35e525..103067c81a 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/production/useStateDestructure.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/production/useStateDestructure.tsx @@ -116,9 +116,9 @@ export default function VersionIndex() {

Full-document SSR, Streaming, Server Functions, bundling and more, - powered by TanStack Router, Vinxi,{' '} - Nitro and Vite. Ready to deploy to - your favorite hosting provider. + powered by TanStack Router, Nitro{' '} + and Vite. Ready to deploy to your favorite hosting + provider.

diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/production/using.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/production/using.tsx new file mode 100644 index 0000000000..140f394f60 --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/production/using.tsx @@ -0,0 +1,5 @@ +const $$splitLoaderImporter = () => import('using.tsx?tsr-split=component---loader---notFoundComponent---pendingComponent'); +import { lazyFn } from '@tanstack/react-router'; +export const Route = createFileRoute({ + loader: lazyFn($$splitLoaderImporter, 'loader') +}); \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/production/using@component---loader---notFoundComponent---pendingComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/production/using@component---loader---notFoundComponent---pendingComponent.tsx new file mode 100644 index 0000000000..ae4bc0c74c --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/production/using@component---loader---notFoundComponent---pendingComponent.tsx @@ -0,0 +1,18 @@ +const DummyPostResource = (postId: string) => ({ + postData: { + id: postId, + title: 'dummy', + body: 'dummy' + }, + [Symbol.dispose]: () => console.log('disposing!') +}); +import { Route } from "using.tsx"; +const SplitLoader = ({ + params: { + postId + } +}) => { + using dummyPost = DummyPostResource(postId); + return dummyPost.postData; +}; +export { SplitLoader as loader }; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/production/using@errorComponent.tsx b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/production/using@errorComponent.tsx new file mode 100644 index 0000000000..ac756d42a8 --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/snapshots/react/3-all-combined-errorComponent-separate/production/using@errorComponent.tsx @@ -0,0 +1 @@ +import { Route } from "using.tsx"; \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/solid/1-default/development/arrow-function.tsx b/packages/router-plugin/tests/code-splitter/snapshots/solid/1-default/development/arrow-function.tsx index f62b65b5eb..e2375ceb8b 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/solid/1-default/development/arrow-function.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/solid/1-default/development/arrow-function.tsx @@ -6,6 +6,10 @@ export const Route = createFileRoute('/posts')({ loader: fetchPosts, component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/solid/2-components-combined-loader-separate/development/arrow-function.tsx b/packages/router-plugin/tests/code-splitter/snapshots/solid/2-components-combined-loader-separate/development/arrow-function.tsx index 5f36162818..b0356f3d87 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/solid/2-components-combined-loader-separate/development/arrow-function.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/solid/2-components-combined-loader-separate/development/arrow-function.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/posts')({ loader: lazyFn($$splitLoaderImporter, 'loader'), component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/snapshots/solid/3-all-combined-errorComponent-separate/development/arrow-function.tsx b/packages/router-plugin/tests/code-splitter/snapshots/solid/3-all-combined-errorComponent-separate/development/arrow-function.tsx index 56e28dce37..8efe2d0465 100644 --- a/packages/router-plugin/tests/code-splitter/snapshots/solid/3-all-combined-errorComponent-separate/development/arrow-function.tsx +++ b/packages/router-plugin/tests/code-splitter/snapshots/solid/3-all-combined-errorComponent-separate/development/arrow-function.tsx @@ -7,6 +7,10 @@ export const Route = createFileRoute('/posts')({ loader: lazyFn($$splitLoaderImporter, 'loader'), component: lazyRouteComponent($$splitComponentImporter, 'component', () => Route.ssr) }); -export function TSRDummyComponent() { - return null; +if (import.meta.hot) { + import.meta.hot.accept(newModule => { + if (newModule.Route && typeof newModule.Route.clone === 'function') { + newModule.Route.clone(Route); + } + }); } \ No newline at end of file diff --git a/packages/router-plugin/tests/code-splitter/test-files/react/useStateDestructure.tsx b/packages/router-plugin/tests/code-splitter/test-files/react/useStateDestructure.tsx index 6a1a086eaf..8f79e69bf0 100644 --- a/packages/router-plugin/tests/code-splitter/test-files/react/useStateDestructure.tsx +++ b/packages/router-plugin/tests/code-splitter/test-files/react/useStateDestructure.tsx @@ -159,9 +159,9 @@ export default function VersionIndex() { lg:text-xl lg:max-w-[600px]" > Full-document SSR, Streaming, Server Functions, bundling and more, - powered by TanStack Router, Vinxi,{' '} - Nitro and Vite. Ready to deploy to - your favorite hosting provider. + powered by TanStack Router, Nitro{' '} + and Vite. Ready to deploy to your favorite hosting + provider.

diff --git a/packages/router-plugin/tests/code-splitter/test-files/react/using.tsx b/packages/router-plugin/tests/code-splitter/test-files/react/using.tsx new file mode 100644 index 0000000000..e9b7173804 --- /dev/null +++ b/packages/router-plugin/tests/code-splitter/test-files/react/using.tsx @@ -0,0 +1,10 @@ +const DummyPostResource = (postId: string) => ({ + postData: { id: postId, title: 'dummy', body: 'dummy' }, + [Symbol.dispose]: () => console.log('disposing!'), +}) +export const Route = createFileRoute({ + loader: ({ params: { postId } }) => { + using dummyPost = DummyPostResource(postId) + return dummyPost.postData + }, +}) diff --git a/packages/router-plugin/tests/detect-route-codesplit-groupings.test.ts b/packages/router-plugin/tests/detect-route-codesplit-groupings.test.ts index 49b6b40c0a..899ace556b 100644 --- a/packages/router-plugin/tests/detect-route-codesplit-groupings.test.ts +++ b/packages/router-plugin/tests/detect-route-codesplit-groupings.test.ts @@ -76,8 +76,7 @@ describe('detectCodeSplitGroupingsFromRoute - success', () => { ({ code, expectedGrouping, expectedRouteId }) => { const result = detectCodeSplitGroupingsFromRoute({ code: code, - filename: 'test.ts', - root: '/src', + sourceFilename: 'test.ts', }) expect(result.groupings).toEqual(expectedGrouping) @@ -121,8 +120,7 @@ describe('detectCodeSplitGroupingsFromRoute - fail', () => { expect(() => detectCodeSplitGroupingsFromRoute({ code: code, - filename: 'test.ts', - root: '/src', + sourceFilename: 'test.ts', }), ).toThrowError() }) diff --git a/packages/router-utils/package.json b/packages/router-utils/package.json index 85f49510cf..7091b1126f 100644 --- a/packages/router-utils/package.json +++ b/packages/router-utils/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/router-utils", - "version": "1.115.0", + "version": "1.121.0-alpha.2", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/router-utils/src/ast.ts b/packages/router-utils/src/ast.ts index fbf6d970d5..829471ad97 100644 --- a/packages/router-utils/src/ast.ts +++ b/packages/router-utils/src/ast.ts @@ -1,27 +1,21 @@ import { parse } from '@babel/parser' import _generate from '@babel/generator' import type { GeneratorOptions, GeneratorResult } from '@babel/generator' -import type { ParseResult } from '@babel/parser' +import type { ParseResult, ParserOptions } from '@babel/parser' import type * as _babel_types from '@babel/types' -export type ParseAstOptions = { +export type ParseAstOptions = ParserOptions & { code: string - filename: string - root: string - env?: 'server' | 'client' | 'ssr' } -export function parseAst( - opts: ParseAstOptions, -): ParseResult<_babel_types.File> { - return parse(opts.code, { - plugins: ['jsx', 'typescript'], +export function parseAst({ + code, + ...opts +}: ParseAstOptions): ParseResult<_babel_types.File> { + return parse(code, { + plugins: ['jsx', 'typescript', 'explicitResourceManagement'], sourceType: 'module', - ...{ - root: opts.root, - filename: opts.filename, - env: opts.env, - }, + ...opts, }) } diff --git a/packages/router-vite-plugin/package.json b/packages/router-vite-plugin/package.json index d3768c86fd..a488997804 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.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/server-functions-plugin/README.md b/packages/server-functions-plugin/README.md index 9eda7c0fc3..6c0c32bdcc 100644 --- a/packages/server-functions-plugin/README.md +++ b/packages/server-functions-plugin/README.md @@ -8,9 +8,9 @@ Create a new instance of the plugin with the following options: ```ts const TanStackServerFnsPlugin = createTanStackServerFnPlugin({ - // This is the ID that will be available to look up and import - // our server function manifest and resolve its module - manifestVirtualImportId: 'tsr:server-fn-manifest', + // This is the ID (virtual module) that will be made available to look up + // and import our server function manifest and resolve its modules. + manifestVirtualImportId: 'tanstack:server-fn-manifest', client: { getRuntimeCode: () => `import { createClientRpc } from '@tanstack/react-start/client-runtime'`, @@ -44,7 +44,7 @@ Each runtime replacement should be implemented by your framework. Generally, on ```ts function createClientRpc(functionId: string) { - const url = `${process.env.YOUR_SERVER_BASE}/_server-fn/${functionId}` + const url = `${process.env.YOUR_SERVER_BASE}/_serverFn/${functionId}` const fn = async (...args: any[]) => { const res = await fetch(url, { @@ -71,7 +71,7 @@ function createClientRpc(functionId: string) { In your server handler, you can import the manifest and use it to look up and dynamically import the server function you want to call. ```ts -import serverFnManifest from 'tsr:server-fn-manifest' +import serverFnManifest from 'tanstack:server-fn-manifest' export const handler = async (req: Request) => { const functionId = req.url.split('/').pop() @@ -86,5 +86,5 @@ export const handler = async (req: Request) => { const args = await req.json() return await fnModule(...args) - +} ``` diff --git a/packages/server-functions-plugin/package.json b/packages/server-functions-plugin/package.json index 289b909ea6..f8d97dccd9 100644 --- a/packages/server-functions-plugin/package.json +++ b/packages/server-functions-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/server-functions-plugin", - "version": "1.119.2", + "version": "1.121.0-alpha.8", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -74,7 +74,6 @@ "@babel/traverse": "^7.26.8", "@babel/types": "^7.26.8", "babel-dead-code-elimination": "^1.0.9", - "dedent": "^1.5.3", "tiny-invariant": "^1.3.3" }, "devDependencies": { diff --git a/packages/server-functions-plugin/src/index.ts b/packages/server-functions-plugin/src/index.ts index dfa8993b45..2221ccf40c 100644 --- a/packages/server-functions-plugin/src/index.ts +++ b/packages/server-functions-plugin/src/index.ts @@ -1,6 +1,9 @@ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs' import path from 'node:path' -import { TanStackDirectiveFunctionsPlugin } from '@tanstack/directive-functions-plugin' +import { + TanStackDirectiveFunctionsPlugin, + TanStackDirectiveFunctionsPluginEnv, +} from '@tanstack/directive-functions-plugin' import type { Plugin } from 'vite' import type { DirectiveFn, @@ -19,12 +22,29 @@ declare global { } export type ServerFnPluginOpts = { + /** + * The virtual import ID that will be used to import the server function manifest. + * This virtual import ID will be used in the server build to import the manifest + * and its modules. + */ manifestVirtualImportId: string + /** + * The path to the manifest file that will be created during the build process. + * This file will be used to import the modules for the server functions in your + * server handler. + * + * @default 'node_modules/.tanstack-start/server-functions-manifest.json' + */ + manifestOutputFilename?: string client: ServerFnPluginEnvOpts ssr: ServerFnPluginEnvOpts server: ServerFnPluginEnvOpts + importer?: (fn: DirectiveFn) => Promise } +const defaultManifestFilename = + 'node_modules/.tanstack-start/server-functions-manifest.json' + export type ServerFnPluginEnvOpts = { getRuntimeCode: () => string replacer: ReplacerFn @@ -36,8 +56,6 @@ export function createTanStackServerFnPlugin(opts: ServerFnPluginOpts): { server: Array } { const ROOT = process.cwd() - const manifestFilename = - 'node_modules/.tanstack-start/server-functions-manifest.json' globalThis.TSR_directiveFnsById = {} @@ -58,13 +76,17 @@ export function createTanStackServerFnPlugin(opts: ServerFnPluginOpts): { // into the manifest because it's a dynamic import. Instead, as you'll // see below, we augment the manifest output with a code-generated importer // that looks exactly like this. - importer: () => import(fn.extractedFilename), + importer: () => + opts.importer ? opts.importer(fn) : import(fn.extractedFilename), }, ]), ), ) } + const manifestFilename = + opts.manifestOutputFilename || defaultManifestFilename + const directive = 'use server' const directiveLabel = 'Server Function' @@ -79,7 +101,6 @@ export function createTanStackServerFnPlugin(opts: ServerFnPluginOpts): { getRuntimeCode: opts.client.getRuntimeCode, replacer: opts.client.replacer, onDirectiveFnsById, - // devSplitImporter: `(globalThis.app.getRouter('server').internals.devServer.ssrLoadModule)`, }), { // Now that we have the directiveFnsById, we need to create a new @@ -93,7 +114,9 @@ export function createTanStackServerFnPlugin(opts: ServerFnPluginOpts): { // build. // Ensure the manifest directory exists - mkdirSync(path.dirname(manifestFilename), { recursive: true }) + mkdirSync(path.join(ROOT, path.dirname(manifestFilename)), { + recursive: true, + }) // Write the manifest to disk writeFileSync( @@ -124,7 +147,6 @@ export function createTanStackServerFnPlugin(opts: ServerFnPluginOpts): { getRuntimeCode: opts.ssr.getRuntimeCode, replacer: opts.ssr.replacer, onDirectiveFnsById, - // devSplitImporter: `(globalThis.app.getRouter('server').internals.devServer.ssrLoadModule)`, }), ], server: [ @@ -135,9 +157,17 @@ export function createTanStackServerFnPlugin(opts: ServerFnPluginOpts): { // so the manifest is like a serialized state from the client build to the server build name: 'tanstack-start-server-fn-vite-plugin-manifest-server', enforce: 'pre', - resolveId: (id) => (id === opts.manifestVirtualImportId ? id : null), + resolveId(id) { + if (id === opts.manifestVirtualImportId) { + return resolveViteId(id) + } + + return undefined + }, load(id) { - if (id !== opts.manifestVirtualImportId) return null + if (id !== resolveViteId(opts.manifestVirtualImportId)) { + return undefined + } // In development, we **can** use the in-memory manifest, and we should // since it will be incrementally updated as we use the app and dynamic @@ -185,3 +215,201 @@ export function createTanStackServerFnPlugin(opts: ServerFnPluginOpts): { ], } } + +export interface TanStackServerFnPluginEnvOpts { + /** + * The virtual import ID that will be used to import the server function manifest. + * This virtual import ID will be used in the server build to import the manifest + * and its modules. + */ + manifestVirtualImportId: string + /** + * The path to the manifest file that will be created during the build process. + * This file will be used to import the modules for the server functions in your + * server handler. + * + * @default 'node_modules/.tanstack-start/server-functions-manifest.json' + */ + manifestOutputFilename?: string + client: { + envName?: string + getRuntimeCode: () => string + replacer: ReplacerFn + } + server: { + envName?: string + getRuntimeCode: () => string + replacer: ReplacerFn + } + importer?: (fn: DirectiveFn) => Promise +} + +export function TanStackServerFnPluginEnv( + opts: TanStackServerFnPluginEnvOpts, +): Array { + opts = { + ...opts, + client: { + ...opts.client, + envName: opts.client.envName || 'client', + }, + server: { + ...opts.server, + envName: opts.server.envName || 'server', + }, + } + + const root = process.cwd() + + globalThis.TSR_directiveFnsById = {} + + const onDirectiveFnsById = (d: Record) => { + // When directives are compiled, save them to our global variable + // This variable will be used both during development to incrementally + // look up server functions and during build/production to produce a + // static manifest that can be read by the server build + Object.assign( + globalThis.TSR_directiveFnsById, + Object.fromEntries( + Object.entries(d).map(([id, fn]) => [ + id, + { + ...fn, + // This importer is required for the development server to + // work. It's also required in production, but cannot be serialized + // into the manifest because it's a dynamic import. Instead, as you'll + // see below, we augment the manifest output with a code-generated importer + // that looks exactly like this. + importer: () => + opts.importer ? opts.importer(fn) : import(fn.extractedFilename), + }, + ]), + ), + ) + } + + const manifestFilename = + opts.manifestOutputFilename || defaultManifestFilename + + const directive = 'use server' + const directiveLabel = 'Server Function' + + return [ + // The client plugin is used to compile the client directives + // and save them so we can create a manifest + TanStackDirectiveFunctionsPluginEnv({ + directive, + directiveLabel, + onDirectiveFnsById, + environments: { + client: { + envLabel: 'Client', + getRuntimeCode: opts.client.getRuntimeCode, + replacer: opts.client.replacer, + envName: opts.client.envName, + }, + server: { + envLabel: 'Server', + getRuntimeCode: opts.server.getRuntimeCode, + replacer: opts.server.replacer, + envName: opts.server.envName, + }, + }, + }), + { + // Now that we have the directiveFnsById, we need to create a new + // virtual module that can be used to import that manifest + name: 'tanstack-start-server-fn-vite-plugin-build-client', + applyToEnvironment(environment) { + return environment.name === opts.client.envName + }, + buildEnd() { + // In production, we create a manifest so we can + // access it later in the server build, which likely does not run in the + // same vite build environment. This is essentially a + // serialized state transfer from the client build to the server + // build. + + // Ensure the manifest directory exists + mkdirSync(path.join(root, path.dirname(manifestFilename)), { + recursive: true, + }) + + // Write the manifest to disk + writeFileSync( + path.join(root, manifestFilename), + JSON.stringify( + Object.fromEntries( + Object.entries(globalThis.TSR_directiveFnsById).map( + ([id, fn]) => [ + id, + { + functionName: fn.functionName, + extractedFilename: fn.extractedFilename, + }, + ], + ), + ), + ), + ) + }, + }, + { + // On the server, we need to be able to read the server-function manifest from the client build. + // This is likely used in the handler for server functions, so we can find the server function + // by its ID, import it, and call it. We can't do this in memory here because the builds happen in isolation, + // so the manifest is like a serialized state from the client build to the server build + name: 'tanstack-start-server-fn-vite-plugin-manifest-server', + enforce: 'pre', + // applyToEnvironment(environment) { + // return environment.name === opts.server.envName + // }, + resolveId(id) { + if (id === opts.manifestVirtualImportId) { + return resolveViteId(id) + } + + return undefined + }, + load(id) { + if (id !== resolveViteId(opts.manifestVirtualImportId)) { + return undefined + } + + // In development, we **can** use the in-memory manifest, and we should + // since it will be incrementally updated as we use the app and dynamic + // imports are triggered. + if (process.env.NODE_ENV === 'development') { + return `export default globalThis.TSR_directiveFnsById` + } + + // In production, we need to read the manifest from the client build. + // The manifest at that point should contain the full set of server functions + // that were found in the client build. + const manifest = JSON.parse( + readFileSync(path.join(root, manifestFilename), 'utf-8'), + ) + + // The manifest has a lot of information, but for now we only need to + // provide the function ID for lookup and the importer for loading + // This should keep the manifest small for now. + const manifestWithImports = ` + export default {${Object.entries(manifest) + .map( + ([id, fn]: any) => + `'${id}': { + functionName: '${fn.functionName}', + importer: () => import(${JSON.stringify(fn.extractedFilename)}) + }`, + ) + .join(',')}}` + + return manifestWithImports + }, + }, + ] +} + +function resolveViteId(id: string) { + return `\0${id}` +} diff --git a/packages/solid-router-devtools/package.json b/packages/solid-router-devtools/package.json index 2970a3554a..3bd71ac5e1 100644 --- a/packages/solid-router-devtools/package.json +++ b/packages/solid-router-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-router-devtools", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for Solid applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/solid-router/package.json b/packages/solid-router/package.json index 931c967fcc..029d21e039 100644 --- a/packages/solid-router/package.json +++ b/packages/solid-router/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-router", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for Solid applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/solid-router/src/HeadContent.tsx b/packages/solid-router/src/HeadContent.tsx index 512903273a..8caac5bf9f 100644 --- a/packages/solid-router/src/HeadContent.tsx +++ b/packages/solid-router/src/HeadContent.tsx @@ -59,8 +59,8 @@ export const useTags = () => { }) const links = useRouterState({ - select: (state) => - state.matches + select: (state) => { + const constructed = state.matches .map((match) => match.links!) .filter(Boolean) .flat(1) @@ -69,7 +69,27 @@ export const useTags = () => { attrs: { ...link, }, - })) as Array, + })) satisfies Array + + const manifest = router.ssr?.manifest + + // These are the assets extracted from the ViteManifest + // using the `startManifestPlugin` + const assets = state.matches + .map((match) => manifest?.routes[match.routeId]?.assets ?? []) + .filter(Boolean) + .flat(1) + .filter((asset) => asset.tag === 'link') + .map( + (asset) => + ({ + tag: 'link', + attrs: asset.attrs, + }) satisfies RouterManagedTag, + ) + + return [...constructed, ...assets] + }, }) const preloadMeta = useRouterState({ diff --git a/packages/solid-router/src/Match.tsx b/packages/solid-router/src/Match.tsx index e4d6dc91e3..b053540f08 100644 --- a/packages/solid-router/src/Match.tsx +++ b/packages/solid-router/src/Match.tsx @@ -329,6 +329,16 @@ export const Outlet = () => { return ( + + + } + > + + + + {renderRouteNotFound(router, route(), undefined)} diff --git a/packages/solid-router/src/Matches.tsx b/packages/solid-router/src/Matches.tsx index c269f74d68..7a0d32918d 100644 --- a/packages/solid-router/src/Matches.tsx +++ b/packages/solid-router/src/Matches.tsx @@ -10,6 +10,7 @@ import { SafeFragment } from './SafeFragment' import type { AnyRouter, DeepPartial, + Expand, MakeOptionalPathParams, MakeOptionalSearchParams, MakeRouteMatchUnion, @@ -117,7 +118,7 @@ export function useMatchRoute() { >( opts: UseMatchRouteOptions, ): Solid.Accessor< - false | ResolveRoute['types']['allParams'] + false | Expand['types']['allParams']> > => { const { pending, caseSensitive, fuzzy, includeSearch, ...rest } = opts diff --git a/packages/solid-router/src/ScrollRestoration.tsx b/packages/solid-router/src/ScrollRestoration.tsx index 063d93914f..71d472723d 100644 --- a/packages/solid-router/src/ScrollRestoration.tsx +++ b/packages/solid-router/src/ScrollRestoration.tsx @@ -64,6 +64,6 @@ export function useElementScrollRestoration( } const restoreKey = getKey(router.latestLocation) - const byKey = scrollRestorationCache.state[restoreKey] + const byKey = scrollRestorationCache?.state[restoreKey] return byKey?.[elementSelector] } diff --git a/packages/solid-router/src/fileRoute.ts b/packages/solid-router/src/fileRoute.ts index b20789e938..427416d193 100644 --- a/packages/solid-router/src/fileRoute.ts +++ b/packages/solid-router/src/fileRoute.ts @@ -28,6 +28,7 @@ import type { RouteIds, RouteLoaderFn, UpdatableRouteOptions, + UseNavigateResult, } from '@tanstack/router-core' import type { UseLoaderDepsRoute } from './useLoaderDeps' import type { UseLoaderDataRoute } from './useLoaderData' @@ -41,8 +42,13 @@ export function createFileRoute< TFullPath extends RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'], >( - path: TFilePath, + path?: TFilePath, ): FileRoute['createRoute'] { + if (typeof path === 'object') { + return new FileRoute(path, { + silent: true, + }).createRoute(path) as any + } return new FileRoute(path, { silent: true, }).createRoute @@ -63,7 +69,7 @@ export class FileRoute< silent?: boolean constructor( - public path: TFilePath, + public path?: TFilePath, _opts?: { silent: boolean }, ) { this.silent = _opts?.silent @@ -159,6 +165,18 @@ export function FileRouteLoader< return (loaderFn) => loaderFn as any } +declare module '@tanstack/router-core' { + export interface LazyRoute { + useMatch: UseMatchRoute + useRouteContext: UseRouteContextRoute + useSearch: UseSearchRoute + useParams: UseParamsRoute + useLoaderDeps: UseLoaderDepsRoute + useLoaderData: UseLoaderDataRoute + useNavigate: () => UseNavigateResult + } +} + export class LazyRoute { options: { id: string @@ -208,7 +226,7 @@ export class LazyRoute { return useLoaderData({ ...opts, from: this.options.id } as any) } - useNavigate = () => { + useNavigate = (): UseNavigateResult => { const router = useRouter() return useNavigate({ from: router.routesById[this.options.id].fullPath }) } @@ -229,6 +247,10 @@ export function createLazyRoute< export function createLazyFileRoute< TFilePath extends keyof FileRoutesByPath, TRoute extends FileRoutesByPath[TFilePath]['preLoaderRoute'], ->(id: TFilePath) { +>(id: TFilePath): (opts: LazyRouteOptions) => LazyRoute { + if (typeof id === 'object') { + return new LazyRoute(id) as any + } + return (opts: LazyRouteOptions) => new LazyRoute({ id, ...opts }) } diff --git a/packages/solid-router/src/index.tsx b/packages/solid-router/src/index.tsx index fc7c0bfd29..2d7204db62 100644 --- a/packages/solid-router/src/index.tsx +++ b/packages/solid-router/src/index.tsx @@ -47,7 +47,6 @@ export type { DeferredPromiseState, DeferredPromise, ParsedLocation, - ParsePathParams, RemoveTrailingSlashes, RemoveLeadingSlashes, ActiveOptions, @@ -56,6 +55,8 @@ export type { RootRouteId, AnyPathParams, ResolveParams, + ResolveOptionalParams, + ResolveRequiredParams, SearchSchemaInput, AnyContext, RouteContext, @@ -77,8 +78,6 @@ export type { TrimPath, TrimPathLeft, TrimPathRight, - ParseSplatParams, - SplatParams, StringifyParamsFn, ParamsOptions, InferAllParams, @@ -207,6 +206,8 @@ export type { InjectedHtmlEntry, RouterErrorSerializer, SerializerExtensions, + CreateFileRoute, + CreateLazyFileRoute, } from '@tanstack/router-core' export { diff --git a/packages/solid-router/src/router.ts b/packages/solid-router/src/router.ts index c2bbf24e7a..bc5af4f758 100644 --- a/packages/solid-router/src/router.ts +++ b/packages/solid-router/src/router.ts @@ -1,4 +1,5 @@ import { RouterCore } from '@tanstack/router-core' +import { createFileRoute, createLazyFileRoute } from './fileRoute' import type { RouterHistory } from '@tanstack/history' import type { AnyRoute, @@ -101,3 +102,11 @@ export class Router< super(options) } } + +if (typeof globalThis !== 'undefined') { + ;(globalThis as any).createFileRoute = createFileRoute + ;(globalThis as any).createLazyFileRoute = createLazyFileRoute +} else if (typeof window !== 'undefined') { + ;(window as any).createFileRoute = createFileRoute + ;(window as any).createFileRoute = createLazyFileRoute +} diff --git a/packages/solid-router/src/useBlocker.tsx b/packages/solid-router/src/useBlocker.tsx index 5568c120f2..a769899600 100644 --- a/packages/solid-router/src/useBlocker.tsx +++ b/packages/solid-router/src/useBlocker.tsx @@ -180,7 +180,10 @@ export function useBlocker( location: HistoryLocation, ): AnyShouldBlockFnLocation { const parsedLocation = router.parseLocation(undefined, location) - const matchedRoutes = router.getMatchedRoutes(parsedLocation) + const matchedRoutes = router.getMatchedRoutes( + parsedLocation.pathname, + undefined, + ) if (matchedRoutes.foundRoute === undefined) { throw new Error(`No route found for location ${location.href}`) } diff --git a/packages/solid-router/src/useNavigate.tsx b/packages/solid-router/src/useNavigate.tsx index d63e7b9bd2..9347b5c98c 100644 --- a/packages/solid-router/src/useNavigate.tsx +++ b/packages/solid-router/src/useNavigate.tsx @@ -17,7 +17,7 @@ export function useNavigate< const { navigate } = useRouter() return ((options: NavigateOptions) => { - return navigate({ from: _defaultOpts?.from, ...options }) + return navigate({ from: _defaultOpts?.from as any, ...options }) }) as UseNavigateResult } diff --git a/packages/solid-router/tests/link.test.tsx b/packages/solid-router/tests/link.test.tsx index d10af4ecf8..6385efc3bb 100644 --- a/packages/solid-router/tests/link.test.tsx +++ b/packages/solid-router/tests/link.test.tsx @@ -2551,11 +2551,6 @@ describe('Link', () => { expect(postsLink).toHaveAttribute('href', '/posts/id1/details') fireEvent.click(postsLink) - - const invoicesErrorText = await screen.findByText( - 'Invariant failed: Could not find match for from: /invoices', - ) - expect(invoicesErrorText).toBeInTheDocument() }) test('when navigating to /posts/$postId/info which is declaratively masked as /posts/$postId', async () => { diff --git a/packages/solid-router/tests/redirect.test.tsx b/packages/solid-router/tests/redirect.test.tsx index adb4b4c3c7..f774477094 100644 --- a/packages/solid-router/tests/redirect.test.tsx +++ b/packages/solid-router/tests/redirect.test.tsx @@ -1,21 +1,32 @@ import { cleanup, fireEvent, render, screen } from '@solidjs/testing-library' -import { afterEach, describe, expect, test, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { Link, RouterProvider, + createBrowserHistory, createMemoryHistory, createRootRoute, createRoute, createRouter, + invariant, redirect, useRouter, } from '../src' import { sleep } from './utils' +import type { RouterHistory } from '../src' + +let history: RouterHistory + +beforeEach(() => { + history = createBrowserHistory() + expect(window.location.pathname).toBe('/') +}) afterEach(() => { + history.destroy() vi.clearAllMocks() vi.resetAllMocks() window.history.replaceState(null, 'root', '/') @@ -228,7 +239,7 @@ describe('redirect', () => { indexRoute, finalRoute, ]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render(() => ) @@ -273,11 +284,18 @@ describe('redirect', () => { routeTree: rootRoute.addChildren([indexRoute, aboutRoute]), // Mock server mode isServer: true, + history: createMemoryHistory({ + initialEntries: ['/'], + }), }) await router.load() - expect(router.state.redirect).toEqual({ + expect(router.state.redirect).toBeDefined() + expect(router.state.redirect).toBeInstanceOf(Response) + invariant(router.state.redirect) + + expect(router.state.redirect.options).toEqual({ _fromLocation: expect.objectContaining({ hash: '', href: '/', @@ -286,65 +304,66 @@ describe('redirect', () => { searchStr: '', }), to: '/about', - headers: {}, - reloadDocument: false, href: '/about', - isRedirect: true, - routeId: '/', - routerCode: 'BEFORE_LOAD', statusCode: 307, }) }) + }) - test('when `redirect` is thrown in `loader`', async () => { - const rootRoute = createRootRoute() - - const indexRoute = createRoute({ - path: '/', - getParentRoute: () => rootRoute, - loader: () => { - throw redirect({ - to: '/about', - }) - }, - }) - - const aboutRoute = createRoute({ - path: '/about', - getParentRoute: () => rootRoute, - component: () => { - return 'About' - }, - }) + test('when `redirect` is thrown in `loader`', async () => { + const rootRoute = createRootRoute() + + const indexRoute = createRoute({ + path: '/', + getParentRoute: () => rootRoute, + loader: () => { + throw redirect({ + to: '/about', + }) + }, + }) - const router = createRouter({ - history: createMemoryHistory({ - initialEntries: ['/'], - }), - routeTree: rootRoute.addChildren([indexRoute, aboutRoute]), - }) + const aboutRoute = createRoute({ + path: '/about', + getParentRoute: () => rootRoute, + component: () => { + return 'About' + }, + }) + const router = createRouter({ + history: createMemoryHistory({ + initialEntries: ['/'], + }), + routeTree: rootRoute.addChildren([indexRoute, aboutRoute]), // Mock server mode - router.isServer = true - - await router.load() + isServer: true, + }) - expect(router.state.redirect).toEqual({ - _fromLocation: expect.objectContaining({ - hash: '', - href: '/', - pathname: '/', - search: {}, - searchStr: '', - }), - to: '/about', - headers: {}, - href: '/about', - isRedirect: true, - reloadDocument: false, - routeId: '/', - statusCode: 307, - }) + await router.load() + + const currentRedirect = router.state.redirect + + expect(currentRedirect).toBeDefined() + expect(currentRedirect).toBeInstanceOf(Response) + invariant(currentRedirect) + expect(currentRedirect.status).toEqual(307) + expect(currentRedirect.headers.get('Location')).toEqual('/about') + expect(currentRedirect.options).toEqual({ + _fromLocation: { + hash: '', + href: '/', + pathname: '/', + search: {}, + searchStr: '', + state: { + __TSR_index: 0, + key: currentRedirect.options._fromLocation!.state.key, + }, + }, + href: '/about', + to: '/about', + statusCode: 307, }) }) }) diff --git a/packages/solid-router/tests/route.test-d.tsx b/packages/solid-router/tests/route.test-d.tsx index fc58b779ab..3cdc65bb1d 100644 --- a/packages/solid-router/tests/route.test-d.tsx +++ b/packages/solid-router/tests/route.test-d.tsx @@ -1765,3 +1765,165 @@ test('when creating a child route with an explicit search input', () => { .parameter(0) .toEqualTypeOf<{ page: string }>() }) + +test('when creating a route with a prefix and suffix', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'prefix{$postId}suffix', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf< + Accessor<{ + postId: string + }> + >() +}) + +test('when creating a route with a optional prefix and suffix', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'prefix{-$postId}suffix', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf< + Accessor<{ + postId?: string + }> + >() +}) + +test('when creating a route with a splat prefix and suffix', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'prefix{$}suffix', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf< + Accessor<{ + _splat?: string + }> + >() +}) + +test('when creating a route with a splat, optional param and required param', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'docs/$docId/$/{-$detailId}/{$myFile}.pdf', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf< + Accessor<{ + docId: string + _splat?: string + myFile: string + detailId?: string + }> + >() +}) + +test('when creating a route with a boundary splat, optional param and required param', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'docs/$docId/before{$}after/detail{-$detailId}/file-{$myFile}.pdf', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf< + Accessor<{ + docId: string + _splat?: string + myFile: string + detailId?: string + }> + >() +}) + +test('when creating a route with a nested boundary splat, optional param and required param', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'docs/$docId/before{$}after/{-detail{$detailId}suffix}/file-{$myFile}.pdf', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf< + Accessor<{ + docId: string + _splat?: string + myFile: string + detailId?: string + }> + >() +}) + +test('when creating a route with a nested boundary splat, optional param, required param and escaping', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: 'docs/$docId/before{$}after/{-detail{$detailId}suffix}[.$test]/file-{$myFile}[.]pdf/escape-param[$postId]', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf< + Accessor<{ + docId: string + _splat?: string + myFile: string + detailId?: string + }> + >() +}) + +test('when creating a route with escaped path param', () => { + const rootRoute = createRootRoute() + + const prefixSuffixRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '[$postId]', + }) + + const routeTree = rootRoute.addChildren([prefixSuffixRoute]) + + const router = createRouter({ routeTree }) + + expectTypeOf(prefixSuffixRoute.useParams()).toEqualTypeOf< + Accessor<{}> + >() +}) diff --git a/packages/solid-router/tests/route.test.tsx b/packages/solid-router/tests/route.test.tsx index 7a8f776a61..f0a2a8e591 100644 --- a/packages/solid-router/tests/route.test.tsx +++ b/packages/solid-router/tests/route.test.tsx @@ -1,15 +1,26 @@ -import { afterEach, describe, expect, it, test, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, it, test, vi } from 'vitest' import { cleanup, render, screen } from '@solidjs/testing-library' import { RouterProvider, + createBrowserHistory, createRootRoute, createRoute, createRouter, getRouteApi, } from '../src' +import type { RouterHistory } from '../src' + +let history: RouterHistory + +beforeEach(() => { + history = createBrowserHistory() + expect(window.location.pathname).toBe('/') +}) + afterEach(() => { + history.destroy() vi.resetAllMocks() window.history.replaceState(null, 'root', '/') cleanup() @@ -161,7 +172,7 @@ describe('onEnter event', () => { }, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree, context: { foo: 'bar' } }) + const router = createRouter({ routeTree, history, context: { foo: 'bar' } }) await router.load() @@ -182,7 +193,7 @@ describe('onEnter event', () => { }, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree, context: { foo: 'bar' } }) + const router = createRouter({ routeTree, history, context: { foo: 'bar' } }) render(() => ) @@ -214,8 +225,9 @@ describe('route.head', () => { component: () =>
Index
, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render(() => ) + await router.load() const indexElem = await screen.findByText('Index') expect(indexElem).toBeInTheDocument() @@ -254,7 +266,7 @@ describe('route.head', () => { component: () =>
Index
, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render(() => ) const indexElem = await screen.findByText('Index') expect(indexElem).toBeInTheDocument() @@ -286,8 +298,9 @@ describe('route.head', () => { component: () =>
Index
, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render(() => ) + await router.load() const indexElem = await screen.findByText('Index') expect(indexElem).toBeInTheDocument() @@ -316,7 +329,7 @@ describe('route.head', () => { component: () =>
Index
, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render(() => ) const indexElem = await screen.findByText('Index') expect(indexElem).toBeInTheDocument() @@ -343,8 +356,9 @@ describe('route.head', () => { component: () =>
Index
, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render(() => ) + await router.load() const indexElem = await screen.findByText('Index') expect(indexElem).toBeInTheDocument() @@ -373,7 +387,7 @@ describe('route.head', () => { component: () =>
Index
, }) const routeTree = rootRoute.addChildren([indexRoute]) - const router = createRouter({ routeTree }) + const router = createRouter({ routeTree, history }) render(() => ) const indexElem = await screen.findByText('Index') expect(indexElem).toBeInTheDocument() diff --git a/packages/solid-start-client/README.md b/packages/solid-start-client/README.md index fd6e98ac6d..273667a4af 100644 --- a/packages/solid-start-client/README.md +++ b/packages/solid-start-client/README.md @@ -1,33 +1,9 @@ -> 🤫 we're cooking up something special! - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! +# TanStack Solid Start - Client - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - +This package is not meant to be used directly. It is a dependency of [`@tanstack/solid-start`](https://www.npmjs.com/package/@tanstack/solid-start). -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) +TanStack Solid Start is a fullstack-framework made for SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router). -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! +Head over to [tanstack.com/start](https://tanstack.com/start) for more information about getting started. diff --git a/packages/solid-start-client/package.json b/packages/solid-start-client/package.json index 63e7524577..56892f83ac 100644 --- a/packages/solid-start-client/package.json +++ b/packages/solid-start-client/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-start-client", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for Solid applications", "author": "Tanner Linsley", "license": "MIT", @@ -69,8 +69,7 @@ "cookie-es": "^1.2.2", "jsesc": "^3.1.0", "tiny-invariant": "^1.3.3", - "tiny-warning": "^1.0.3", - "vinxi": "^0.5.3" + "tiny-warning": "^1.0.3" }, "devDependencies": { "@solidjs/testing-library": "^0.8.10", diff --git a/packages/solid-start-client/src/index.tsx b/packages/solid-start-client/src/index.tsx index 6b9c30ee8f..3aebc26282 100644 --- a/packages/solid-start-client/src/index.tsx +++ b/packages/solid-start-client/src/index.tsx @@ -1,6 +1,15 @@ -/// -export { mergeHeaders } from '@tanstack/start-client-core' -export { startSerializer } from '@tanstack/start-client-core' +export { + mergeHeaders, + startSerializer, + createIsomorphicFn, + createServerFn, + createMiddleware, + registerGlobalMiddleware, + globalMiddleware, + serverOnly, + clientOnly, + json, +} from '@tanstack/start-client-core' export { type DehydratedRouter, type ClientExtractedBaseEntry, @@ -10,16 +19,10 @@ export { type ClientExtractedPromise, type ClientExtractedStream, type ResolvePromiseState, -} from '@tanstack/start-client-core' -export { - createIsomorphicFn, type IsomorphicFn, type ServerOnlyFn, type ClientOnlyFn, type IsomorphicFnBase, -} from '@tanstack/start-client-core' -export { createServerFn } from '@tanstack/start-client-core' -export { type ServerFn as FetchFn, type ServerFnCtx as FetchFnCtx, type CompiledFetcherFnOptions, @@ -31,43 +34,33 @@ export { type ServerFn, type ServerFnCtx, type ServerFnResponseType, -} from '@tanstack/start-client-core' -export { type JsonResponse } from '@tanstack/start-client-core' -export { - createMiddleware, + type JsonResponse, type IntersectAllValidatorInputs, type IntersectAllValidatorOutputs, - type MiddlewareServerFn, - type AnyMiddleware, - type MiddlewareOptions, - type MiddlewareWithTypes, - type MiddlewareValidator, - type MiddlewareServer, - type MiddlewareAfterClient, - type MiddlewareAfterMiddleware, - type MiddlewareAfterServer, - type Middleware, - type MiddlewareClientFnOptions, - type MiddlewareClientFnResult, - type MiddlewareClientNextFn, - type ClientResultWithContext, + type FunctionMiddlewareServerFn, + type AnyFunctionMiddleware, + type FunctionMiddlewareOptions, + type FunctionMiddlewareWithTypes, + type FunctionMiddlewareValidator, + type FunctionMiddlewareServer, + type FunctionMiddlewareAfterClient, + type FunctionMiddlewareAfterServer, + type FunctionMiddleware, + type FunctionMiddlewareClientFnOptions, + type FunctionMiddlewareClientFnResult, + type FunctionMiddlewareClientNextFn, + type FunctionClientResultWithContext, type AssignAllClientContextBeforeNext, type AssignAllMiddleware, type AssignAllServerContext, - type MiddlewareAfterValidator, - type MiddlewareClientFn, - type MiddlewareServerFnResult, - type MiddlewareClient, - type MiddlewareServerFnOptions, - type MiddlewareServerNextFn, - type ServerResultWithContext, -} from '@tanstack/start-client-core' -export { - registerGlobalMiddleware, - globalMiddleware, + type FunctionMiddlewareAfterValidator, + type FunctionMiddlewareClientFn, + type FunctionMiddlewareServerFnResult, + type FunctionMiddlewareClient, + type FunctionMiddlewareServerFnOptions, + type FunctionMiddlewareServerNextFn, + type FunctionServerResultWithContext, } from '@tanstack/start-client-core' -export { serverOnly, clientOnly } from '@tanstack/start-client-core' -export { json } from '@tanstack/start-client-core' export { Meta } from './Meta' export { Scripts } from './Scripts' export { StartClient } from './StartClient' diff --git a/packages/solid-start-client/src/renderRSC.tsx b/packages/solid-start-client/src/renderRSC.tsx index 7c534ebf3a..83735d882a 100644 --- a/packages/solid-start-client/src/renderRSC.tsx +++ b/packages/solid-start-client/src/renderRSC.tsx @@ -1,6 +1,6 @@ // TODO: RSCs // // @ts-expect-error -// import * as reactDom from '@vinxi/react-server-dom/client' +// import * as reactDom from 'react-server-dom/client' // import { isValidElement } from 'solid-js' import invariant from 'tiny-invariant' import type * as Solid from 'solid-js' diff --git a/packages/solid-start-client/src/routesManifest.ts b/packages/solid-start-client/src/routesManifest.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/solid-start-client/src/useServerFn.ts b/packages/solid-start-client/src/useServerFn.ts index c798c871c9..c10e73021a 100644 --- a/packages/solid-start-client/src/useServerFn.ts +++ b/packages/solid-start-client/src/useServerFn.ts @@ -17,12 +17,8 @@ export function useServerFn) => Promise>( return res } catch (err) { if (isRedirect(err)) { - const resolvedRedirect = router.resolveRedirect({ - ...err, - _fromLocation: router.state.location, - }) - - return router.navigate(resolvedRedirect) + err.options._fromLocation = router.state.location + return router.navigate(router.resolveRedirect(err).options) } throw err diff --git a/packages/solid-start-config/README.md b/packages/solid-start-config/README.md deleted file mode 100644 index bb009b0c87..0000000000 --- a/packages/solid-start-config/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/solid-start-config/eslint.config.js b/packages/solid-start-config/eslint.config.js deleted file mode 100644 index 931f0ec774..0000000000 --- a/packages/solid-start-config/eslint.config.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check - -import pluginReact from '@eslint-react/eslint-plugin' -import pluginReactHooks from 'eslint-plugin-react-hooks' -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - ...pluginReact.configs.recommended, - files: ['**/*.{ts,tsx}'], - }, - { - plugins: { - 'react-hooks': pluginReactHooks, - }, - rules: { - '@eslint-react/no-unstable-context-value': 'off', - '@eslint-react/no-unstable-default-props': 'off', - '@eslint-react/dom/no-missing-button-type': 'off', - 'react-hooks/exhaustive-deps': 'error', - 'react-hooks/rules-of-hooks': 'error', - }, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/solid-start-config/package.json b/packages/solid-start-config/package.json deleted file mode 100644 index 0e730177d0..0000000000 --- a/packages/solid-start-config/package.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "name": "@tanstack/solid-start-config", - "version": "1.120.3", - "description": "Modern and scalable routing for Solid applications", - "author": "Tanner Linsley", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/TanStack/router.git", - "directory": "packages/start" - }, - "homepage": "https://tanstack.com/start", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "keywords": [ - "solid", - "location", - "router", - "routing", - "async", - "async router", - "typescript" - ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "build": "tsc", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0;vitest", - "test:eslint": "eslint ./src", - "test:types": "exit 0; vitest" - }, - "type": "module", - "types": "dist/esm/index.d.ts", - "exports": { - ".": { - "import": { - "types": "./dist/esm/index.d.ts", - "default": "./dist/esm/index.js" - } - }, - "./package.json": "./package.json" - }, - "sideEffects": false, - "files": [ - "dist", - "src" - ], - "engines": { - "node": ">=12" - }, - "dependencies": { - "@tanstack/router-core": "workspace:^", - "@tanstack/router-generator": "workspace:^", - "@tanstack/router-plugin": "workspace:^", - "@tanstack/server-functions-plugin": "workspace:^", - "@tanstack/solid-start-plugin": "workspace:^", - "@tanstack/start-server-functions-handler": "workspace:^", - "vite-plugin-solid": "^2.11.2", - "import-meta-resolve": "^4.1.0", - "nitropack": "^2.10.4", - "ofetch": "^1.4.1", - "vite": "^6.1.0", - "vinxi": "0.5.3", - "zod": "^3.24.2" - }, - "peerDependencies": { - "solid-js": ">=1.0.0", - "vite": "^6.0.0" - } -} diff --git a/packages/solid-start-config/src/index.ts b/packages/solid-start-config/src/index.ts deleted file mode 100644 index 3a5c597f0d..0000000000 --- a/packages/solid-start-config/src/index.ts +++ /dev/null @@ -1,670 +0,0 @@ -import path from 'node:path' -import { existsSync, readFileSync } from 'node:fs' -import { readFile } from 'node:fs/promises' -import { fileURLToPath } from 'node:url' -import viteSolid from 'vite-plugin-solid' -import { resolve } from 'import-meta-resolve' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' -import { getConfig } from '@tanstack/router-generator' -import { createApp } from 'vinxi' -import { config } from 'vinxi/plugins/config' -// // @ts-expect-error -// import { serverComponents } from '@vinxi/server-components/plugin' -import { createTanStackServerFnPlugin } from '@tanstack/server-functions-plugin' -import { createTanStackStartPlugin } from '@tanstack/solid-start-plugin' -import { createFetch } from 'ofetch' -import { createNitro } from 'nitropack' -import { tanstackStartVinxiFileRouter } from './vinxi-file-router.js' -import { - checkDeploymentPresetInput, - getUserViteConfig, - inlineConfigSchema, - serverSchema, -} from './schema.js' -import type { configSchema } from '@tanstack/router-generator' -import type { z } from 'zod' -import type { - TanStackStartInputConfig, - TanStackStartOutputConfig, -} from './schema.js' -import type { App as VinxiApp } from 'vinxi' -import type { Manifest } from '@tanstack/router-core' -import type * as vite from 'vite' - -export type { - TanStackStartInputConfig, - TanStackStartOutputConfig, -} from './schema.js' - -function setTsrDefaults(config: TanStackStartOutputConfig['tsr']) { - // Normally these are `./src/___`, but we're using `./app/___` for Start stuff - const appDirectory = config?.appDirectory ?? './app' - return { - ...config, - appDirectory: config?.appDirectory ?? appDirectory, - routesDirectory: - config?.routesDirectory ?? path.join(appDirectory, 'routes'), - generatedRouteTree: - config?.generatedRouteTree ?? path.join(appDirectory, 'routeTree.gen.ts'), - } -} - -function mergeSsrOptions(options: Array) { - let ssrOptions: vite.SSROptions = {} - let noExternal: vite.SSROptions['noExternal'] = [] - for (const option of options) { - if (!option) { - continue - } - - if (option.noExternal) { - if (option.noExternal === true) { - noExternal = true - } else if (noExternal !== true) { - if (Array.isArray(option.noExternal)) { - noExternal.push(...option.noExternal) - } else { - noExternal.push(option.noExternal) - } - } - } - - ssrOptions = { - ...ssrOptions, - ...option, - noExternal, - } - } - - return ssrOptions -} - -export async function defineConfig( - inlineConfig: TanStackStartInputConfig = {}, -): Promise { - const opts = inlineConfigSchema.parse(inlineConfig) - - const { preset: configDeploymentPreset, ...serverOptions } = - serverSchema.parse(opts.server || {}) - - const deploymentPreset = checkDeploymentPresetInput(configDeploymentPreset) - const tsr = setTsrDefaults(opts.tsr) - const tsrConfig = getConfig(tsr) - - const appDirectory = tsr.appDirectory - const publicDir = opts.routers?.public?.dir || './public' - - const publicBase = opts.routers?.public?.base || '/' - const clientBase = opts.routers?.client?.base || '/_build' - const apiBase = opts.tsr?.apiBase || '/api' - const serverBase = opts.routers?.server?.base || '/_server' - - const apiMiddleware = opts.routers?.api?.middleware || undefined - const serverMiddleware = opts.routers?.server?.middleware || undefined - const ssrMiddleware = opts.routers?.ssr?.middleware || undefined - - const clientEntry = - opts.routers?.client?.entry || path.join(appDirectory, 'client.tsx') - const ssrEntry = - opts.routers?.ssr?.entry || path.join(appDirectory, 'ssr.tsx') - const apiEntry = opts.routers?.api?.entry || path.join(appDirectory, 'api.ts') - - const globalMiddlewareEntry = - opts.routers?.server?.globalMiddlewareEntry || - path.join(appDirectory, 'global-middleware.ts') - - const apiEntryExists = existsSync(apiEntry) - - const viteConfig = getUserViteConfig(opts.vite) - - const TanStackServerFnsPlugin = createTanStackServerFnPlugin({ - // This is the ID that will be available to look up and import - // our server function manifest and resolve its module - manifestVirtualImportId: 'tsr:server-fn-manifest', - client: { - getRuntimeCode: () => - `import { createClientRpc } from '@tanstack/solid-start/server-functions-client'`, - replacer: (opts) => - `createClientRpc('${opts.functionId}', '${serverBase}')`, - }, - ssr: { - getRuntimeCode: () => - `import { createSsrRpc } from '@tanstack/solid-start/server-functions-ssr'`, - replacer: (opts) => `createSsrRpc('${opts.functionId}', '${serverBase}')`, - }, - server: { - getRuntimeCode: () => - `import { createServerRpc } from '@tanstack/solid-start/server-functions-server'`, - replacer: (opts) => - `createServerRpc('${opts.functionId}', '${serverBase}', ${opts.fn})`, - }, - }) - - const TanStackStartPlugin = createTanStackStartPlugin({ - globalMiddlewareEntry, - }) - - // Create a dummy nitro app to get the resolved public output path - const dummyNitroApp = await createNitro({ - preset: deploymentPreset, - compatibilityDate: '2024-12-01', - }) - - const nitroOutputPublicDir = dummyNitroApp.options.output.publicDir - await dummyNitroApp.close() - - let vinxiApp = createApp({ - server: { - ...serverOptions, - preset: deploymentPreset, - experimental: { - ...serverOptions.experimental, - asyncContext: true, - }, - }, - routers: [ - { - name: 'public', - type: 'static', - dir: publicDir, - base: publicBase, - }, - { - name: 'client', - type: 'client', - target: 'browser', - handler: clientEntry, - base: clientBase, - // @ts-expect-error - build: { - sourcemap: true, - }, - plugins: () => { - const routerType = 'client' - const clientViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-client', { - ...viteConfig.userConfig, - ...clientViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(clientViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - clientViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(clientViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - target: 'solid', - enableRouteGeneration: true, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.client, - TanStackServerFnsPlugin.client, - ...(viteConfig.plugins || []), - ...(clientViteConfig.plugins || []), - viteSolid({ ...opts.solid, ssr: true }), - // TODO: RSCS - enable this - // serverComponents.client(), - ] - }, - }, - { - name: 'ssr', - type: 'http', - target: 'server', - handler: ssrEntry, - middleware: ssrMiddleware, - // @ts-expect-error - link: { - client: 'client', - }, - plugins: () => { - const routerType = 'ssr' - const ssrViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-ssr', { - ...viteConfig.userConfig, - ...ssrViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(ssrViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - ssrViteConfig.userConfig.ssr, - { - noExternal, - external: ['@vinxi/react-server-dom/client'], - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(ssrViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - target: 'solid', - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.ssr, - TanStackServerFnsPlugin.ssr, - tsrRoutesManifest({ - tsrConfig, - clientBase, - }), - ...(getUserViteConfig(opts.vite).plugins || []), - ...(getUserViteConfig(opts.routers?.ssr?.vite).plugins || []), - viteSolid({ ...opts.solid, ssr: true }), - ] - }, - }, - { - name: 'server', - type: 'http', - target: 'server', - base: serverBase, - middleware: serverMiddleware, - // TODO: RSCS - enable this - // worker: true, - handler: importToProjectRelative( - '@tanstack/start-server-functions-handler', - ), - plugins: () => { - const routerType = 'server' - const serverViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-server', { - ...viteConfig.userConfig, - ...serverViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(serverViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv('TSS_SERVER_FN_BASE', serverBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - serverViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(serverViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - target: 'solid', - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.server, - TanStackServerFnsPlugin.server, - // TODO: RSCS - remove this - // resolve: { - // conditions: [], - // }, - // TODO: RSCs - add this - // serverComponents.serverActions({ - // resolve: { - // conditions: [ - // 'react-server', - // // 'node', - // 'import', - // process.env.NODE_ENV, - // ], - // }, - // runtime: '@vinxi/react-server-dom/runtime', - // transpileDeps: ['react', 'react-dom', '@vinxi/react-server-dom'], - // }), - ...(viteConfig.plugins || []), - ...(serverViteConfig.plugins || []), - viteSolid({ ...opts.solid, ssr: true }), - ] - }, - }, - ], - }) - - const noExternal = [ - '@tanstack/solid-start', - '@tanstack/solid-start/server', - '@tanstack/solid-start-client', - '@tanstack/solid-start-server', - '@tanstack/start-server-functions-fetcher', - '@tanstack/start-server-functions-handler', - '@tanstack/start-server-functions-client', - '@tanstack/start-server-functions-ssr', - '@tanstack/start-server-functions-server', - '@tanstack/solid-start-router-manifest', - '@tanstack/solid-start-config', - '@tanstack/start-api-routes', - '@tanstack/server-functions-plugin', - 'tsr:routes-manifest', - 'tsr:server-fn-manifest', - ] - - // If API routes handler exists, add a router for it - if (apiEntryExists) { - vinxiApp = vinxiApp.addRouter({ - name: 'api', - type: 'http', - target: 'server', - base: apiBase, - handler: apiEntry, - middleware: apiMiddleware, - routes: tanstackStartVinxiFileRouter({ tsrConfig, apiBase }), - plugins: () => { - const viteConfig = getUserViteConfig(opts.vite) - const apiViteConfig = getUserViteConfig(opts.routers?.api?.vite) - - return [ - config('tsr-vite-config-api', { - ...viteConfig.userConfig, - ...apiViteConfig.userConfig, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - apiViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(apiViteConfig.userConfig.optimizeDeps || {}), - }, - define: { - ...(viteConfig.userConfig.define || {}), - ...(apiViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv('TSS_OUTPUT_PUBLIC_DIR', nitroOutputPublicDir), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - target: 'solid', - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - ...(viteConfig.plugins || []), - ...(apiViteConfig.plugins || []), - viteSolid({ ...opts.solid, ssr: true }), - ] - }, - }) - } - - // Because Vinxi doesn't use the normal nitro dev server, it doesn't - // supply $fetch during dev. We need to hook into the dev server creation, - // nab the proper utils from the custom nitro instance that is used - // during dev and supply the $fetch to app. - // Hopefully and likely, this will just get removed when we move to - // Nitro directly. - vinxiApp.hooks.hook('app:dev:nitro:config', (devServer) => { - vinxiApp.hooks.hook( - 'app:dev:server:created', - ({ devApp: { localFetch } }) => { - const $fetch = createFetch({ - fetch: localFetch, - defaults: { - baseURL: devServer.nitro.options.runtimeConfig.app.baseURL, - }, - }) - - // @ts-expect-error - globalThis.$fetch = $fetch - }, - ) - }) - - return vinxiApp -} - -function importToProjectRelative(p: string) { - const resolved = fileURLToPath(resolve(p, import.meta.url)) - - const relative = path.relative(process.cwd(), resolved) - - return relative -} - -function tsrRoutesManifest(opts: { - tsrConfig: z.infer - clientBase: string -}): vite.Plugin { - let config: vite.ResolvedConfig - - return { - name: 'tsr-routes-manifest', - configResolved(resolvedConfig) { - config = resolvedConfig - }, - resolveId(id) { - if (id === 'tsr:routes-manifest') { - return id - } - return - }, - async load(id) { - if (id === 'tsr:routes-manifest') { - // If we're in development, return a dummy manifest - - if (config.command === 'serve') { - return `export default () => ({ - routes: {} - })` - } - - const clientViteManifestPath = path.resolve( - config.build.outDir, - `../client/${opts.clientBase}/.vite/manifest.json`, - ) - - type ViteManifest = Record< - string, - { - file: string - isEntry: boolean - imports: Array - } - > - - let manifest: ViteManifest - try { - manifest = JSON.parse(await readFile(clientViteManifestPath, 'utf-8')) - } catch (err) { - console.error(err) - throw new Error( - `Could not find the production client vite manifest at '${clientViteManifestPath}'!`, - ) - } - - const routeTreePath = path.resolve(opts.tsrConfig.generatedRouteTree) - - let routeTreeContent: string - try { - routeTreeContent = readFileSync(routeTreePath, 'utf-8') - } catch (err) { - console.error(err) - throw new Error( - `Could not find the generated route tree at '${routeTreePath}'!`, - ) - } - - // Extract the routesManifest JSON from the route tree file. - // It's located between the /* ROUTE_MANIFEST_START and ROUTE_MANIFEST_END */ comment block. - - const routerManifest = JSON.parse( - routeTreeContent.match( - /\/\* ROUTE_MANIFEST_START([\s\S]*?)ROUTE_MANIFEST_END \*\//, - )?.[1] || '{ routes: {} }', - ) as Manifest - - const routes = routerManifest.routes - - let entryFile: - | { - file: string - imports: Array - } - | undefined - - const filesByRouteFilePath: ViteManifest = Object.fromEntries( - Object.entries(manifest).map(([k, v]) => { - if (v.isEntry) { - entryFile = v - } - - const rPath = k.split('?')[0] - - return [rPath, v] - }, {}), - ) - - // Add preloads to the routes from the vite manifest - Object.entries(routes).forEach(([k, v]) => { - const file = - filesByRouteFilePath[ - path.join(opts.tsrConfig.routesDirectory, v.filePath as string) - ] - - if (file) { - const preloads = file.imports.map((d) => - path.join(opts.clientBase, manifest[d]!.file), - ) - - preloads.unshift(path.join(opts.clientBase, file.file)) - - routes[k] = { - ...v, - preloads, - } - } - }) - - if (entryFile) { - routes.__root__!.preloads = [ - path.join(opts.clientBase, entryFile.file), - ...entryFile.imports.map((d) => - path.join(opts.clientBase, manifest[d]!.file), - ), - ] - } - - const recurseRoute = ( - route: { - preloads?: Array - children?: Array - }, - seenPreloads = {} as Record, - ) => { - route.preloads = route.preloads?.filter((preload) => { - if (seenPreloads[preload]) { - return false - } - seenPreloads[preload] = true - return true - }) - - if (route.children) { - route.children.forEach((child) => { - const childRoute = routes[child]! - recurseRoute(childRoute, { ...seenPreloads }) - }) - } - } - - // @ts-expect-error - recurseRoute(routes.__root__) - - const routesManifest = { - routes, - } - - if (process.env.TSR_VITE_DEBUG) { - console.info( - 'Routes Manifest: \n' + JSON.stringify(routesManifest, null, 2), - ) - } - - return `export default () => (${JSON.stringify(routesManifest)})` - } - return - }, - } -} - -function injectDefineEnv( - key: TKey, - value: TValue, -): { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } { - return { - [`process.env.${key}`]: JSON.stringify(value), - [`import.meta.env.${key}`]: JSON.stringify(value), - } as { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } -} diff --git a/packages/solid-start-config/src/schema.ts b/packages/solid-start-config/src/schema.ts deleted file mode 100644 index 9c8a6dc810..0000000000 --- a/packages/solid-start-config/src/schema.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { configSchema } from '@tanstack/router-generator' -import { z } from 'zod' -import type { PluginOption } from 'vite' -import type { AppOptions as VinxiAppOptions } from 'vinxi' -import type { NitroOptions } from 'nitropack' -import type { Options as ViteSolidOptions } from 'vite-plugin-solid' -import type { CustomizableConfig } from 'vinxi/dist/types/lib/vite-dev' - -type StartUserViteConfig = CustomizableConfig | (() => CustomizableConfig) - -export function getUserViteConfig(config?: StartUserViteConfig): { - plugins: Array | undefined - userConfig: CustomizableConfig -} { - const { plugins, ...userConfig } = - typeof config === 'function' ? config() : { ...config } - return { plugins, userConfig } -} - -/** - * Not all the deployment presets are fully functional or tested. - * @see https://github.com/TanStack/router/pull/2002 - */ -const vinxiDeploymentPresets = [ - 'alwaysdata', // untested - 'aws-amplify', // untested - 'aws-lambda', // untested - 'azure', // untested - 'azure-functions', // untested - 'base-worker', // untested - 'bun', // ✅ working - 'cleavr', // untested - 'cli', // untested - 'cloudflare', // untested - 'cloudflare-module', // untested - 'cloudflare-pages', // ✅ working - 'cloudflare-pages-static', // untested - 'deno', // untested - 'deno-deploy', // untested - 'deno-server', // untested - 'digital-ocean', // untested - 'edgio', // untested - 'firebase', // untested - 'flight-control', // untested - 'github-pages', // untested - 'heroku', // untested - 'iis', // untested - 'iis-handler', // untested - 'iis-node', // untested - 'koyeb', // untested - 'layer0', // untested - 'netlify', // ✅ working - 'netlify-builder', // untested - 'netlify-edge', // untested - 'netlify-static', // untested - 'nitro-dev', // untested - 'nitro-prerender', // untested - 'node', // partially working - 'node-cluster', // untested - 'node-server', // ✅ working - 'platform-sh', // untested - 'service-worker', // untested - 'static', // 🟧 partially working - 'stormkit', // untested - 'vercel', // ✅ working - 'vercel-edge', // untested - 'vercel-static', // untested - 'winterjs', // untested - 'zeabur', // untested - 'zeabur-static', // untested -] as const - -type DeploymentPreset = (typeof vinxiDeploymentPresets)[number] | (string & {}) - -const testedDeploymentPresets: Array = [ - 'bun', - 'netlify', - 'vercel', - 'cloudflare-pages', - 'node-server', -] - -export function checkDeploymentPresetInput( - preset?: string, -): DeploymentPreset | undefined { - if (preset) { - if (!vinxiDeploymentPresets.includes(preset as any)) { - console.warn( - `Invalid deployment preset "${preset}". Available presets are: ${vinxiDeploymentPresets - .map((p) => `"${p}"`) - .join(', ')}.`, - ) - } - - if (!testedDeploymentPresets.includes(preset as any)) { - console.warn( - `The deployment preset '${preset}' is not fully supported yet and may not work as expected.`, - ) - } - } - - return preset -} - -type HTTPSOptions = { - cert?: string - key?: string - pfx?: string - passphrase?: string - validityDays?: number - domains?: Array -} - -type ServerOptions_ = VinxiAppOptions['server'] & { - https?: boolean | HTTPSOptions -} - -type ServerOptions = { - [K in keyof ServerOptions_]: ServerOptions_[K] -} - -export const serverSchema = z - .object({ - routeRules: z.custom().optional(), - preset: z.custom().optional(), - static: z.boolean().optional(), - prerender: z - .object({ - routes: z.array(z.string()), - ignore: z - .array( - z.custom< - string | RegExp | ((path: string) => undefined | null | boolean) - >(), - ) - .optional(), - crawlLinks: z.boolean().optional(), - }) - .optional(), - }) - .and(z.custom()) - -const viteSchema = z.custom() - -const viteSolidSchema = z.custom() - -const routersSchema = z.object({ - ssr: z - .object({ - entry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - client: z - .object({ - entry: z.string().optional(), - base: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - server: z - .object({ - base: z.string().optional(), - globalMiddlewareEntry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - api: z - .object({ - entry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - public: z - .object({ - dir: z.string().optional(), - base: z.string().optional(), - }) - .optional(), -}) - -const tsrConfig = configSchema.partial().extend({ - appDirectory: z.string().optional(), -}) - -export const inlineConfigSchema = z.object({ - solid: viteSolidSchema.optional(), - vite: viteSchema.optional(), - tsr: tsrConfig.optional(), - routers: routersSchema.optional(), - server: serverSchema.optional(), -}) - -export type TanStackStartInputConfig = z.input -export type TanStackStartOutputConfig = z.infer diff --git a/packages/solid-start-config/src/vinxi-file-router.ts b/packages/solid-start-config/src/vinxi-file-router.ts deleted file mode 100644 index 9e6d829d1b..0000000000 --- a/packages/solid-start-config/src/vinxi-file-router.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { - BaseFileSystemRouter as VinxiBaseFileSystemRouter, - analyzeModule as vinxiFsRouterAnalyzeModule, - cleanPath as vinxiFsRouterCleanPath, -} from 'vinxi/fs-router' -import { - CONSTANTS as GENERATOR_CONSTANTS, - startAPIRouteSegmentsFromTSRFilePath, -} from '@tanstack/router-generator' -import type { configSchema } from '@tanstack/router-generator' -import type { - AppOptions as VinxiAppOptions, - RouterSchemaInput as VinxiRouterSchemaInput, -} from 'vinxi' -import type { z } from 'zod' - -export function tanstackStartVinxiFileRouter(opts: { - tsrConfig: z.infer - apiBase: string -}) { - const apiBaseSegment = opts.apiBase.split('/').filter(Boolean).join('/') - const isAPIPath = new RegExp(`/${apiBaseSegment}/`) - - return function (router: VinxiRouterSchemaInput, app: VinxiAppOptions) { - // Our own custom File Router that extends the VinxiBaseFileSystemRouter - // for splitting the API routes into its own "bundle" - // and adding the $APIRoute metadata to the route object - // This could be customized in future to support more complex splits - class TanStackStartFsRouter extends VinxiBaseFileSystemRouter { - toPath(src: string): string { - const inputPath = vinxiFsRouterCleanPath(src, this.config) - - const segments = startAPIRouteSegmentsFromTSRFilePath( - inputPath, - opts.tsrConfig, - ) - - const pathname = segments - .map((part) => { - if (part.type === 'splat') { - return `*splat` - } - - if (part.type === 'param') { - return `:${part.value}?` - } - - return part.value - }) - .join('/') - - return pathname.length > 0 ? `/${pathname}` : '/' - } - - toRoute(src: string) { - const webPath = this.toPath(src) - - const [_, exports] = vinxiFsRouterAnalyzeModule(src) - - const hasAPIRoute = exports.find( - (exp) => exp.n === GENERATOR_CONSTANTS.APIRouteExportVariable, - ) - - return { - path: webPath, - filePath: src, - $APIRoute: - isAPIPath.test(webPath) && hasAPIRoute - ? { - src, - pick: [GENERATOR_CONSTANTS.APIRouteExportVariable], - } - : undefined, - } - } - } - - return new TanStackStartFsRouter( - { - dir: opts.tsrConfig.routesDirectory, - extensions: ['js', 'jsx', 'ts', 'tsx'], - }, - router, - app, - ) - } -} diff --git a/packages/solid-start-config/tsconfig.json b/packages/solid-start-config/tsconfig.json deleted file mode 100644 index 940a9cce0a..0000000000 --- a/packages/solid-start-config/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": ["src/index.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist/esm", - "target": "esnext", - "noEmit": false - } -} diff --git a/packages/solid-start-plugin/README.md b/packages/solid-start-plugin/README.md index 798fa094a3..f1f10693be 100644 --- a/packages/solid-start-plugin/README.md +++ b/packages/solid-start-plugin/README.md @@ -1,5 +1,9 @@ -# TanStack Start Vite Plugin +# TanStack Solid Start - Plugin -See https://tanstack.com/router/latest/docs/framework/react/guide/file-based-routing +This package is not meant to be used directly. It is a dependency of [`@tanstack/solid-start`](https://www.npmjs.com/package/@tanstack/solid-start). + +TanStack Solid Start is a fullstack-framework made for SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router). + +Head over to [tanstack.com/start](https://tanstack.com/start) for more information about getting started. diff --git a/packages/solid-start-plugin/package.json b/packages/solid-start-plugin/package.json index 1fb0325218..e4852ca4c5 100644 --- a/packages/solid-start-plugin/package.json +++ b/packages/solid-start-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-start-plugin", - "version": "1.115.0", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for Solid applications", "author": "Tanner Linsley", "license": "MIT", @@ -27,7 +27,7 @@ "clean": "rimraf ./dist && rimraf ./coverage", "clean:snapshots": "rimraf **/*snapshot* --glob", "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "vitest", + "test:unit": "exit 0; vitest", "test:eslint": "eslint ./src", "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", @@ -65,22 +65,16 @@ "node": ">=12" }, "dependencies": { - "@babel/code-frame": "7.26.2", - "@babel/core": "^7.26.8", - "@babel/plugin-syntax-jsx": "^7.25.9", - "@babel/plugin-syntax-typescript": "^7.25.9", - "@babel/template": "^7.26.8", - "@babel/traverse": "^7.26.8", - "@babel/types": "^7.26.8", "@tanstack/router-utils": "workspace:^", - "babel-dead-code-elimination": "^1.0.9", - "tiny-invariant": "^1.3.3", - "vite": "6.1.4" + "@tanstack/start-plugin-core": "workspace:^", + "zod": "^3.24.2" }, "devDependencies": { - "@types/babel__code-frame": "^7.0.6", - "@types/babel__core": "^7.20.5", - "@types/babel__template": "^7.4.4", - "@types/babel__traverse": "^7.20.6" + "vite": "^6.0.0", + "vite-plugin-solid": "^2.11.6" + }, + "peerDependencies": { + "vite": ">=6.0.0", + "vite-plugin-solid": ">=2.11.6" } } diff --git a/packages/solid-start-plugin/src/compilers.ts b/packages/solid-start-plugin/src/compilers.ts deleted file mode 100644 index 0fd65af65c..0000000000 --- a/packages/solid-start-plugin/src/compilers.ts +++ /dev/null @@ -1,584 +0,0 @@ -import * as babel from '@babel/core' -import * as t from '@babel/types' -import { codeFrameColumns } from '@babel/code-frame' -import { - deadCodeElimination, - findReferencedIdentifiers, -} from 'babel-dead-code-elimination' -import { generateFromAst, parseAst } from '@tanstack/router-utils' -import type { GeneratorResult, ParseAstOptions } from '@tanstack/router-utils' - -// build these once and reuse them -const handleServerOnlyCallExpression = - buildEnvOnlyCallExpressionHandler('server') -const handleClientOnlyCallExpression = - buildEnvOnlyCallExpressionHandler('client') - -type CompileOptions = ParseAstOptions & { - env: 'server' | 'client' | 'ssr' - dce?: boolean -} - -type IdentifierConfig = { - name: string - type: 'ImportSpecifier' | 'ImportNamespaceSpecifier' - namespaceId: string - handleCallExpression: ( - path: babel.NodePath, - opts: CompileOptions, - ) => void - paths: Array -} - -export function compileStartOutput(opts: CompileOptions): GeneratorResult { - const ast = parseAst(opts) - - const doDce = opts.dce ?? true - // find referenced identifiers *before* we transform anything - const refIdents = doDce ? findReferencedIdentifiers(ast) : undefined - - babel.traverse(ast, { - Program: { - enter(programPath) { - const identifiers: { - createServerFn: IdentifierConfig - createMiddleware: IdentifierConfig - serverOnly: IdentifierConfig - clientOnly: IdentifierConfig - createIsomorphicFn: IdentifierConfig - } = { - createServerFn: { - name: 'createServerFn', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleCreateServerFnCallExpression, - paths: [], - }, - createMiddleware: { - name: 'createMiddleware', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleCreateMiddlewareCallExpression, - paths: [], - }, - serverOnly: { - name: 'serverOnly', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleServerOnlyCallExpression, - paths: [], - }, - clientOnly: { - name: 'clientOnly', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleClientOnlyCallExpression, - paths: [], - }, - createIsomorphicFn: { - name: 'createIsomorphicFn', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleCreateIsomorphicFnCallExpression, - paths: [], - }, - } - - const identifierKeys = Object.keys(identifiers) as Array< - keyof typeof identifiers - > - - programPath.traverse({ - ImportDeclaration: (path) => { - if (path.node.source.value !== '@tanstack/solid-start') { - return - } - - // handle a destructured imports being renamed like "import { createServerFn as myCreateServerFn } from '@tanstack/solid-start';" - path.node.specifiers.forEach((specifier) => { - identifierKeys.forEach((identifierKey) => { - const identifier = identifiers[identifierKey] - - if ( - specifier.type === 'ImportSpecifier' && - specifier.imported.type === 'Identifier' - ) { - if (specifier.imported.name === identifierKey) { - identifier.name = specifier.local.name - identifier.type = 'ImportSpecifier' - } - } - - // handle namespace imports like "import * as TanStackStart from '@tanstack/solid-start';" - if (specifier.type === 'ImportNamespaceSpecifier') { - identifier.type = 'ImportNamespaceSpecifier' - identifier.namespaceId = specifier.local.name - identifier.name = `${identifier.namespaceId}.${identifierKey}` - } - }) - }) - }, - CallExpression: (path) => { - identifierKeys.forEach((identifierKey) => { - // Check to see if the call expression is a call to the - // identifiers[identifierKey].name - if ( - t.isIdentifier(path.node.callee) && - path.node.callee.name === identifiers[identifierKey].name - ) { - // The identifier could be a call to the original function - // in the source code. If this is case, we need to ignore it. - // Check the scope to see if the identifier is a function declaration. - // if it is, then we can ignore it. - - if ( - path.scope.getBinding(identifiers[identifierKey].name)?.path - .node.type === 'FunctionDeclaration' - ) { - return - } - - return identifiers[identifierKey].paths.push(path) - } - - if (t.isMemberExpression(path.node.callee)) { - if ( - t.isIdentifier(path.node.callee.object) && - t.isIdentifier(path.node.callee.property) - ) { - const callname = [ - path.node.callee.object.name, - path.node.callee.property.name, - ].join('.') - - if (callname === identifiers[identifierKey].name) { - identifiers[identifierKey].paths.push(path) - } - } - } - - return - }) - }, - }) - - identifierKeys.forEach((identifierKey) => { - identifiers[identifierKey].paths.forEach((path) => { - identifiers[identifierKey].handleCallExpression( - path as babel.NodePath, - opts, - ) - }) - }) - }, - }, - }) - - if (doDce) { - deadCodeElimination(ast, refIdents) - } - - return generateFromAst(ast, { - sourceMaps: true, - sourceFileName: opts.filename, - filename: opts.filename, - }) -} - -function handleCreateServerFnCallExpression( - path: babel.NodePath, - opts: ParseAstOptions, -) { - // The function is the 'fn' property of the object passed to createServerFn - - // const firstArg = path.node.arguments[0] - // if (t.isObjectExpression(firstArg)) { - // // Was called with some options - // } - - // Traverse the member expression and find the call expressions for - // the validator, handler, and middleware methods. Check to make sure they - // are children of the createServerFn call expression. - - const calledOptions = path.node.arguments[0] - ? (path.get('arguments.0') as babel.NodePath) - : null - - const shouldValidateClient = !!calledOptions?.node.properties.find((prop) => { - return ( - t.isObjectProperty(prop) && - t.isIdentifier(prop.key) && - prop.key.name === 'validateClient' && - t.isBooleanLiteral(prop.value) && - prop.value.value === true - ) - }) - - const callExpressionPaths = { - middleware: null as babel.NodePath | null, - validator: null as babel.NodePath | null, - handler: null as babel.NodePath | null, - } - - const validMethods = Object.keys(callExpressionPaths) - - const rootCallExpression = getRootCallExpression(path) - - // if (debug) - // console.info( - // 'Handling createServerFn call expression:', - // rootCallExpression.toString(), - // ) - - // Check if the call is assigned to a variable - if (!rootCallExpression.parentPath.isVariableDeclarator()) { - throw new Error('createServerFn must be assigned to a variable!') - } - - // Get the identifier name of the variable - const variableDeclarator = rootCallExpression.parentPath.node - const existingVariableName = (variableDeclarator.id as t.Identifier).name - - rootCallExpression.traverse({ - MemberExpression(memberExpressionPath) { - if (t.isIdentifier(memberExpressionPath.node.property)) { - const name = memberExpressionPath.node.property - .name as keyof typeof callExpressionPaths - - if ( - validMethods.includes(name) && - memberExpressionPath.parentPath.isCallExpression() - ) { - callExpressionPaths[name] = memberExpressionPath.parentPath - } - } - }, - }) - - if (callExpressionPaths.validator) { - const innerInputExpression = callExpressionPaths.validator.node.arguments[0] - - if (!innerInputExpression) { - throw new Error( - 'createServerFn().validator() must be called with a validator!', - ) - } - - // If we're on the client, and we're not validating the client, remove the validator call expression - if ( - opts.env === 'client' && - !shouldValidateClient && - t.isMemberExpression(callExpressionPaths.validator.node.callee) - ) { - callExpressionPaths.validator.replaceWith( - callExpressionPaths.validator.node.callee.object, - ) - } - } - - // First, we need to move the handler function to a nested function call - // that is applied to the arguments passed to the server function. - - const handlerFnPath = callExpressionPaths.handler?.get( - 'arguments.0', - ) as babel.NodePath - - if (!callExpressionPaths.handler || !handlerFnPath.node) { - throw codeFrameError( - opts.code, - path.node.callee.loc!, - `createServerFn must be called with a "handler" property!`, - ) - } - - const handlerFn = handlerFnPath.node - - // So, the way we do this is we give the handler function a way - // to access the serverFn ctx on the server via function scope. - // The 'use server' extracted function will be called with the - // payload from the client, then use the scoped serverFn ctx - // to execute the handler function. - // This way, we can do things like data and middleware validation - // in the __execute function without having to AST transform the - // handler function too much itself. - - // .handler((optsOut, ctx) => { - // return ((optsIn) => { - // 'use server' - // ctx.__execute(handlerFn, optsIn) - // })(optsOut) - // }) - - // If the handler function is an identifier and we're on the client, we need to - // remove the bound function from the file. - // If we're on the server, you can leave it, since it will get referenced - // as a second argument. - - if (t.isIdentifier(handlerFn)) { - if (opts.env === 'client' || opts.env === 'ssr') { - // Find the binding for the handler function - const binding = handlerFnPath.scope.getBinding(handlerFn.name) - // Remove it - if (binding) { - binding.path.remove() - } - } - // If the env is server, just leave it alone - } - - handlerFnPath.replaceWith( - t.arrowFunctionExpression( - [t.identifier('opts'), t.identifier('signal')], - t.blockStatement( - // Everything in here is server-only, since the client - // will strip out anything in the 'use server' directive. - [ - t.returnStatement( - t.callExpression( - t.identifier(`${existingVariableName}.__executeServer`), - [t.identifier('opts'), t.identifier('signal')], - ), - ), - ], - [t.directive(t.directiveLiteral('use server'))], - ), - ), - ) - - if (opts.env === 'server') { - callExpressionPaths.handler.node.arguments.push(handlerFn) - } -} - -function handleCreateMiddlewareCallExpression( - path: babel.NodePath, - opts: ParseAstOptions, -) { - const rootCallExpression = getRootCallExpression(path) - - // if (debug) - // console.info( - // 'Handling createMiddleware call expression:', - // rootCallExpression.toString(), - // ) - - const callExpressionPaths = { - middleware: null as babel.NodePath | null, - validator: null as babel.NodePath | null, - client: null as babel.NodePath | null, - server: null as babel.NodePath | null, - } - - const validMethods = Object.keys(callExpressionPaths) - - rootCallExpression.traverse({ - MemberExpression(memberExpressionPath) { - if (t.isIdentifier(memberExpressionPath.node.property)) { - const name = memberExpressionPath.node.property - .name as keyof typeof callExpressionPaths - - if ( - validMethods.includes(name) && - memberExpressionPath.parentPath.isCallExpression() - ) { - callExpressionPaths[name] = memberExpressionPath.parentPath - } - } - }, - }) - - if (callExpressionPaths.validator) { - const innerInputExpression = callExpressionPaths.validator.node.arguments[0] - - if (!innerInputExpression) { - throw new Error( - 'createMiddleware().validator() must be called with a validator!', - ) - } - - // If we're on the client or ssr, remove the validator call expression - if (opts.env === 'client' || opts.env === 'ssr') { - if (t.isMemberExpression(callExpressionPaths.validator.node.callee)) { - callExpressionPaths.validator.replaceWith( - callExpressionPaths.validator.node.callee.object, - ) - } - } - } - - const serverFnPath = callExpressionPaths.server?.get( - 'arguments.0', - ) as babel.NodePath - - if ( - callExpressionPaths.server && - serverFnPath.node && - (opts.env === 'client' || opts.env === 'ssr') - ) { - // If we're on the client, remove the server call expression - if (t.isMemberExpression(callExpressionPaths.server.node.callee)) { - callExpressionPaths.server.replaceWith( - callExpressionPaths.server.node.callee.object, - ) - } - } -} - -function buildEnvOnlyCallExpressionHandler(env: 'client' | 'server') { - return function envOnlyCallExpressionHandler( - path: babel.NodePath, - opts: ParseAstOptions, - ) { - // if (debug) - // console.info(`Handling ${env}Only call expression:`, path.toString()) - - const isEnvMatch = - env === 'client' - ? opts.env === 'client' - : opts.env === 'server' || opts.env === 'ssr' - - if (isEnvMatch) { - // extract the inner function from the call expression - const innerInputExpression = path.node.arguments[0] - - if (!t.isExpression(innerInputExpression)) { - throw new Error( - `${env}Only() functions must be called with a function!`, - ) - } - - path.replaceWith(innerInputExpression) - return - } - - // If we're on the wrong environment, replace the call expression - // with a function that always throws an error. - path.replaceWith( - t.arrowFunctionExpression( - [], - t.blockStatement([ - t.throwStatement( - t.newExpression(t.identifier('Error'), [ - t.stringLiteral( - `${env}Only() functions can only be called on the ${env}!`, - ), - ]), - ), - ]), - ), - ) - } -} - -function handleCreateIsomorphicFnCallExpression( - path: babel.NodePath, - opts: CompileOptions, -) { - const rootCallExpression = getRootCallExpression(path) - - // if (debug) - // console.info( - // 'Handling createIsomorphicFn call expression:', - // rootCallExpression.toString(), - // ) - - const callExpressionPaths = { - client: null as babel.NodePath | null, - server: null as babel.NodePath | null, - } - - const validMethods = Object.keys(callExpressionPaths) - - rootCallExpression.traverse({ - MemberExpression(memberExpressionPath) { - if (t.isIdentifier(memberExpressionPath.node.property)) { - const name = memberExpressionPath.node.property - .name as keyof typeof callExpressionPaths - - if ( - validMethods.includes(name) && - memberExpressionPath.parentPath.isCallExpression() - ) { - callExpressionPaths[name] = memberExpressionPath.parentPath - } - } - }, - }) - - if ( - validMethods.every( - (method) => - !callExpressionPaths[method as keyof typeof callExpressionPaths], - ) - ) { - const variableId = rootCallExpression.parentPath.isVariableDeclarator() - ? rootCallExpression.parentPath.node.id - : null - console.warn( - 'createIsomorphicFn called without a client or server implementation!', - 'This will result in a no-op function.', - 'Variable name:', - t.isIdentifier(variableId) ? variableId.name : 'unknown', - ) - } - - const resolvedEnv = opts.env === 'ssr' ? 'server' : opts.env - - const envCallExpression = callExpressionPaths[resolvedEnv] - - if (!envCallExpression) { - // if we don't have an implementation for this environment, default to a no-op - rootCallExpression.replaceWith( - t.arrowFunctionExpression([], t.blockStatement([])), - ) - return - } - - const innerInputExpression = envCallExpression.node.arguments[0] - - if (!t.isExpression(innerInputExpression)) { - throw new Error( - `createIsomorphicFn().${resolvedEnv}(func) must be called with a function!`, - ) - } - - rootCallExpression.replaceWith(innerInputExpression) -} - -function getRootCallExpression(path: babel.NodePath) { - // Find the highest callExpression parent - let rootCallExpression: babel.NodePath = path - - // Traverse up the chain of CallExpressions - while (rootCallExpression.parentPath.isMemberExpression()) { - const parent = rootCallExpression.parentPath - if (parent.parentPath.isCallExpression()) { - rootCallExpression = parent.parentPath - } - } - - return rootCallExpression -} - -function codeFrameError( - code: string, - loc: { - start: { line: number; column: number } - end: { line: number; column: number } - }, - message: string, -) { - const frame = codeFrameColumns( - code, - { - start: loc.start, - end: loc.end, - }, - { - highlightCode: true, - message, - }, - ) - - return new Error(frame) -} diff --git a/packages/solid-start-plugin/src/index.ts b/packages/solid-start-plugin/src/index.ts index f24f09d18a..73986b51f1 100644 --- a/packages/solid-start-plugin/src/index.ts +++ b/packages/solid-start-plugin/src/index.ts @@ -1,130 +1,99 @@ -import { fileURLToPath, pathToFileURL } from 'node:url' import path from 'node:path' -import { existsSync } from 'node:fs' -import { logDiff } from '@tanstack/router-utils' -import { compileStartOutput } from './compilers' -import type { Plugin } from 'vite' +import viteSolid from 'vite-plugin-solid' +import { TanStackStartVitePluginCore } from '@tanstack/start-plugin-core' +import * as vite from 'vite' +import { getTanStackStartOptions } from './schema' +import type { PluginOption, ResolvedConfig } from 'vite' +import type { TanStackStartInputConfig, WithSolidPlugin } from './schema' -const debug = - process.env.TSR_VITE_DEBUG && - ['true', 'solid-start-plugin'].includes(process.env.TSR_VITE_DEBUG) +export type { + TanStackStartInputConfig, + TanStackStartOutputConfig, + WithSolidPlugin, +} from './schema' -export type TanStackStartViteOptions = { - globalMiddlewareEntry: string -} +export function TanStackStartVitePlugin( + opts?: TanStackStartInputConfig & WithSolidPlugin, +): Array { + type OptionsWithSolid = ReturnType & + WithSolidPlugin + const options: OptionsWithSolid = getTanStackStartOptions(opts) -const transformFuncs = [ - 'createServerFn', - 'createMiddleware', - 'serverOnly', - 'clientOnly', - 'createIsomorphicFn', -] -const tokenRegex = new RegExp(transformFuncs.join('|')) -// const eitherFuncRegex = new RegExp( -// `(function ${transformFuncs.join('|function ')})`, -// ) + let resolvedConfig: ResolvedConfig -export function createTanStackStartPlugin(opts: TanStackStartViteOptions): { - client: Array - ssr: Array - server: Array -} { - const globalMiddlewarePlugin = (): Plugin => { - let entry: string | null = null - let resolvedGlobalMiddlewareEntry: string | null = null - let globalMiddlewareEntryExists = false - let ROOT: string = process.cwd() - return { - name: 'vite-plugin-tanstack-start-ensure-global-middleware', - enforce: 'pre', + return [ + TanStackStartVitePluginCore({ framework: 'solid' }, options), + { + name: 'tanstack-solid-start:resolve-entries', configResolved: (config) => { - ROOT = config.root - entry = path.resolve(ROOT, (config as any).router.handler) - resolvedGlobalMiddlewareEntry = path.resolve( - ROOT, - opts.globalMiddlewareEntry, - ) - globalMiddlewareEntryExists = existsSync(resolvedGlobalMiddlewareEntry) - - if (!entry) { - throw new Error( - '@tanstack/solid-start-plugin: No server entry found!', - ) - } + resolvedConfig = config }, - transform(code, id) { - if (entry && id.includes(entry)) { - if (globalMiddlewareEntryExists) { - return { - code: `${code}\n\nimport '${path.resolve(ROOT, opts.globalMiddlewareEntry)}'`, - map: null, - } - } + resolveId(id) { + if ( + [ + '/~start/server-entry', + '/~start/default-server-entry', + '/~start/default-client-entry', + ].includes(id) + ) { + return `${id}.tsx` } - return code + + return null }, - } - } + load(id) { + const routerImportPath = JSON.stringify( + path.resolve(options.root, options.tsr.srcDirectory, 'router'), + ) - return { - client: [ - globalMiddlewarePlugin(), - TanStackStartServerFnsAndMiddleware({ ...opts, env: 'client' }), - ], - ssr: [ - globalMiddlewarePlugin(), - TanStackStartServerFnsAndMiddleware({ ...opts, env: 'ssr' }), - ], - server: [ - globalMiddlewarePlugin(), - TanStackStartServerFnsAndMiddleware({ ...opts, env: 'server' }), - ], - } -} + if (id === '/~start/server-entry.tsx') { + const ssrEntryPath = options.serverEntryPath.startsWith( + '/~start/default-server-entry', + ) + ? options.serverEntryPath + : vite.normalizePath( + path.resolve(resolvedConfig.root, options.serverEntryPath), + ) -export function TanStackStartServerFnsAndMiddleware(opts: { - env: 'server' | 'ssr' | 'client' -}): Plugin { - let ROOT: string = process.cwd() + return ` +import { toWebRequest, defineEventHandler } from '@tanstack/solid-start/server'; +import serverEntry from '${ssrEntryPath}'; - return { - name: 'vite-plugin-tanstack-start-create-server-fn', - enforce: 'pre', - configResolved: (config) => { - ROOT = config.root - }, - transform(code, id) { - const url = pathToFileURL(id) - url.searchParams.delete('v') - id = fileURLToPath(url).replace(/\\/g, '/') +export default defineEventHandler(function(event) { + const request = toWebRequest(event); + return serverEntry({ request }); +}) +` + } - const includesToken = tokenRegex.test(code) - // const includesEitherFunc = eitherFuncRegex.test(code) + if (id === '/~start/default-client-entry.tsx') { + return ` +import { hydrate } from 'solid-js/web' +import { StartClient } from '@tanstack/solid-start' +import { createRouter } from ${routerImportPath} - if ( - !includesToken - // includesEitherFunc - // /node_modules/.test(id) - ) { - return null - } +const router = createRouter() - if (debug) console.info(`${opts.env} Compiling Start: `, id) +hydrate(() => , document.body) +` + } - const compiled = compileStartOutput({ - code, - root: ROOT, - filename: id, - env: opts.env, - }) + if (id === '/~start/default-server-entry.tsx') { + return ` +import { createStartHandler, defaultStreamHandler } from '@tanstack/solid-start/server' +import { createRouter } from ${routerImportPath} - if (debug) { - logDiff(code, compiled.code) - console.log('Output:\n', compiled.code + '\n\n') - } +export default createStartHandler({ + createRouter, +})(defaultStreamHandler) +` + } - return compiled + return null + }, }, - } + viteSolid({ ...options.solid, ssr: true }), + ] } + +export { TanStackStartVitePlugin as tanstackStart } diff --git a/packages/solid-start-plugin/src/schema.ts b/packages/solid-start-plugin/src/schema.ts new file mode 100644 index 0000000000..c9d836957c --- /dev/null +++ b/packages/solid-start-plugin/src/schema.ts @@ -0,0 +1,31 @@ +import { z } from 'zod' +import { + createTanStackConfig, + createTanStackStartOptionsSchema, +} from '@tanstack/start-plugin-core' +import type { Options as ViteSolidOptions } from 'vite-plugin-solid' + +export type WithSolidPlugin = { + solid?: ViteSolidOptions +} + +const frameworkPlugin = { + solid: z.custom().optional(), +} + +// eslint-disable-next-line unused-imports/no-unused-vars +const TanStackStartOptionsSchema = + createTanStackStartOptionsSchema(frameworkPlugin) + +const defaultConfig = createTanStackConfig(frameworkPlugin) + +export function getTanStackStartOptions(opts?: TanStackStartInputConfig) { + return defaultConfig.parse(opts) +} + +export type TanStackStartInputConfig = z.input< + typeof TanStackStartOptionsSchema +> +export type TanStackStartOutputConfig = ReturnType< + typeof getTanStackStartOptions +> diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/createIsomorphicFn.test.ts b/packages/solid-start-plugin/tests/createIsomorphicFn/createIsomorphicFn.test.ts deleted file mode 100644 index 9d1e78228e..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/createIsomorphicFn.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { readFile, readdir } from 'node:fs/promises' -import path from 'node:path' -import { afterAll, describe, expect, test, vi } from 'vitest' - -import { compileStartOutput } from '../../src/compilers' - -async function getFilenames() { - return await readdir(path.resolve(import.meta.dirname, './test-files')) -} - -describe('createIsomorphicFn compiles correctly', async () => { - const noImplWarning = - 'createIsomorphicFn called without a client or server implementation!' - - const originalConsoleWarn = console.warn - const consoleSpy = vi.spyOn(console, 'warn').mockImplementation((...args) => { - // we want to avoid sending this warning to the console, we know about it - if (args[0] === noImplWarning) { - return - } - originalConsoleWarn(...args) - }) - - afterAll(() => { - consoleSpy.mockRestore() - }) - - const filenames = await getFilenames() - - describe.each(filenames)('should handle "%s"', async (filename) => { - const file = await readFile( - path.resolve(import.meta.dirname, `./test-files/${filename}`), - ) - const code = file.toString() - - test.each(['client', 'server'] as const)( - `should compile for ${filename} %s`, - async (env) => { - const compiledResult = compileStartOutput({ - env, - code, - root: './test-files', - filename, - dce: false, - }) - - await expect(compiledResult.code).toMatchFileSnapshot( - `./snapshots/${env}/${filename}`, - ) - }, - ) - }) - test('should error if implementation not provided', () => { - expect(() => { - compileStartOutput({ - env: 'client', - code: ` - import { createIsomorphicFn } from '@tanstack/solid-start' - const clientOnly = createIsomorphicFn().client()`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - }).toThrowError() - expect(() => { - compileStartOutput({ - env: 'server', - code: ` - import { createIsomorphicFn } from '@tanstack/solid-start' - const serverOnly = createIsomorphicFn().server()`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - }).toThrowError() - }) - test('should warn to console if no implementations provided', () => { - compileStartOutput({ - env: 'client', - code: ` - import { createIsomorphicFn } from '@tanstack/solid-start' - const noImpl = createIsomorphicFn()`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - expect(consoleSpy).toHaveBeenCalledWith( - noImplWarning, - 'This will result in a no-op function.', - 'Variable name:', - 'noImpl', - ) - }) -}) diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx deleted file mode 100644 index 269cab1607..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { createIsomorphicFn } from '@tanstack/solid-start'; -const noImpl = () => {}; -const serverOnlyFn = () => {}; -const clientOnlyFn = () => 'client'; -const serverThenClientFn = () => 'client'; -const clientThenServerFn = () => 'client'; -function abstractedServerFn() { - return 'server'; -} -const serverOnlyFnAbstracted = () => {}; -function abstractedClientFn() { - return 'client'; -} -const clientOnlyFnAbstracted = abstractedClientFn; -const serverThenClientFnAbstracted = abstractedClientFn; -const clientThenServerFnAbstracted = abstractedClientFn; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx deleted file mode 100644 index 3c5c041e90..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { createIsomorphicFn as isomorphicFn } from '@tanstack/solid-start'; -const noImpl = () => {}; -const serverOnlyFn = () => {}; -const clientOnlyFn = () => 'client'; -const serverThenClientFn = () => 'client'; -const clientThenServerFn = () => 'client'; -function abstractedServerFn() { - return 'server'; -} -const serverOnlyFnAbstracted = () => {}; -function abstractedClientFn() { - return 'client'; -} -const clientOnlyFnAbstracted = abstractedClientFn; -const serverThenClientFnAbstracted = abstractedClientFn; -const clientThenServerFnAbstracted = abstractedClientFn; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx deleted file mode 100644 index 5b90ddeaf1..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start'; -const noImpl = () => {}; -const serverOnlyFn = () => {}; -const clientOnlyFn = () => 'client'; -const serverThenClientFn = () => 'client'; -const clientThenServerFn = () => 'client'; -function abstractedServerFn() { - return 'server'; -} -const serverOnlyFnAbstracted = () => {}; -function abstractedClientFn() { - return 'client'; -} -const clientOnlyFnAbstracted = abstractedClientFn; -const serverThenClientFnAbstracted = abstractedClientFn; -const clientThenServerFnAbstracted = abstractedClientFn; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx deleted file mode 100644 index 126e2404c5..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { createIsomorphicFn } from '@tanstack/solid-start'; -const noImpl = () => {}; -const serverOnlyFn = () => 'server'; -const clientOnlyFn = () => {}; -const serverThenClientFn = () => 'server'; -const clientThenServerFn = () => 'server'; -function abstractedServerFn() { - return 'server'; -} -const serverOnlyFnAbstracted = abstractedServerFn; -function abstractedClientFn() { - return 'client'; -} -const clientOnlyFnAbstracted = () => {}; -const serverThenClientFnAbstracted = abstractedServerFn; -const clientThenServerFnAbstracted = abstractedServerFn; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx deleted file mode 100644 index 442156f4e3..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { createIsomorphicFn as isomorphicFn } from '@tanstack/solid-start'; -const noImpl = () => {}; -const serverOnlyFn = () => 'server'; -const clientOnlyFn = () => {}; -const serverThenClientFn = () => 'server'; -const clientThenServerFn = () => 'server'; -function abstractedServerFn() { - return 'server'; -} -const serverOnlyFnAbstracted = abstractedServerFn; -function abstractedClientFn() { - return 'client'; -} -const clientOnlyFnAbstracted = () => {}; -const serverThenClientFnAbstracted = abstractedServerFn; -const clientThenServerFnAbstracted = abstractedServerFn; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx deleted file mode 100644 index 318745b993..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start'; -const noImpl = () => {}; -const serverOnlyFn = () => 'server'; -const clientOnlyFn = () => {}; -const serverThenClientFn = () => 'server'; -const clientThenServerFn = () => 'server'; -function abstractedServerFn() { - return 'server'; -} -const serverOnlyFnAbstracted = abstractedServerFn; -function abstractedClientFn() { - return 'client'; -} -const clientOnlyFnAbstracted = () => {}; -const serverThenClientFnAbstracted = abstractedServerFn; -const clientThenServerFnAbstracted = abstractedServerFn; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx deleted file mode 100644 index 51263bea85..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { createIsomorphicFn } from '@tanstack/solid-start' - -const noImpl = createIsomorphicFn() - -const serverOnlyFn = createIsomorphicFn().server(() => 'server') - -const clientOnlyFn = createIsomorphicFn().client(() => 'client') - -const serverThenClientFn = createIsomorphicFn() - .server(() => 'server') - .client(() => 'client') - -const clientThenServerFn = createIsomorphicFn() - .client(() => 'client') - .server(() => 'server') - -function abstractedServerFn() { - return 'server' -} - -const serverOnlyFnAbstracted = createIsomorphicFn().server(abstractedServerFn) - -function abstractedClientFn() { - return 'client' -} - -const clientOnlyFnAbstracted = createIsomorphicFn().client(abstractedClientFn) - -const serverThenClientFnAbstracted = createIsomorphicFn() - .server(abstractedServerFn) - .client(abstractedClientFn) - -const clientThenServerFnAbstracted = createIsomorphicFn() - .client(abstractedClientFn) - .server(abstractedServerFn) diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx deleted file mode 100644 index 6606a86c50..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { createIsomorphicFn as isomorphicFn } from '@tanstack/solid-start' - -const noImpl = isomorphicFn() - -const serverOnlyFn = isomorphicFn().server(() => 'server') - -const clientOnlyFn = isomorphicFn().client(() => 'client') - -const serverThenClientFn = isomorphicFn() - .server(() => 'server') - .client(() => 'client') - -const clientThenServerFn = isomorphicFn() - .client(() => 'client') - .server(() => 'server') - -function abstractedServerFn() { - return 'server' -} - -const serverOnlyFnAbstracted = isomorphicFn().server(abstractedServerFn) - -function abstractedClientFn() { - return 'client' -} - -const clientOnlyFnAbstracted = isomorphicFn().client(abstractedClientFn) - -const serverThenClientFnAbstracted = isomorphicFn() - .server(abstractedServerFn) - .client(abstractedClientFn) - -const clientThenServerFnAbstracted = isomorphicFn() - .client(abstractedClientFn) - .server(abstractedServerFn) diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx deleted file mode 100644 index 9ca4b15b94..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start' - -const noImpl = TanStackStart.createIsomorphicFn() - -const serverOnlyFn = TanStackStart.createIsomorphicFn().server(() => 'server') - -const clientOnlyFn = TanStackStart.createIsomorphicFn().client(() => 'client') - -const serverThenClientFn = TanStackStart.createIsomorphicFn() - .server(() => 'server') - .client(() => 'client') - -const clientThenServerFn = TanStackStart.createIsomorphicFn() - .client(() => 'client') - .server(() => 'server') - -function abstractedServerFn() { - return 'server' -} - -const serverOnlyFnAbstracted = - TanStackStart.createIsomorphicFn().server(abstractedServerFn) - -function abstractedClientFn() { - return 'client' -} - -const clientOnlyFnAbstracted = - TanStackStart.createIsomorphicFn().client(abstractedClientFn) - -const serverThenClientFnAbstracted = TanStackStart.createIsomorphicFn() - .server(abstractedServerFn) - .client(abstractedClientFn) - -const clientThenServerFnAbstracted = TanStackStart.createIsomorphicFn() - .client(abstractedClientFn) - .server(abstractedServerFn) diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx deleted file mode 100644 index ac0d1d2a9a..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { createMiddleware } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createMiddleware({ - id: 'test' -}); -export const withoutUseServer = createMiddleware({ - id: 'test' -}); -export const withVariable = createMiddleware({ - id: 'test' -}); -async function abstractedFunction() { - 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)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = createMiddleware({ - id: 'test' -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx deleted file mode 100644 index 3e917e901f..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { createMiddleware as middlewareFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = middlewareFn({ - id: 'test' -}); -export const withoutUseServer = middlewareFn({ - id: 'test' -}); -export const withVariable = middlewareFn({ - id: 'test' -}); -async function abstractedFunction() { - 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)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = middlewareFn({ - id: 'test' -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx deleted file mode 100644 index 00d22094e8..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = TanStackStart.createMiddleware({ - id: 'test' -}); -export const withoutUseServer = TanStackStart.createMiddleware({ - id: 'test' -}); -export const withVariable = TanStackStart.createMiddleware({ - id: 'test' -}); -async function abstractedFunction() { - 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)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = TanStackStart.createMiddleware({ - id: 'test' -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx deleted file mode 100644 index 40a49dca05..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { createMiddleware } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createMiddleware({ - id: 'test' -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx deleted file mode 100644 index dda24f7c4e..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { createMiddleware } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createMiddleware({ - id: 'test' -}).server(async function () { - 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)); -}); -export const withoutUseServer = createMiddleware({ - id: 'test' -}).server(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)); -}); -export const withVariable = createMiddleware({ - id: 'test' -}).server(abstractedFunction); -async function abstractedFunction() { - 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)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = createMiddleware({ - id: 'test' -}).server(zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx deleted file mode 100644 index 7fcc6b7b5a..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { createMiddleware as middlewareFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = middlewareFn({ - id: 'test' -}).server(async function () { - 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)); -}); -export const withoutUseServer = middlewareFn({ - id: 'test' -}).server(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)); -}); -export const withVariable = middlewareFn({ - id: 'test' -}).server(abstractedFunction); -async function abstractedFunction() { - 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)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = middlewareFn({ - id: 'test' -}).server(zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx deleted file mode 100644 index 92047bfa0a..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = TanStackStart.createMiddleware({ - id: 'test' -}).server(async function () { - 'use server'; - - 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)); -}); -export const withoutUseServer = TanStackStart.createMiddleware({ - id: 'test' -}).server(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)); -}); -export const withVariable = TanStackStart.createMiddleware({ - id: 'test' -}).server(abstractedFunction); -async function abstractedFunction() { - 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)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = TanStackStart.createMiddleware({ - id: 'test' -}).server(zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx deleted file mode 100644 index eb3d933b77..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { createMiddleware } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createMiddleware({ - id: 'test' -}).validator(z.number()).server(({ - input -}) => input + 1); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx b/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx deleted file mode 100644 index 595099cdbe..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { createMiddleware } from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = createMiddleware({ - id: 'test', -}).server(async function () { - 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)) -}) - -export const withoutUseServer = createMiddleware({ - id: 'test', -}).server(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)) -}) - -export const withVariable = createMiddleware({ - id: 'test', -}).server(abstractedFunction) - -async function abstractedFunction() { - 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)) -} - -function zodValidator( - schema: TSchema, - fn: (input: z.output) => TResult, -) { - return async (input: unknown) => { - return fn(schema.parse(input)) - } -} - -export const withZodValidator = createMiddleware({ - id: 'test', -}).server( - zodValidator(z.number(), (input) => { - return { 'you gave': input } - }), -) diff --git a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx b/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx deleted file mode 100644 index 700da4fe63..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { createMiddleware as middlewareFn } from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = middlewareFn({ - id: 'test', -}).server(async function () { - 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)) -}) - -export const withoutUseServer = middlewareFn({ - id: 'test', -}).server(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)) -}) - -export const withVariable = middlewareFn({ - id: 'test', -}).server(abstractedFunction) - -async function abstractedFunction() { - 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)) -} - -function zodValidator( - schema: TSchema, - fn: (input: z.output) => TResult, -) { - return async (input: unknown) => { - return fn(schema.parse(input)) - } -} - -export const withZodValidator = middlewareFn({ - id: 'test', -}).server( - zodValidator(z.number(), (input) => { - return { 'you gave': input } - }), -) diff --git a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx b/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx deleted file mode 100644 index 315d29e1c7..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = TanStackStart.createMiddleware({ - id: 'test', -}).server(async function () { - 'use server' - 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)) -}) - -export const withoutUseServer = TanStackStart.createMiddleware({ - id: 'test', -}).server(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)) -}) - -export const withVariable = TanStackStart.createMiddleware({ - id: 'test', -}).server(abstractedFunction) - -async function abstractedFunction() { - 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)) -} - -function zodValidator( - schema: TSchema, - fn: (input: z.output) => TResult, -) { - return async (input: unknown) => { - return fn(schema.parse(input)) - } -} - -export const withZodValidator = TanStackStart.createMiddleware({ - id: 'test', -}).server( - zodValidator(z.number(), (input) => { - return { 'you gave': input } - }), -) diff --git a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareValidator.tsx b/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareValidator.tsx deleted file mode 100644 index 62ea02b36a..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareValidator.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { createMiddleware } from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = createMiddleware({ - id: 'test', -}) - .validator(z.number()) - .server(({ input }) => input + 1) diff --git a/packages/solid-start-plugin/tests/createServerFn/createServerFn.test.ts b/packages/solid-start-plugin/tests/createServerFn/createServerFn.test.ts deleted file mode 100644 index 8d30fee5ad..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/createServerFn.test.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { readFile, readdir } from 'node:fs/promises' -import path from 'node:path' -import { describe, expect, test } from 'vitest' - -import { compileStartOutput } from '../../src/compilers' - -async function getFilenames() { - return await readdir(path.resolve(import.meta.dirname, './test-files')) -} - -describe('createServerFn compiles correctly', async () => { - const filenames = await getFilenames() - - describe.each(filenames)('should handle "%s"', async (filename) => { - const file = await readFile( - path.resolve(import.meta.dirname, `./test-files/${filename}`), - ) - const code = file.toString() - - test.each(['client', 'server'] as const)( - `should compile for ${filename} %s`, - async (env) => { - const compiledResult = compileStartOutput({ - env, - code, - root: './test-files', - filename, - dce: false, - }) - - await expect(compiledResult.code).toMatchFileSnapshot( - `./snapshots/${env}/${filename}`, - ) - }, - ) - }) - - test('should error if created without a handler', () => { - expect(() => { - compileStartOutput({ - env: 'client', - code: ` - import { createServerFn } from '@tanstack/solid-start' - createServerFn()`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - }).toThrowError() - }) - - test('should be assigned to a variable', () => { - expect(() => { - compileStartOutput({ - env: 'client', - code: ` - import { createServerFn } from '@tanstack/solid-start' - createServerFn().handler(async () => {})`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - }).toThrowError() - }) - - test('should work with identifiers of functions', () => { - const code = ` - import { createServerFn } from '@tanstack/solid-start' - const myFunc = () => { - return 'hello from the server' - } - const myServerFn = createServerFn().handler(myFunc)` - - const compiledResultClient = compileStartOutput({ - root: '/test', - filename: 'test.ts', - code, - env: 'client', - dce: false, - }) - - const compiledResultServer = compileStartOutput({ - root: '/test', - filename: 'test.ts', - code, - env: 'server', - dce: false, - }) - - expect(compiledResultClient.code).toMatchInlineSnapshot(` - "import { createServerFn } from '@tanstack/solid-start'; - const myServerFn = createServerFn().handler((opts, signal) => { - "use server"; - - return myServerFn.__executeServer(opts, signal); - });" - `) - - expect(compiledResultServer.code).toMatchInlineSnapshot(` - "import { createServerFn } from '@tanstack/solid-start'; - const myFunc = () => { - return 'hello from the server'; - }; - const myServerFn = createServerFn().handler((opts, signal) => { - "use server"; - - return myServerFn.__executeServer(opts, signal); - }, myFunc);" - `) - }) - - test('should use dce by default', () => { - const code = ` - import { createServerFn } from '@tanstack/solid-start' - const exportedVar = 'exported' - export const exportedFn = createServerFn().handler(async () => { - return exportedVar - }) - const nonExportedVar = 'non-exported' - const nonExportedFn = createServerFn().handler(async () => { - return nonExportedVar - })` - - // Client - const compiledResult = compileStartOutput({ - root: '/test', - filename: 'test.ts', - code, - env: 'client', - dce: true, - }) - - expect(compiledResult.code).toMatchInlineSnapshot(` - "import { createServerFn } from '@tanstack/solid-start'; - export const exportedFn = createServerFn().handler((opts, signal) => { - "use server"; - - return exportedFn.__executeServer(opts, signal); - }); - const nonExportedFn = createServerFn().handler((opts, signal) => { - "use server"; - - return nonExportedFn.__executeServer(opts, signal); - });" - `) - - // Server - const compiledResultServer = compileStartOutput({ - root: '/test', - filename: 'test.ts', - code, - env: 'server', - dce: true, - }) - - expect(compiledResultServer.code).toMatchInlineSnapshot(` - "import { createServerFn } from '@tanstack/solid-start'; - const exportedVar = 'exported'; - export const exportedFn = createServerFn().handler((opts, signal) => { - "use server"; - - return exportedFn.__executeServer(opts, signal); - }, async () => { - return exportedVar; - }); - const nonExportedVar = 'non-exported'; - const nonExportedFn = createServerFn().handler((opts, signal) => { - "use server"; - - return nonExportedFn.__executeServer(opts, signal); - }, async () => { - return nonExportedVar; - });" - `) - }) -}) diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx deleted file mode 100644 index d8105165f0..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { createServerFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}); -export const withArrowFunction = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withArrowFunction.__executeServer(opts, signal); -}); -export const withArrowFunctionAndFunction = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withArrowFunctionAndFunction.__executeServer(opts, signal); -}); -export const withoutUseServer = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withoutUseServer.__executeServer(opts, signal); -}); -export const withVariable = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withVariable.__executeServer(opts, signal); -}); -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withZodValidator.__executeServer(opts, signal); -}); -export const withValidatorFn = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withValidatorFn.__executeServer(opts, signal); -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx deleted file mode 100644 index e7d1010563..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { createServerFn as serverFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}); -export const withoutUseServer = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withoutUseServer.__executeServer(opts, signal); -}); -export const withVariable = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withVariable.__executeServer(opts, signal); -}); -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withZodValidator.__executeServer(opts, signal); -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx deleted file mode 100644 index e2735ea5d1..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}); -export const withoutUseServer = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withoutUseServer.__executeServer(opts, signal); -}); -export const withVariable = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withVariable.__executeServer(opts, signal); -}); -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withZodValidator.__executeServer(opts, signal); -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnValidator.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnValidator.tsx deleted file mode 100644 index f43f06ee88..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnValidator.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { createServerFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx deleted file mode 100644 index 673c4e90fe..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { createServerFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}, async function () { - 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)); -}); -export const withArrowFunction = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withArrowFunction.__executeServer(opts, signal); -}, async () => null); -export const withArrowFunctionAndFunction = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withArrowFunctionAndFunction.__executeServer(opts, signal); -}, async () => test()); -export const withoutUseServer = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withoutUseServer.__executeServer(opts, signal); -}, 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)); -}); -export const withVariable = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withVariable.__executeServer(opts, signal); -}, abstractedFunction); -async function abstractedFunction() { - 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)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withZodValidator.__executeServer(opts, signal); -}, zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); -export const withValidatorFn = createServerFn({ - method: 'GET' -}).validator(z.number()).handler((opts, signal) => { - "use server"; - - return withValidatorFn.__executeServer(opts, signal); -}, async ({ - input -}) => { - return null; -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx deleted file mode 100644 index d9902417f5..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { createServerFn as serverFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}, async function () { - 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)); -}); -export const withoutUseServer = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withoutUseServer.__executeServer(opts, signal); -}, 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)); -}); -export const withVariable = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withVariable.__executeServer(opts, signal); -}, abstractedFunction); -async function abstractedFunction() { - 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)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withZodValidator.__executeServer(opts, signal); -}, zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx deleted file mode 100644 index 83964ecc5c..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}, async function () { - 'use server'; - - 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)); -}); -export const withoutUseServer = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withoutUseServer.__executeServer(opts, signal); -}, 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)); -}); -export const withVariable = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withVariable.__executeServer(opts, signal); -}, abstractedFunction); -async function abstractedFunction() { - 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)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withZodValidator.__executeServer(opts, signal); -}, zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnValidator.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnValidator.tsx deleted file mode 100644 index 364f8354fa..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnValidator.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { createServerFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createServerFn({ - method: 'GET' -}).validator(z.number()).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}, ({ - input -}) => input + 1); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnDestructured.tsx b/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnDestructured.tsx deleted file mode 100644 index fd7f48510d..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnDestructured.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { createServerFn } from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = createServerFn({ - method: 'GET', -}).handler(async function () { - 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)) -}) - -export const withArrowFunction = createServerFn({ - method: 'GET', -}).handler(async () => null) - -export const withArrowFunctionAndFunction = createServerFn({ - method: 'GET', -}).handler(async () => test()) - -export const withoutUseServer = createServerFn({ - method: 'GET', -}).handler(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)) -}) - -export const withVariable = createServerFn({ - method: 'GET', -}).handler(abstractedFunction) - -async function abstractedFunction() { - 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)) -} - -function zodValidator( - schema: TSchema, - fn: (input: z.output) => TResult, -) { - return async (input: unknown) => { - return fn(schema.parse(input)) - } -} - -export const withZodValidator = createServerFn({ - method: 'GET', -}).handler( - zodValidator(z.number(), (input) => { - return { 'you gave': input } - }), -) - -export const withValidatorFn = createServerFn({ - method: 'GET', -}) - .validator(z.number()) - .handler(async ({ input }) => { - return null - }) diff --git a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx b/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx deleted file mode 100644 index 823339b3ac..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { createServerFn as serverFn } from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = serverFn({ - method: 'GET', -}).handler(async function () { - 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)) -}) - -export const withoutUseServer = serverFn({ - method: 'GET', -}).handler(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)) -}) - -export const withVariable = serverFn({ method: 'GET' }).handler( - abstractedFunction, -) - -async function abstractedFunction() { - 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)) -} - -function zodValidator( - schema: TSchema, - fn: (input: z.output) => TResult, -) { - return async (input: unknown) => { - return fn(schema.parse(input)) - } -} - -export const withZodValidator = serverFn({ - method: 'GET', -}).handler( - zodValidator(z.number(), (input) => { - return { 'you gave': input } - }), -) diff --git a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnStarImport.tsx b/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnStarImport.tsx deleted file mode 100644 index d4ecddb304..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnStarImport.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = TanStackStart.createServerFn({ - method: 'GET', -}).handler(async function () { - 'use server' - 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)) -}) - -export const withoutUseServer = TanStackStart.createServerFn({ - method: 'GET', -}).handler(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)) -}) - -export const withVariable = TanStackStart.createServerFn({ - method: 'GET', -}).handler(abstractedFunction) - -async function abstractedFunction() { - 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)) -} - -function zodValidator( - schema: TSchema, - fn: (input: z.output) => TResult, -) { - return async (input: unknown) => { - return fn(schema.parse(input)) - } -} - -export const withZodValidator = TanStackStart.createServerFn({ - method: 'GET', -}).handler( - zodValidator(z.number(), (input) => { - return { 'you gave': input } - }), -) diff --git a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnValidator.tsx b/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnValidator.tsx deleted file mode 100644 index 0d535eb369..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnValidator.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { createServerFn } from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = createServerFn({ - method: 'GET', -}) - .validator(z.number()) - .handler(({ input }) => input + 1) diff --git a/packages/solid-start-plugin/tests/envOnly/envOnly.test.ts b/packages/solid-start-plugin/tests/envOnly/envOnly.test.ts deleted file mode 100644 index 00c9786170..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/envOnly.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { readFile, readdir } from 'node:fs/promises' -import path from 'node:path' -import { describe, expect, test } from 'vitest' - -import { compileStartOutput } from '../../src/compilers' - -async function getFilenames() { - return await readdir(path.resolve(import.meta.dirname, './test-files')) -} - -describe('envOnly functions compile correctly', async () => { - const filenames = await getFilenames() - - describe.each(filenames)('should handle "%s"', async (filename) => { - const file = await readFile( - path.resolve(import.meta.dirname, `./test-files/${filename}`), - ) - const code = file.toString() - - test.each(['client', 'server'] as const)( - `should compile for ${filename} %s`, - async (env) => { - const compiledResult = compileStartOutput({ - env, - code, - root: './test-files', - filename, - dce: false, - }) - - await expect(compiledResult.code).toMatchFileSnapshot( - `./snapshots/${env}/${filename}`, - ) - }, - ) - }) - test('should error if implementation not provided', () => { - expect(() => { - compileStartOutput({ - env: 'client', - code: ` - import { clientOnly } from '@tanstack/solid-start' - const fn = clientOnly()`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - }).toThrowError() - expect(() => { - compileStartOutput({ - env: 'server', - code: ` - import { serverOnly } from '@tanstack/solid-start' - const fn = serverOnly()`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - }).toThrowError() - }) -}) diff --git a/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructured.tsx b/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructured.tsx deleted file mode 100644 index 8080d677e6..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructured.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { serverOnly, clientOnly } from '@tanstack/solid-start'; -const serverFunc = () => { - throw new Error("serverOnly() functions can only be called on the server!"); -}; -const clientFunc = () => 'client'; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx b/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx deleted file mode 100644 index c3e67e045b..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { serverOnly as serverFn, clientOnly as clientFn } from '@tanstack/solid-start'; -const serverFunc = () => { - throw new Error("serverOnly() functions can only be called on the server!"); -}; -const clientFunc = () => 'client'; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyStarImport.tsx b/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyStarImport.tsx deleted file mode 100644 index d860ab6d21..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyStarImport.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import * as TanstackStart from '@tanstack/solid-start'; -const serverFunc = () => { - throw new Error("serverOnly() functions can only be called on the server!"); -}; -const clientFunc = () => 'client'; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructured.tsx b/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructured.tsx deleted file mode 100644 index 35bf2907cc..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructured.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { serverOnly, clientOnly } from '@tanstack/solid-start'; -const serverFunc = () => 'server'; -const clientFunc = () => { - throw new Error("clientOnly() functions can only be called on the client!"); -}; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx b/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx deleted file mode 100644 index 31c1c2a23b..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { serverOnly as serverFn, clientOnly as clientFn } from '@tanstack/solid-start'; -const serverFunc = () => 'server'; -const clientFunc = () => { - throw new Error("clientOnly() functions can only be called on the client!"); -}; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyStarImport.tsx b/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyStarImport.tsx deleted file mode 100644 index 318b47dd64..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyStarImport.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import * as TanstackStart from '@tanstack/solid-start'; -const serverFunc = () => 'server'; -const clientFunc = () => { - throw new Error("clientOnly() functions can only be called on the client!"); -}; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyDestructured.tsx b/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyDestructured.tsx deleted file mode 100644 index c4513f737d..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyDestructured.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { serverOnly, clientOnly } from '@tanstack/solid-start' - -const serverFunc = serverOnly(() => 'server') - -const clientFunc = clientOnly(() => 'client') diff --git a/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyDestructuredRename.tsx b/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyDestructuredRename.tsx deleted file mode 100644 index 4b48ba3b58..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyDestructuredRename.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { - serverOnly as serverFn, - clientOnly as clientFn, -} from '@tanstack/solid-start' - -const serverFunc = serverFn(() => 'server') - -const clientFunc = clientFn(() => 'client') diff --git a/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyStarImport.tsx b/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyStarImport.tsx deleted file mode 100644 index adeab52616..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyStarImport.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import * as TanstackStart from '@tanstack/solid-start' - -const serverFunc = TanstackStart.serverOnly(() => 'server') - -const clientFunc = TanstackStart.clientOnly(() => 'client') diff --git a/packages/solid-start-plugin/tsconfig.json b/packages/solid-start-plugin/tsconfig.json index 37d21ef6ca..090ec3917d 100644 --- a/packages/solid-start-plugin/tsconfig.json +++ b/packages/solid-start-plugin/tsconfig.json @@ -3,6 +3,8 @@ "include": ["src", "vite.config.ts", "tests"], "exclude": ["tests/**/test-files/**", "tests/**/snapshots/**"], "compilerOptions": { - "jsx": "react-jsx" + "outDir": "dist/esm", + "target": "esnext", + "noEmit": true } } diff --git a/packages/solid-start-plugin/vite.config.ts b/packages/solid-start-plugin/vite.config.ts index 5389f0f739..2c711fd181 100644 --- a/packages/solid-start-plugin/vite.config.ts +++ b/packages/solid-start-plugin/vite.config.ts @@ -16,5 +16,6 @@ export default mergeConfig( tanstackViteConfig({ entry: './src/index.ts', srcDir: './src', + outDir: './dist', }), ) diff --git a/packages/solid-start-router-manifest/README.md b/packages/solid-start-router-manifest/README.md deleted file mode 100644 index bb009b0c87..0000000000 --- a/packages/solid-start-router-manifest/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/solid-start-router-manifest/eslint.config.js b/packages/solid-start-router-manifest/eslint.config.js deleted file mode 100644 index 931f0ec774..0000000000 --- a/packages/solid-start-router-manifest/eslint.config.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check - -import pluginReact from '@eslint-react/eslint-plugin' -import pluginReactHooks from 'eslint-plugin-react-hooks' -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - ...pluginReact.configs.recommended, - files: ['**/*.{ts,tsx}'], - }, - { - plugins: { - 'react-hooks': pluginReactHooks, - }, - rules: { - '@eslint-react/no-unstable-context-value': 'off', - '@eslint-react/no-unstable-default-props': 'off', - '@eslint-react/dom/no-missing-button-type': 'off', - 'react-hooks/exhaustive-deps': 'error', - 'react-hooks/rules-of-hooks': 'error', - }, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/solid-start-router-manifest/package.json b/packages/solid-start-router-manifest/package.json deleted file mode 100644 index 3ee031b8e0..0000000000 --- a/packages/solid-start-router-manifest/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "@tanstack/solid-start-router-manifest", - "version": "1.120.3", - "description": "Modern and scalable routing for Solid applications", - "author": "Tanner Linsley", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/TanStack/router.git", - "directory": "packages/start" - }, - "homepage": "https://tanstack.com/start", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "keywords": [ - "solid", - "location", - "router", - "routing", - "async", - "async router", - "typescript" - ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "tsc" - }, - "type": "module", - "types": "dist/esm/index.d.ts", - "exports": { - ".": { - "import": { - "types": "./dist/esm/index.d.ts", - "default": "./dist/esm/index.js" - } - }, - "./package.json": "./package.json" - }, - "sideEffects": false, - "files": [ - "dist", - "src" - ], - "engines": { - "node": ">=12" - }, - "dependencies": { - "@tanstack/router-core": "workspace:^", - "tiny-invariant": "^1.3.3", - "vinxi": "0.5.3" - }, - "devDependencies": { - "typescript": "^5.7.2" - } -} diff --git a/packages/solid-start-router-manifest/src/index.ts b/packages/solid-start-router-manifest/src/index.ts deleted file mode 100644 index 9a41e3f788..0000000000 --- a/packages/solid-start-router-manifest/src/index.ts +++ /dev/null @@ -1,83 +0,0 @@ -// @ts-expect-error -import tsrGetManifest from 'tsr:routes-manifest' -import { getManifest } from 'vinxi/manifest' -import { default as invariant } from 'tiny-invariant' -import type { Manifest } from '@tanstack/router-core' - -function sanitizeBase(base: string) { - return base.replace(/^\/|\/$/g, '') -} - -/** - * @description Returns the full, unfiltered router manifest. This includes relationships - * between routes, assets, and preloads and is NOT what you want to serialize and - * send to the client. - */ -export function getFullRouterManifest() { - const routerManifest = tsrGetManifest() as Manifest - - const rootRoute = (routerManifest.routes.__root__ = - routerManifest.routes.__root__ || {}) - - rootRoute.assets = rootRoute.assets || [] - - const script = '' - // Always fake that HMR is ready - if (process.env.NODE_ENV === 'development') { - const CLIENT_BASE = sanitizeBase(process.env.TSS_CLIENT_BASE || '') - - if (!CLIENT_BASE) { - throw new Error( - 'tanstack/solid-start-router-manifest: TSS_CLIENT_BASE must be defined in your environment for getFullRouterManifest()', - ) - } - } - - // Get the entry for the client from vinxi - const vinxiClientManifest = getManifest('client') - - const importPath = - vinxiClientManifest.inputs[vinxiClientManifest.handler]?.output.path - if (!importPath) { - invariant(importPath, 'Could not find client entry in vinxi manifest') - } - - rootRoute.assets.push({ - tag: 'script', - attrs: { - type: 'module', - suppressHydrationWarning: true, - async: true, - }, - children: `${script}import("${importPath}")`, - }) - - return routerManifest -} - -/** - * @description Returns the router manifest that should be sent to the client. - * This includes only the assets and preloads for the current route and any - * special assets that are needed for the client. It does not include relationships - * between routes or any other data that is not needed for the client. - */ -export function getRouterManifest() { - const routerManifest = getFullRouterManifest() - - // Strip out anything that isn't needed for the client - return { - ...routerManifest, - routes: Object.fromEntries( - Object.entries(routerManifest.routes).map(([k, v]: any) => { - const { preloads, assets } = v - return [ - k, - { - preloads, - assets, - }, - ] - }), - ), - } -} diff --git a/packages/solid-start-router-manifest/tsconfig.json b/packages/solid-start-router-manifest/tsconfig.json deleted file mode 100644 index 940a9cce0a..0000000000 --- a/packages/solid-start-router-manifest/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": ["src/index.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist/esm", - "target": "esnext", - "noEmit": false - } -} diff --git a/packages/solid-start-router-manifest/vite.config.ts b/packages/solid-start-router-manifest/vite.config.ts deleted file mode 100644 index d6472068fb..0000000000 --- a/packages/solid-start-router-manifest/vite.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { defineConfig, mergeConfig } from 'vitest/config' -import { tanstackViteConfig } from '@tanstack/config/vite' -import packageJson from './package.json' -import type { ViteUserConfig } from 'vitest/config' - -const config = defineConfig({ - plugins: [] as ViteUserConfig['plugins'], - test: { - name: packageJson.name, - watch: false, - environment: 'jsdom', - }, -}) - -export default mergeConfig( - config, - tanstackViteConfig({ - entry: './src/index.ts', - srcDir: './src', - externalDeps: ['tsr:routes-manifest'], - }), -) diff --git a/packages/solid-start-server/README.md b/packages/solid-start-server/README.md index fd6e98ac6d..46a245ec2d 100644 --- a/packages/solid-start-server/README.md +++ b/packages/solid-start-server/README.md @@ -1,33 +1,9 @@ -> 🤫 we're cooking up something special! - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! +# TanStack Solid Start - Server - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - +This package is not meant to be used directly. It is a dependency of [`@tanstack/solid-start`](https://www.npmjs.com/package/@tanstack/solid-start). -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) +TanStack Solid Start is a fullstack-framework made for SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router). -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! +Head over to [tanstack.com/start](https://tanstack.com/start) for more information about getting started. diff --git a/packages/solid-start-server/package.json b/packages/solid-start-server/package.json index 4aea00c279..78c3f1e528 100644 --- a/packages/solid-start-server/package.json +++ b/packages/solid-start-server/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-start-server", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for Solid applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/solid-start-server/src/index.tsx b/packages/solid-start-server/src/index.tsx index f4573955c8..b0dda10b7a 100644 --- a/packages/solid-start-server/src/index.tsx +++ b/packages/solid-start-server/src/index.tsx @@ -1,4 +1,5 @@ export { StartServer } from './StartServer' export { defaultStreamHandler } from './defaultStreamHandler' export { defaultRenderHandler } from './defaultRenderHandler' + export * from '@tanstack/start-server-core' diff --git a/packages/solid-start-server/vite.config.ts b/packages/solid-start-server/vite.config.ts index c0a7454291..79aa39295e 100644 --- a/packages/solid-start-server/vite.config.ts +++ b/packages/solid-start-server/vite.config.ts @@ -22,5 +22,10 @@ export default mergeConfig( tanstackViteConfig({ srcDir: './src', entry: './src/index.tsx', + externalDeps: [ + 'tanstack-start-server-fn-manifest:v', + 'tanstack-start-router-manifest:v', + 'tanstack-start-server-routes-manifest:v', + ], }), ) diff --git a/packages/solid-start/README.md b/packages/solid-start/README.md index 5745ba8bf0..c44c19422c 100644 --- a/packages/solid-start/README.md +++ b/packages/solid-start/README.md @@ -1,33 +1,42 @@ -> 🤫 we're cooking up something special! - -# TanStack Start +# TanStack Solid Start -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) +![TanStack Solid Start Header](https://github.com/tanstack/router/raw/main/media/header.png) -🤖 Type-safe router w/ built-in caching & URL state management for Solid! (Experimental) +SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router) and Vite. Ready to deploy to your favorite hosting provider. #TanStack - + + - - - - - - semantic-release - + + + + + + + + + semantic-release + + Join the discussion on Github -Best of JS + + + Best of JS + + - + + - + + Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! +Visit [tanstack.com/start](https://tanstack.com/start) for docs, guides, API and more! diff --git a/packages/solid-start/package.json b/packages/solid-start/package.json index 228c931c61..99f98ac929 100644 --- a/packages/solid-start/package.json +++ b/packages/solid-start/package.json @@ -1,13 +1,13 @@ { "name": "@tanstack/solid-start", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for Solid applications", "author": "Tanner Linsley", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/TanStack/router.git", - "directory": "packages/start" + "directory": "packages/solid-start" }, "homepage": "https://tanstack.com/start", "funding": { @@ -62,34 +62,14 @@ "default": "./dist/cjs/server.cjs" } }, - "./config": { + "./plugin/vite": { "import": { - "types": "./dist/esm/config.d.ts", - "default": "./dist/esm/config.js" + "types": "./dist/esm/plugin-vite.d.ts", + "default": "./dist/esm/plugin-vite.js" }, "require": { - "types": "./dist/cjs/config.d.cts", - "default": "./dist/cjs/config.cjs" - } - }, - "./api": { - "import": { - "types": "./dist/esm/api.d.ts", - "default": "./dist/esm/api.js" - }, - "require": { - "types": "./dist/cjs/api.d.cts", - "default": "./dist/cjs/api.cjs" - } - }, - "./router-manifest": { - "import": { - "types": "./dist/esm/router-manifest.d.ts", - "default": "./dist/esm/router-manifest.js" - }, - "require": { - "types": "./dist/cjs/router-manifest.d.cts", - "default": "./dist/cjs/router-manifest.cjs" + "types": "./dist/cjs/plugin-vite.d.cts", + "default": "./dist/cjs/plugin-vite.cjs" } }, "./server-functions-client": { @@ -112,26 +92,6 @@ "default": "./dist/cjs/server-functions-server.cjs" } }, - "./server-functions-handler": { - "import": { - "types": "./dist/esm/server-functions-handler.d.ts", - "default": "./dist/esm/server-functions-handler.js" - }, - "require": { - "types": "./dist/cjs/server-functions-handler.d.cts", - "default": "./dist/cjs/server-functions-handler.cjs" - } - }, - "./server-functions-ssr": { - "import": { - "types": "./dist/esm/server-functions-ssr.d.ts", - "default": "./dist/esm/server-functions-ssr.js" - }, - "require": { - "types": "./dist/cjs/server-functions-ssr.d.cts", - "default": "./dist/cjs/server-functions-ssr.cjs" - } - }, "./package.json": "./package.json" }, "sideEffects": false, @@ -145,17 +105,14 @@ "dependencies": { "@tanstack/solid-start-client": "workspace:^", "@tanstack/solid-start-server": "workspace:^", - "@tanstack/solid-start-config": "workspace:^", - "@tanstack/solid-start-router-manifest": "workspace:^", + "@tanstack/solid-start-plugin": "workspace:^", "@tanstack/start-server-functions-client": "workspace:^", - "@tanstack/start-server-functions-server": "workspace:^", - "@tanstack/start-server-functions-handler": "workspace:^", - "@tanstack/start-server-functions-ssr": "workspace:^", - "@tanstack/start-api-routes": "workspace:^" + "@tanstack/start-server-functions-server": "workspace:^" }, "peerDependencies": { "solid-js": ">=1.0.0", - "vite": "^6.0.0" + "vite": ">=6.0.0", + "vite-plugin-solid": ">=2.11.6" }, "devDependencies": { "esbuild": "^0.25.0" diff --git a/packages/solid-start/src/api.tsx b/packages/solid-start/src/api.tsx deleted file mode 100644 index fff3bec5ea..0000000000 --- a/packages/solid-start/src/api.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/start-api-routes' diff --git a/packages/solid-start/src/config.tsx b/packages/solid-start/src/config.tsx deleted file mode 100644 index 5a71360c3a..0000000000 --- a/packages/solid-start/src/config.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/solid-start-config' diff --git a/packages/solid-start/src/plugin-vite.ts b/packages/solid-start/src/plugin-vite.ts new file mode 100644 index 0000000000..24c76d5516 --- /dev/null +++ b/packages/solid-start/src/plugin-vite.ts @@ -0,0 +1 @@ +export * from '@tanstack/solid-start-plugin' diff --git a/packages/solid-start/src/router-manifest.tsx b/packages/solid-start/src/router-manifest.tsx deleted file mode 100644 index 4e939be275..0000000000 --- a/packages/solid-start/src/router-manifest.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/solid-start-router-manifest' diff --git a/packages/solid-start/src/server-functions-handler.tsx b/packages/solid-start/src/server-functions-handler.tsx deleted file mode 100644 index c3cc9770d2..0000000000 --- a/packages/solid-start/src/server-functions-handler.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/start-server-functions-handler' diff --git a/packages/solid-start/src/server-functions-ssr.tsx b/packages/solid-start/src/server-functions-ssr.tsx deleted file mode 100644 index 7359e26f45..0000000000 --- a/packages/solid-start/src/server-functions-ssr.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/start-server-functions-ssr' diff --git a/packages/solid-start/vite.config.ts b/packages/solid-start/vite.config.ts index dfcd5b4b41..8557385ded 100644 --- a/packages/solid-start/vite.config.ts +++ b/packages/solid-start/vite.config.ts @@ -17,22 +17,16 @@ export default mergeConfig( entry: [ './src/client.tsx', './src/server.tsx', - './src/config.tsx', - './src/router-manifest.tsx', + './src/plugin-vite.ts', './src/server-functions-client.tsx', './src/server-functions-server.tsx', - './src/server-functions-ssr.tsx', - './src/api.tsx', ], externalDeps: [ '@tanstack/solid-start-client', '@tanstack/solid-start-server', - '@tanstack/solid-start-config', - '@tanstack/solid-start-router-manifest', + '@tanstack/solid-start-plugin', '@tanstack/start-server-functions-client', '@tanstack/start-server-functions-server', - '@tanstack/start-server-functions-ssr', - '@tanstack/start-api-routes', ], }), ) diff --git a/packages/start-api-routes/README.md b/packages/start-api-routes/README.md deleted file mode 100644 index bb009b0c87..0000000000 --- a/packages/start-api-routes/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/start-api-routes/eslint.config.js b/packages/start-api-routes/eslint.config.js deleted file mode 100644 index 931f0ec774..0000000000 --- a/packages/start-api-routes/eslint.config.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check - -import pluginReact from '@eslint-react/eslint-plugin' -import pluginReactHooks from 'eslint-plugin-react-hooks' -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - ...pluginReact.configs.recommended, - files: ['**/*.{ts,tsx}'], - }, - { - plugins: { - 'react-hooks': pluginReactHooks, - }, - rules: { - '@eslint-react/no-unstable-context-value': 'off', - '@eslint-react/no-unstable-default-props': 'off', - '@eslint-react/dom/no-missing-button-type': 'off', - 'react-hooks/exhaustive-deps': 'error', - 'react-hooks/rules-of-hooks': 'error', - }, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/start-api-routes/src/index.ts b/packages/start-api-routes/src/index.ts deleted file mode 100644 index dbfba63cce..0000000000 --- a/packages/start-api-routes/src/index.ts +++ /dev/null @@ -1,369 +0,0 @@ -import { eventHandler, toWebRequest } from '@tanstack/start-server-core' -import vinxiFileRoutes from 'vinxi/routes' -import type { ResolveParams } from '@tanstack/router-core' - -export type StartAPIHandlerCallback = (ctx: { - request: Request -}) => Response | Promise - -export type StartAPIMethodCallback = (ctx: { - request: Request - params: ResolveParams -}) => Response | Promise - -const HTTP_API_METHODS = [ - 'GET', - 'POST', - 'PUT', - 'PATCH', - 'DELETE', - 'OPTIONS', - 'HEAD', -] as const -export type HTTP_API_METHOD = (typeof HTTP_API_METHODS)[number] - -/** - * - * @param cb The callback function that will be called when the API handler is invoked - * @returns The response from the callback function - */ -export function createStartAPIHandler(cb: StartAPIHandlerCallback) { - return eventHandler(async (event) => { - const request = toWebRequest(event)! - const res = await cb({ request }) - return res - }) -} - -type APIRoute = { - path: TPath - methods: Partial>> -} - -type CreateAPIRouteFn = ( - methods: Partial>>, -) => APIRoute - -type CreateAPIRoute = ( - path: TPath, -) => CreateAPIRouteFn - -type APIRouteReturnType = ReturnType> - -/** - * This function is used to create an API route that will be listening on a specific path when you are not using the file-based routes. - * - * @param path The path that the API route will be listening on. You need to make sure that this is a valid TanStack Router path in order for the route to be matched. This means that you can use the following syntax: - * /api/foo/$bar/name/$ - * - The `$bar` is a parameter that will be extracted from the URL and passed to the handler - * - The `$` is a wildcard that will match any number of segments in the URL - * @returns A function that takes the methods that the route will be listening on and returns the API route object - */ -export const createAPIRoute: CreateAPIRoute = (path) => (methods) => ({ - path, - methods, -}) - -/** - * This function is used to create an API route that will be listening on a specific path when you are using the file-based routes. - * - * @param filePath The path that the API file route will be listening on. This filePath should automatically be generated by the TSR plugin and should be a valid TanStack Router path - * @returns A function that takes the methods that the route will be listening on and returns the API route object - */ -export const createAPIFileRoute: CreateAPIRoute = (filePath) => (methods) => ({ - path: filePath, - methods, -}) - -/** - * This function takes a URL object and a list of routes and finds the route that matches the URL. - * - * @param url URL object - * @param entryRoutes List of routes entries in the TSR format to find the current match by the URL - * @returns Returns the route that matches the URL or undefined if no route matches - */ -function findRoute( - url: URL, - entryRoutes: Array<{ routePath: string; payload: TPayload }>, -): - | { - routePath: string - params: Record - payload: TPayload - } - | undefined { - const urlSegments = url.pathname.split('/').filter(Boolean) - - const routes = entryRoutes - .sort((a, b) => { - const aParts = a.routePath.split('/').filter(Boolean) - const bParts = b.routePath.split('/').filter(Boolean) - - return bParts.length - aParts.length - }) - .filter((r) => { - const routeSegments = r.routePath.split('/').filter(Boolean) - return urlSegments.length >= routeSegments.length - }) - - for (const route of routes) { - const routeSegments = route.routePath.split('/').filter(Boolean) - const params: Record = {} - let matches = true - for (let i = 0; i < routeSegments.length; i++) { - const routeSegment = routeSegments[i] as string - const urlSegment = urlSegments[i] as string - if (routeSegment.startsWith('$')) { - if (routeSegment === '$') { - const wildcardValue = urlSegments.slice(i).join('/') - if (wildcardValue !== '') { - params['*'] = wildcardValue - params['_splat'] = wildcardValue - } else { - matches = false - break - } - } else { - const paramName = routeSegment.slice(1) - params[paramName] = urlSegment - } - } else if (routeSegment !== urlSegment) { - matches = false - break - } - } - if (matches) { - return { routePath: route.routePath, params, payload: route.payload } - } - } - - return undefined -} - -/** - * You should only be using this function if you are not using the file-based routes. - * - * - * @param opts - A map of TSR routes with the values being the route handlers - * @returns The handler for the incoming request - * - * @example - * ```ts - * // app/foo.ts - * import { createAPIRoute } from '@tanstack/start-api-routes' - * const fooBarRoute = createAPIRoute('/api/foo/$bar')({ - * GET: ({ params }) => { - * return new Response(JSON.stringify({ params })) - * } - * }) - * - * // app/api.ts - * import { - * createStartAPIHandler, - * defaultAPIRoutesHandler - * } from '@tanstack/start-api-routes' - * - * export default createStartAPIHandler( - * defaultAPIRoutesHandler({ - * '/api/foo/$bar': fooBarRoute - * }) - * ) - * ``` - */ -export const defaultAPIRoutesHandler: (opts: { - routes: { [TPath in string]: APIRoute } -}) => StartAPIHandlerCallback = (opts) => { - return async ({ request }) => { - if (!HTTP_API_METHODS.includes(request.method as HTTP_API_METHOD)) { - return new Response('Method not allowed', { status: 405 }) - } - - const url = new URL(request.url, 'http://localhost:3000') - - const routes = Object.entries(opts.routes).map(([routePath, route]) => ({ - routePath, - payload: route, - })) - - // Find the route that matches the request by the request URL - const match = findRoute(url, routes) - - // If we don't have a route that could possibly handle the request, return a 404 - if (!match) { - return new Response('Not found', { status: 404 }) - } - - // If the route path doesn't match the payload path, return a 404 - if (match.routePath !== match.payload.path) { - console.error( - `Route path mismatch: ${match.routePath} !== ${match.payload.path}. Please make sure that the route path in \`createAPIRoute\` matches the path in the handler map in \`defaultAPIRoutesHandler\``, - ) - return new Response('Not found', { status: 404 }) - } - - const method = request.method as HTTP_API_METHOD - - // Get the handler for the request method based on the Request Method - const handler = match.payload.methods[method] - - // If the handler is not defined, return a 405 - if (!handler) { - return new Response('Method not allowed', { status: 405 }) - } - - return await handler({ request, params: match.params }) - } -} - -interface CustomizedVinxiFileRoute { - path: string // this path adheres to the h3 router path format - filePath: string // this is the file path on the system - $APIRoute?: { - src: string // this is the path to the source file - import: () => Promise<{ - APIRoute: APIRouteReturnType - }> - } -} - -/** - * This is populated by the work done in the config file using the tsrFileRouter - */ -const vinxiRoutes = ( - vinxiFileRoutes as unknown as Array -).filter((route) => route['$APIRoute']) - -/** - * This function takes the vinxi routes and interpolates them into a format that can be worked with in the API handler - * - * @param routes The vinxi routes that have been filtered to only include those with a $APIRoute property - * @returns An array of objects where the path `key` is interpolated to a valid TanStack Router path, with the `payload` being the original route object - * - * @example - * ``` - * const input = [ - * { - * path: '/api/boo/:$id?/name/*splat', - * filePath: '..../code/tanstack/router/examples/react/start-basic/app/routes/api.boo.$id.name.$.tsx', - * '$APIRoute': [Object] - * } - * ] - * - * toTSRFileBasedRoutes(input) - * [ - * { - * path: '/api/boo/$id/name/$', - * route: { - * path: '/api/boo/:$id?/name/*splat', - * filePath: '..../code/tanstack/router/examples/react/start-basic/app/routes/api.boo.$id.name.$.tsx', - * '$APIRoute': [Object] - * } - * } - * ] - * ``` - */ -function toTSRFileBasedRoutes( - routes: Array, -): Array<{ routePath: string; payload: CustomizedVinxiFileRoute }> { - const pairs: Array<{ - routePath: string - payload: CustomizedVinxiFileRoute - }> = [] - - routes.forEach((route) => { - const parts = route.path.split('/').filter(Boolean) - - const path = parts - .map((part) => { - if (part === '*splat') { - return '$' - } - - if (part.startsWith(':$') && part.endsWith('?')) { - return part.slice(1, -1) - } - - return part - }) - .join('/') - - pairs.push({ routePath: `/${path}`, payload: route }) - }) - - return pairs -} - -/** - * This function is the default handler for the API routes when using file-based routes. - * - * @param StartAPIHandlerCallbackContext - * @returns The handler for the incoming request - * - * @example - * ```ts - * // app/api.ts - * import { - * createStartAPIHandler, - * defaultAPIFileRouteHandler - * } from '@tanstack/start-api-routes' - * - * export default createStartAPIHandler(defaultAPIFileRouteHandler) - * ``` - */ -export const defaultAPIFileRouteHandler: StartAPIHandlerCallback = async ({ - request, -}) => { - // Simple early abort if there are no routes - if (!vinxiRoutes.length) { - return new Response('No routes found', { status: 404 }) - } - - if (!HTTP_API_METHODS.includes(request.method as HTTP_API_METHOD)) { - return new Response('Method not allowed', { status: 405 }) - } - - const routes = toTSRFileBasedRoutes(vinxiRoutes) - - const url = new URL(request.url, 'http://localhost:3000') - - // Find the route that file that matches the request by the request URL - const match = findRoute(url, routes) - - // If we don't have a route that could possibly handle the request, return a 404 - if (!match) { - return new Response('Not found', { status: 404 }) - } - - // The action is the route file that we need to import - // which contains the possible handlers for the incoming request - let action: APIRouteReturnType | undefined = undefined - - try { - // We can guarantee that action is defined since we filtered for it earlier - action = await match.payload.$APIRoute!.import().then((m) => m.APIRoute) - } catch (err) { - // If we can't import the route file, return a 500 - console.error('Error importing route file:', err) - return new Response('Internal server error', { status: 500 }) - } - - // If we don't have an action, return a 500 - if (!action) { - return new Response('Internal server error', { status: 500 }) - } - - const method = request.method as HTTP_API_METHOD - - // Get the handler for the request method based on the Request Method - const handler = action.methods[method] - - // If the handler is not defined, return a 405 - // What this means is that we have a route that matches the request - // but we don't have a handler for the request method - // i.e we have a route that matches /api/foo/$ but we don't have a POST handler - if (!handler) { - return new Response('Method not allowed', { status: 405 }) - } - - return await handler({ request, params: match.params }) -} diff --git a/packages/start-api-routes/tsconfig.json b/packages/start-api-routes/tsconfig.json deleted file mode 100644 index 51dda9abf2..0000000000 --- a/packages/start-api-routes/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "jsx": "react-jsx", - "module": "esnext" - }, - "include": ["src", "vite.config.ts"] -} diff --git a/packages/start-api-routes/vite.config.ts b/packages/start-api-routes/vite.config.ts deleted file mode 100644 index 976bb5c87f..0000000000 --- a/packages/start-api-routes/vite.config.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { defineConfig, mergeConfig } from 'vitest/config' -import { tanstackViteConfig } from '@tanstack/config/vite' -import packageJson from './package.json' -import type { ViteUserConfig } from 'vitest/config' - -const config = defineConfig({ - plugins: [] as ViteUserConfig['plugins'], - test: { - name: packageJson.name, - watch: false, - environment: 'jsdom', - }, -}) - -export default mergeConfig( - config, - tanstackViteConfig({ - entry: './src/index.ts', - srcDir: './src', - }), -) diff --git a/packages/start-client-core/README.md b/packages/start-client-core/README.md index fd6e98ac6d..6c9085433a 100644 --- a/packages/start-client-core/README.md +++ b/packages/start-client-core/README.md @@ -1,33 +1,12 @@ -> 🤫 we're cooking up something special! - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) +# TanStack Start - Client Core -🤖 Type-safe router w/ built-in caching & URL state management for React! +This package is not meant to be used directly. It is a dependency of the TanStack Start framework-specific packages: - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - +- [`@tanstack/react-start`](https://www.npmjs.com/package/@tanstack/react-start) +- [`@tanstack/solid-start`](https://www.npmjs.com/package/@tanstack/solid-start). -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) +It provides the core functionality for TanStack Start, which is a fullstack-framework made for SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router). -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! +Head over to [tanstack.com/start](https://tanstack.com/start) for more information about getting started. diff --git a/packages/start-client-core/package.json b/packages/start-client-core/package.json index e4ce1dbd0d..195dc61f68 100644 --- a/packages/start-client-core/package.json +++ b/packages/start-client-core/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/start-client-core", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/start-client-core/src/createMiddleware.ts b/packages/start-client-core/src/createMiddleware.ts index 654fe78271..357adea2f2 100644 --- a/packages/start-client-core/src/createMiddleware.ts +++ b/packages/start-client-core/src/createMiddleware.ts @@ -14,21 +14,225 @@ import type { SerializerStringify, } from '@tanstack/router-core' -export type AssignAllMiddleware< +export function createMiddleware( + options: { + type: TType + validateClient?: boolean + }, + __opts?: FunctionMiddlewareOptions< + unknown, + undefined, + undefined, + undefined, + ServerFnResponseType + >, +): CreateMiddlewareResult { + // const resolvedOptions = (__opts || options) as MiddlewareOptions< + const resolvedOptions = { + type: 'function', + ...(__opts || + (options as FunctionMiddlewareOptions< + unknown, + undefined, + undefined, + undefined, + ServerFnResponseType + >)), + } + + return { + options: resolvedOptions, + middleware: (middleware: any) => { + return createMiddleware( + {} as any, + Object.assign(resolvedOptions, { middleware }), + ) as any + }, + validator: (validator: any) => { + return createMiddleware( + {} as any, + Object.assign(resolvedOptions, { validator }), + ) as any + }, + client: (client: any) => { + return createMiddleware( + {} as any, + Object.assign(resolvedOptions, { client }), + ) as any + }, + server: (server: any) => { + return createMiddleware( + {} as any, + Object.assign(resolvedOptions, { server }), + ) as any + }, + } as unknown as CreateMiddlewareResult +} + +export type MiddlewareType = 'request' | 'function' + +export type CreateMiddlewareResult = + 'function' extends TType + ? FunctionMiddleware + : RequestMiddleware + +export interface FunctionMiddleware< + TServerFnResponseType extends ServerFnResponseType, +> extends FunctionMiddlewareAfterMiddleware { + middleware: ( + middlewares: Constrain< + TNewMiddlewares, + ReadonlyArray + >, + ) => FunctionMiddlewareAfterMiddleware +} + +export interface FunctionMiddlewareAfterMiddleware< + TMiddlewares, + TServerFnResponseType extends ServerFnResponseType, +> extends FunctionMiddlewareWithTypes< + TMiddlewares, + undefined, + undefined, + undefined, + undefined, + undefined, + TServerFnResponseType + >, + FunctionMiddlewareServer< + TMiddlewares, + undefined, + undefined, + undefined, + TServerFnResponseType + >, + FunctionMiddlewareClient, + FunctionMiddlewareValidator {} + +export interface FunctionMiddlewareWithTypes< + TMiddlewares, + TValidator, + TServerContext, + TServerSendContext, + TClientContext, + TClientSendContext, + TServerFnResponseType extends ServerFnResponseType, +> { + _types: FunctionMiddlewareTypes< + TMiddlewares, + TValidator, + TServerContext, + TServerSendContext, + TClientContext, + TClientSendContext + > + options: FunctionMiddlewareOptions< + TMiddlewares, + TValidator, + TServerContext, + TClientContext, + TServerFnResponseType + > +} + +export interface FunctionMiddlewareTypes< + in out TMiddlewares, + in out TValidator, + in out TServerContext, + in out TServerSendContext, + in out TClientContext, + in out TClientSendContext, +> { + type: 'function' + middlewares: TMiddlewares + input: ResolveValidatorInput + allInput: IntersectAllValidatorInputs + output: ResolveValidatorOutput + allOutput: IntersectAllValidatorOutputs + clientContext: TClientContext + allClientContextBeforeNext: AssignAllClientContextBeforeNext< + TMiddlewares, + TClientContext + > + allClientContextAfterNext: AssignAllClientContextAfterNext< + TMiddlewares, + TClientContext, + TClientSendContext + > + serverContext: TServerContext + serverSendContext: TServerSendContext + allServerSendContext: AssignAllServerSendContext< + TMiddlewares, + TServerSendContext + > + allServerContext: AssignAllServerContext< + TMiddlewares, + TServerSendContext, + TServerContext + > + clientSendContext: TClientSendContext + allClientSendContext: AssignAllClientSendContext< + TMiddlewares, + TClientSendContext + > + validator: TValidator +} + +/** + * Recursively resolve the input type produced by a sequence of middleware + */ +export type IntersectAllValidatorInputs = + unknown extends TValidator + ? TValidator + : TValidator extends undefined + ? IntersectAllMiddleware + : IntersectAssign< + IntersectAllMiddleware, + ResolveValidatorInput + > + +export type IntersectAllMiddleware< TMiddlewares, - TType extends keyof AnyMiddleware['_types'], + TType extends + | keyof AnyFunctionMiddleware['_types'] + | keyof AnyRequestMiddleware['_types'], TAcc = undefined, -> = TMiddlewares extends readonly [ - infer TMiddleware extends AnyMiddleware, - ...infer TRest, -] - ? AssignAllMiddleware< - TRest, - TType, - Assign - > +> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest] + ? TMiddleware extends AnyFunctionMiddleware | AnyRequestMiddleware + ? IntersectAllMiddleware< + TRest, + TType, + IntersectAssign< + TAcc, + TMiddleware['_types'][TType & keyof TMiddleware['_types']] + > + > + : TAcc : TAcc +export type AnyFunctionMiddleware = FunctionMiddlewareWithTypes< + any, + any, + any, + any, + any, + any, + any +> + +/** + * Recursively merge the output type produced by a sequence of middleware + */ +export type IntersectAllValidatorOutputs = + unknown extends TValidator + ? TValidator + : TValidator extends undefined + ? IntersectAllMiddleware + : IntersectAssign< + IntersectAllMiddleware, + ResolveValidatorOutput + > + /** * Recursively resolve the client context type produced by a sequence of middleware */ @@ -42,15 +246,21 @@ export type AssignAllClientContextBeforeNext< TClientContext > -export type AssignAllClientSendContext< +export type AssignAllMiddleware< TMiddlewares, - TSendContext = undefined, -> = unknown extends TSendContext - ? TSendContext - : Assign< - AssignAllMiddleware, - TSendContext - > + TType extends + | keyof AnyFunctionMiddleware['_types'] + | keyof AnyRequestMiddleware['_types'], + TAcc = undefined, +> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest] + ? TMiddleware extends AnyFunctionMiddleware | AnyRequestMiddleware + ? AssignAllMiddleware< + TRest, + TType, + Assign + > + : TAcc + : TAcc export type AssignAllClientContextAfterNext< TMiddlewares, @@ -63,6 +273,16 @@ export type AssignAllClientContextAfterNext< Assign > +export type AssignAllServerSendContext< + TMiddlewares, + TSendContext = undefined, +> = unknown extends TSendContext + ? TSendContext + : Assign< + AssignAllMiddleware, + TSendContext + > + /** * Recursively resolve the server context type produced by a sequence of middleware */ @@ -77,57 +297,17 @@ export type AssignAllServerContext< Assign > -export type AssignAllServerSendContext< +export type AssignAllClientSendContext< TMiddlewares, TSendContext = undefined, > = unknown extends TSendContext ? TSendContext : Assign< - AssignAllMiddleware, + AssignAllMiddleware, TSendContext > -export type IntersectAllMiddleware< - TMiddlewares, - TType extends keyof AnyMiddleware['_types'], - TAcc = undefined, -> = TMiddlewares extends readonly [ - infer TMiddleware extends AnyMiddleware, - ...infer TRest, -] - ? IntersectAllMiddleware< - TRest, - TType, - IntersectAssign - > - : TAcc - -/** - * Recursively resolve the input type produced by a sequence of middleware - */ -export type IntersectAllValidatorInputs = - unknown extends TValidator - ? TValidator - : IntersectAssign< - IntersectAllMiddleware, - TValidator extends undefined - ? undefined - : ResolveValidatorInput - > -/** - * Recursively merge the output type produced by a sequence of middleware - */ -export type IntersectAllValidatorOutputs = - unknown extends TValidator - ? TValidator - : IntersectAssign< - IntersectAllMiddleware, - TValidator extends undefined - ? undefined - : ResolveValidatorOutput - > - -export interface MiddlewareOptions< +export interface FunctionMiddlewareOptions< in out TMiddlewares, in out TValidator, in out TServerContext, @@ -137,14 +317,14 @@ export interface MiddlewareOptions< validateClient?: boolean middleware?: TMiddlewares validator?: ConstrainValidator - client?: MiddlewareClientFn< + client?: FunctionMiddlewareClientFn< TMiddlewares, TValidator, TServerContext, TClientContext, TServerFnResponseType > - server?: MiddlewareServerFn< + server?: FunctionMiddlewareServerFn< TMiddlewares, TValidator, TServerContext, @@ -154,38 +334,44 @@ export interface MiddlewareOptions< > } -export type MiddlewareServerNextFn = < - TNewServerContext = undefined, +export type FunctionMiddlewareClientNextFn = < TSendContext = undefined, + TNewClientContext = undefined, >(ctx?: { - context?: TNewServerContext + context?: TNewClientContext sendContext?: SerializerStringify + headers?: HeadersInit }) => Promise< - ServerResultWithContext< - TMiddlewares, - TServerSendContext, - TNewServerContext, - TSendContext - > + FunctionClientResultWithContext > -export interface MiddlewareServerFnOptions< - in out TMiddlewares, - in out TValidator, - in out TServerSendContext, - in out TServerFnResponseType, +export interface FunctionMiddlewareServer< + TMiddlewares, + TValidator, + TServerSendContext, + TClientContext, + TServerFnResponseType extends ServerFnResponseType, > { - data: Expand> - context: Expand> - next: MiddlewareServerNextFn - response: TServerFnResponseType - method: Method - filename: string - functionId: string - signal: AbortSignal + server: ( + server: FunctionMiddlewareServerFn< + TMiddlewares, + TValidator, + TServerSendContext, + TNewServerContext, + TSendContext, + TServerFnResponseType + >, + ) => FunctionMiddlewareAfterServer< + TMiddlewares, + TValidator, + TNewServerContext, + TServerSendContext, + TClientContext, + TSendContext, + ServerFnResponseType + > } - -export type MiddlewareServerFn< +export type FunctionMiddlewareServerFn< TMiddlewares, TValidator, TServerSendContext, @@ -193,96 +379,47 @@ export type MiddlewareServerFn< TSendContext, TServerFnResponseType extends ServerFnResponseType, > = ( - options: MiddlewareServerFnOptions< + options: FunctionMiddlewareServerFnOptions< TMiddlewares, TValidator, TServerSendContext, TServerFnResponseType >, -) => MiddlewareServerFnResult< +) => FunctionMiddlewareServerFnResult< TMiddlewares, TServerSendContext, TNewServerContext, TSendContext > -export type MiddlewareServerFnResult< - TMiddlewares, - TServerSendContext, - TServerContext, - TSendContext, -> = - | Promise< - ServerResultWithContext< - TMiddlewares, - TServerSendContext, - TServerContext, - TSendContext - > - > - | ServerResultWithContext< - TMiddlewares, - TServerSendContext, - TServerContext, - TSendContext - > - -export type MiddlewareClientNextFn = < - TSendContext = undefined, - TNewClientContext = undefined, ->(ctx?: { - context?: TNewClientContext - sendContext?: SerializerStringify - headers?: HeadersInit -}) => Promise< - ClientResultWithContext -> - -export interface MiddlewareClientFnOptions< +export interface RequestMiddlewareServerFnOptions< in out TMiddlewares, - in out TValidator, - in out TServerFnResponseType extends ServerFnResponseType, + in out TServerSendContext, > { - data: Expand> - context: Expand> - sendContext: Expand> + request: Request + context: Expand> + next: FunctionMiddlewareServerNextFn + response: Response method: Method - response: TServerFnResponseType signal: AbortSignal - next: MiddlewareClientNextFn - filename: string - functionId: string - type: ServerFnTypeOrTypeFn< - Method, - TServerFnResponseType, - TMiddlewares, - TValidator - > } -export type MiddlewareClientFn< - TMiddlewares, - TValidator, - TSendContext, - TClientContext, - TServerFnResponseType extends ServerFnResponseType, -> = ( - options: MiddlewareClientFnOptions< +export type FunctionMiddlewareServerNextFn = < + TNewServerContext = undefined, + TSendContext = undefined, +>(ctx?: { + context?: TNewServerContext + sendContext?: SerializerStringify +}) => Promise< + FunctionServerResultWithContext< TMiddlewares, - TValidator, - TServerFnResponseType - >, -) => MiddlewareClientFnResult - -export type MiddlewareClientFnResult< - TMiddlewares, - TSendContext, - TClientContext, -> = - | Promise> - | ClientResultWithContext + TServerSendContext, + TNewServerContext, + TSendContext + > +> -export type ServerResultWithContext< +export type FunctionServerResultWithContext< in out TMiddlewares, in out TServerSendContext, in out TServerContext, @@ -299,70 +436,44 @@ export type ServerResultWithContext< sendContext: Expand> } -export type ClientResultWithContext< - in out TMiddlewares, - in out TSendContext, - in out TClientContext, -> = { - 'use functions must return the result of next()': true - context: Expand> - sendContext: Expand> - headers: HeadersInit -} - -export type AnyMiddleware = MiddlewareWithTypes< - any, - any, - any, - any, - any, - any, - any -> - -export interface MiddlewareTypes< +export interface FunctionMiddlewareServerFnOptions< in out TMiddlewares, in out TValidator, - in out TServerContext, in out TServerSendContext, - in out TClientContext, - in out TClientSendContext, + in out TServerFnResponseType, > { - middlewares: TMiddlewares - input: ResolveValidatorInput - allInput: IntersectAllValidatorInputs - output: ResolveValidatorOutput - allOutput: IntersectAllValidatorOutputs - clientContext: TClientContext - allClientContextBeforeNext: AssignAllClientContextBeforeNext< - TMiddlewares, - TClientContext - > - allClientContextAfterNext: AssignAllClientContextAfterNext< - TMiddlewares, - TClientContext, - TClientSendContext - > - serverContext: TServerContext - serverSendContext: TServerSendContext - allServerSendContext: AssignAllServerSendContext< - TMiddlewares, - TServerSendContext - > - allServerContext: AssignAllServerContext< - TMiddlewares, - TServerSendContext, - TServerContext - > - clientSendContext: TClientSendContext - allClientSendContext: AssignAllClientSendContext< - TMiddlewares, - TClientSendContext - > - validator: TValidator + data: Expand> + context: Expand> + next: FunctionMiddlewareServerNextFn + response: TServerFnResponseType + method: Method + filename: string + functionId: string + signal: AbortSignal } -export interface MiddlewareWithTypes< +export type FunctionMiddlewareServerFnResult< + TMiddlewares, + TServerSendContext, + TServerContext, + TSendContext, +> = + | Promise< + FunctionServerResultWithContext< + TMiddlewares, + TServerSendContext, + TServerContext, + TSendContext + > + > + | FunctionServerResultWithContext< + TMiddlewares, + TServerSendContext, + TServerContext, + TSendContext + > + +export interface FunctionMiddlewareAfterServer< TMiddlewares, TValidator, TServerContext, @@ -370,111 +481,110 @@ export interface MiddlewareWithTypes< TClientContext, TClientSendContext, TServerFnResponseType extends ServerFnResponseType, -> { - _types: MiddlewareTypes< +> extends FunctionMiddlewareWithTypes< TMiddlewares, TValidator, TServerContext, TServerSendContext, TClientContext, - TClientSendContext - > - options: MiddlewareOptions< - TMiddlewares, - TValidator, - TServerContext, - TClientContext, + TClientSendContext, TServerFnResponseType - > -} + > {} -export interface MiddlewareAfterValidator< +export interface FunctionMiddlewareClient< TMiddlewares, TValidator, TServerFnResponseType extends ServerFnResponseType, -> extends MiddlewareWithTypes< - TMiddlewares, - TValidator, - undefined, - undefined, - undefined, - undefined, - ServerFnResponseType - >, - MiddlewareServer< +> { + client: ( + client: FunctionMiddlewareClientFn< TMiddlewares, TValidator, - undefined, - undefined, + TSendServerContext, + TNewClientContext, TServerFnResponseType >, - MiddlewareClient {} - -export interface MiddlewareValidator< - TMiddlewares, - TServerFnResponseType extends ServerFnResponseType, -> { - validator: ( - input: ConstrainValidator, - ) => MiddlewareAfterValidator< + ) => FunctionMiddlewareAfterClient< TMiddlewares, - TNewValidator, - TServerFnResponseType + TValidator, + TSendServerContext, + TNewClientContext, + ServerFnResponseType > } -export interface MiddlewareAfterServer< +export type FunctionMiddlewareClientFn< TMiddlewares, TValidator, - TServerContext, - TServerSendContext, + TSendContext, TClientContext, - TClientSendContext, TServerFnResponseType extends ServerFnResponseType, -> extends MiddlewareWithTypes< +> = ( + options: FunctionMiddlewareClientFnOptions< TMiddlewares, TValidator, - TServerContext, - TServerSendContext, - TClientContext, - TClientSendContext, TServerFnResponseType - > {} - -export interface MiddlewareServer< + >, +) => FunctionMiddlewareClientFnResult< TMiddlewares, - TValidator, - TServerSendContext, - TClientContext, - TServerFnResponseType extends ServerFnResponseType, + TSendContext, + TClientContext +> + +export interface FunctionMiddlewareClientFnOptions< + in out TMiddlewares, + in out TValidator, + in out TServerFnResponseType extends ServerFnResponseType, > { - server: ( - server: MiddlewareServerFn< - TMiddlewares, - TValidator, - TServerSendContext, - TNewServerContext, - TSendContext, - TServerFnResponseType - >, - ) => MiddlewareAfterServer< + data: Expand> + context: Expand> + sendContext: Expand> + method: Method + response: TServerFnResponseType + signal: AbortSignal + next: FunctionMiddlewareClientNextFn + filename: string + functionId: string + type: ServerFnTypeOrTypeFn< + Method, + TServerFnResponseType, TMiddlewares, - TValidator, - TNewServerContext, - TServerSendContext, - TClientContext, - TSendContext, - ServerFnResponseType + TValidator > } -export interface MiddlewareAfterClient< +export type FunctionMiddlewareClientFnResult< + TMiddlewares, + TSendContext, + TClientContext, +> = + | Promise< + FunctionClientResultWithContext< + TMiddlewares, + TSendContext, + TClientContext + > + > + | FunctionClientResultWithContext + +export type FunctionClientResultWithContext< + in out TMiddlewares, + in out TSendContext, + in out TClientContext, +> = { + 'use functions must return the result of next()': true + context: Expand> + sendContext: Expand> + headers: HeadersInit +} + +export interface FunctionMiddlewareAfterClient< TMiddlewares, TValidator, TServerSendContext, TClientContext, TServerFnResponseType extends ServerFnResponseType, -> extends MiddlewareWithTypes< +> extends FunctionMiddlewareWithTypes< TMiddlewares, TValidator, undefined, @@ -483,7 +593,7 @@ export interface MiddlewareAfterClient< undefined, TServerFnResponseType >, - MiddlewareServer< + FunctionMiddlewareServer< TMiddlewares, TValidator, TServerSendContext, @@ -491,105 +601,106 @@ export interface MiddlewareAfterClient< TServerFnResponseType > {} -export interface MiddlewareClient< +export interface FunctionMiddlewareValidator< TMiddlewares, - TValidator, TServerFnResponseType extends ServerFnResponseType, > { - client: ( - client: MiddlewareClientFn< - TMiddlewares, - TValidator, - TSendServerContext, - TNewClientContext, - TServerFnResponseType - >, - ) => MiddlewareAfterClient< + validator: ( + input: ConstrainValidator, + ) => FunctionMiddlewareAfterValidator< TMiddlewares, - TValidator, - TSendServerContext, - TNewClientContext, - ServerFnResponseType + TNewValidator, + TServerFnResponseType > } -export interface MiddlewareAfterMiddleware< +export interface FunctionMiddlewareAfterValidator< TMiddlewares, + TValidator, TServerFnResponseType extends ServerFnResponseType, -> extends MiddlewareWithTypes< +> extends FunctionMiddlewareWithTypes< TMiddlewares, + TValidator, undefined, undefined, undefined, undefined, - undefined, - TServerFnResponseType + ServerFnResponseType >, - MiddlewareServer< + FunctionMiddlewareServer< TMiddlewares, - undefined, + TValidator, undefined, undefined, TServerFnResponseType >, - MiddlewareClient, - MiddlewareValidator {} + FunctionMiddlewareClient {} -export interface Middleware - extends MiddlewareAfterMiddleware { - middleware: ( - middlewares: Constrain>, - ) => MiddlewareAfterMiddleware +export interface RequestMiddleware + extends RequestMiddlewareAfterMiddleware { + middleware: ( + middlewares: Constrain>, + ) => RequestMiddlewareAfterMiddleware } -export function createMiddleware( - options?: { - validateClient?: boolean - }, - __opts?: MiddlewareOptions< - unknown, - undefined, - undefined, +export type AnyRequestMiddleware = RequestMiddlewareWithTypes + +export interface RequestMiddlewareWithTypes { + _types: RequestMiddlewareTypes +} + +export interface RequestMiddlewareTypes { + type: 'request' + middlewares: TMiddlewares + serverContext: TServerContext + allServerContext: AssignAllServerContext< + TMiddlewares, undefined, - ServerFnResponseType - >, -): Middleware { - // const resolvedOptions = (__opts || options) as MiddlewareOptions< - const resolvedOptions = - __opts || - ((options || {}) as MiddlewareOptions< - unknown, - undefined, - undefined, - undefined, - ServerFnResponseType - >) + TServerContext + > +} - return { - options: resolvedOptions as any, - middleware: (middleware: any) => { - return createMiddleware( - undefined, - Object.assign(resolvedOptions, { middleware }), - ) as any - }, - validator: (validator: any) => { - return createMiddleware( - undefined, - Object.assign(resolvedOptions, { validator }), - ) as any - }, - client: (client: any) => { - return createMiddleware( - undefined, - Object.assign(resolvedOptions, { client }), - ) as any - }, - server: (server: any) => { - return createMiddleware( - undefined, - Object.assign(resolvedOptions, { server }), - ) as any - }, - } as unknown as Middleware +export interface RequestMiddlewareAfterMiddleware + extends RequestMiddlewareWithTypes, + RequestMiddlewareServer {} + +export interface RequestMiddlewareServer { + server: ( + fn: RequestServerFn, + ) => RequestMiddlewareAfterServer +} + +export type RequestServerFn = ( + options: RequestServerOptions, +) => RequestMiddlewareServerFnResult + +export interface RequestServerOptions { + request: Request + pathname: string + context: AssignAllServerContext + next: RequestServerNextFn +} + +export type RequestServerNextFn = ( + options?: RequestServerNextFnOptions, +) => RequestMiddlewareServerFnResult + +export interface RequestServerNextFnOptions { + context?: TServerContext +} + +export type RequestMiddlewareServerFnResult = + | Promise> + | RequestServerResult + +export interface RequestServerResult { + request: Request + pathname: string + context: Expand< + AssignAllServerContext + > + response: Response } + +export interface RequestMiddlewareAfterServer + extends RequestMiddlewareWithTypes {} diff --git a/packages/start-client-core/src/createServerFn.ts b/packages/start-client-core/src/createServerFn.ts index a84995097e..14c1b26001 100644 --- a/packages/start-client-core/src/createServerFn.ts +++ b/packages/start-client-core/src/createServerFn.ts @@ -16,15 +16,17 @@ import type { } from '@tanstack/router-core' import type { Readable } from 'node:stream' import type { - AnyMiddleware, + AnyFunctionMiddleware, AssignAllClientSendContext, AssignAllServerContext, + FunctionMiddlewareClientFnResult, + FunctionMiddlewareServerFnResult, IntersectAllValidatorInputs, IntersectAllValidatorOutputs, - MiddlewareClientFnResult, - MiddlewareServerFnResult, } from './createMiddleware' +type TODO = any + export function createServerFn< TMethod extends Method, TServerFnResponseType extends ServerFnResponseType = 'data', @@ -215,8 +217,8 @@ export function createServerFn< } } -async function executeMiddleware( - middlewares: Array, +export async function executeMiddleware( + middlewares: Array, env: 'client' | 'server', opts: ServerFnMiddlewareOptions, ): Promise { @@ -398,6 +400,7 @@ export type ServerFnReturnType< > = TServerFnResponseType extends 'raw' ? RawResponse | Promise : Promise> | SerializerStringify + export type ServerFn< TMethod, TServerFnResponseType extends ServerFnResponseType, @@ -442,7 +445,7 @@ export type ServerFnBaseOptions< method: TMethod response?: TServerFnResponseType validateClient?: boolean - middleware?: Constrain> + middleware?: Constrain> validator?: ConstrainValidator extractedFn?: CompiledFetcherFn serverFn?: ServerFn< @@ -485,7 +488,10 @@ export interface ServerFnMiddleware< TValidator, > { middleware: ( - middlewares: Constrain>, + middlewares: Constrain< + TNewMiddlewares, + ReadonlyArray + >, ) => ServerFnAfterMiddleware< TMethod, TServerFnResponseType, @@ -812,12 +818,12 @@ export function extractFormDataContext(formData: FormData) { } export function flattenMiddlewares( - middlewares: Array, -): Array { - const seen = new Set() - const flattened: Array = [] + middlewares: Array, +): Array { + const seen = new Set() + const flattened: Array = [] - const recurse = (middleware: Array) => { + const recurse = (middleware: Array) => { middleware.forEach((m) => { if (m.options.middleware) { recurse(m.options.middleware) @@ -929,7 +935,7 @@ export function execValidator( export function serverFnBaseToMiddleware( options: ServerFnBaseOptions, -): AnyMiddleware { +): AnyFunctionMiddleware { return { _types: undefined!, options: { @@ -973,16 +979,25 @@ export function serverFnBaseToMiddleware( // but not before serializing the context const res = await options.extractedFn?.(payload) - return next(res) as unknown as MiddlewareClientFnResult + return next(res) as unknown as FunctionMiddlewareClientFnResult< + any, + any, + any + > }, server: async ({ next, ...ctx }) => { // Execute the server function - const result = await options.serverFn?.(ctx) + const result = await options.serverFn?.(ctx as TODO) return next({ ...ctx, result, - } as any) as unknown as MiddlewareServerFnResult + } as any) as unknown as FunctionMiddlewareServerFnResult< + any, + any, + any, + any + > }, }, } diff --git a/packages/start-client-core/src/index.tsx b/packages/start-client-core/src/index.tsx index fb50145dee..5c409dab00 100644 --- a/packages/start-client-core/src/index.tsx +++ b/packages/start-client-core/src/index.tsx @@ -25,30 +25,30 @@ export { createMiddleware, type IntersectAllValidatorInputs, type IntersectAllValidatorOutputs, - type MiddlewareServerFn, - type AnyMiddleware, - type MiddlewareOptions, - type MiddlewareWithTypes, - type MiddlewareValidator, - type MiddlewareServer, - type MiddlewareAfterClient, - type MiddlewareAfterMiddleware, - type MiddlewareAfterServer, - type Middleware, - type MiddlewareClientFnOptions, - type MiddlewareClientFnResult, - type MiddlewareClientNextFn, - type ClientResultWithContext, + type FunctionMiddlewareServerFn, + type AnyFunctionMiddleware, + type FunctionMiddlewareOptions, + type FunctionMiddlewareWithTypes, + type FunctionMiddlewareValidator, + type FunctionMiddlewareServer, + type FunctionMiddlewareAfterClient, + type FunctionMiddlewareAfterServer, + type FunctionMiddleware, + type FunctionMiddlewareClientFnOptions, + type FunctionMiddlewareClientFnResult, + type FunctionMiddlewareClientNextFn, + type FunctionClientResultWithContext, type AssignAllClientContextBeforeNext, type AssignAllMiddleware, type AssignAllServerContext, - type MiddlewareAfterValidator, - type MiddlewareClientFn, - type MiddlewareServerFnResult, - type MiddlewareClient, - type MiddlewareServerFnOptions, - type MiddlewareServerNextFn, - type ServerResultWithContext, + type FunctionMiddlewareAfterValidator, + type FunctionMiddlewareClientFn, + type FunctionMiddlewareServerFnResult, + type FunctionMiddlewareClient, + type FunctionMiddlewareServerFnOptions, + type FunctionMiddlewareServerNextFn, + type FunctionServerResultWithContext, + type AnyRequestMiddleware, } from './createMiddleware' export { registerGlobalMiddleware, @@ -84,4 +84,5 @@ export { extractFormDataContext, flattenMiddlewares, serverFnStaticCache, + executeMiddleware, } from './createServerFn' diff --git a/packages/start-client-core/src/registerGlobalMiddleware.ts b/packages/start-client-core/src/registerGlobalMiddleware.ts index 3d7effc85b..ab13d981ad 100644 --- a/packages/start-client-core/src/registerGlobalMiddleware.ts +++ b/packages/start-client-core/src/registerGlobalMiddleware.ts @@ -1,9 +1,9 @@ -import type { AnyMiddleware } from './createMiddleware' +import type { AnyFunctionMiddleware } from './createMiddleware' -export const globalMiddleware: Array = [] +export const globalMiddleware: Array = [] export function registerGlobalMiddleware(options: { - middleware: Array + middleware: Array }) { globalMiddleware.push(...options.middleware) } diff --git a/packages/start-client-core/src/ssr-client.tsx b/packages/start-client-core/src/ssr-client.tsx index 9eddf971db..b1b43f269a 100644 --- a/packages/start-client-core/src/ssr-client.tsx +++ b/packages/start-client-core/src/ssr-client.tsx @@ -77,15 +77,16 @@ export interface ResolvePromiseState { export interface DehydratedRouter { manifest: Manifest | undefined dehydratedData: any + lastMatchId: string } -export function hydrate(router: AnyRouter) { +export async function hydrate(router: AnyRouter): Promise { invariant( window.__TSR_SSR__?.dehydrated, 'Expected to find a dehydrated data on window.__TSR_SSR__.dehydrated... but we did not. Please file an issue!', ) - const { manifest, dehydratedData } = startSerializer.parse( + const { manifest, dehydratedData, lastMatchId } = startSerializer.parse( window.__TSR_SSR__.dehydrated, ) as DehydratedRouter @@ -116,6 +117,7 @@ export function hydrate(router: AnyRouter) { // Hydrate the router state const matches = router.matchRoutes(router.state.location) + // kick off loading the route chunks const routeChunkPromise = Promise.all( matches.map((match) => { @@ -123,6 +125,7 @@ export function hydrate(router: AnyRouter) { return router.loadRouteChunk(route) }), ) + // Right after hydration and before the first render, we need to rehydrate each match // First step is to reyhdrate loaderData and __beforeLoadContext matches.forEach((match) => { @@ -130,39 +133,36 @@ export function hydrate(router: AnyRouter) { (d) => d.id === match.id, ) - if (dehydratedMatch) { - Object.assign(match, dehydratedMatch) + if (!dehydratedMatch) { + return + } - // Handle beforeLoadContext - if (dehydratedMatch.__beforeLoadContext) { - match.__beforeLoadContext = router.ssr!.serializer.parse( - dehydratedMatch.__beforeLoadContext, - ) as any - } + Object.assign(match, dehydratedMatch) - // Handle loaderData - if (dehydratedMatch.loaderData) { - match.loaderData = router.ssr!.serializer.parse( - dehydratedMatch.loaderData, - ) - } + // Handle beforeLoadContext + if (dehydratedMatch.__beforeLoadContext) { + match.__beforeLoadContext = router.ssr!.serializer.parse( + dehydratedMatch.__beforeLoadContext, + ) as any + } - // Handle error - if (dehydratedMatch.error) { - match.error = router.ssr!.serializer.parse(dehydratedMatch.error) - } + // Handle loaderData + if (dehydratedMatch.loaderData) { + match.loaderData = router.ssr!.serializer.parse( + dehydratedMatch.loaderData, + ) + } - // Handle extracted - ;(match as unknown as SsrMatch).extracted?.forEach((ex) => { - deepMutableSetByPath(match, ['loaderData', ...ex.path], ex.value) - }) - } else { - Object.assign(match, { - status: 'success', - updatedAt: Date.now(), - }) + // Handle error + if (dehydratedMatch.error) { + match.error = router.ssr!.serializer.parse(dehydratedMatch.error) } + // Handle extracted + ;(match as unknown as SsrMatch).extracted?.forEach((ex) => { + deepMutableSetByPath(match, ['loaderData', ...ex.path], ex.value) + }) + return match }) @@ -179,50 +179,56 @@ export function hydrate(router: AnyRouter) { // now that all necessary data is hydrated: // 1) fully reconstruct the route context // 2) execute `head()` and `scripts()` for each match - router.state.matches.forEach((match) => { - const route = router.looseRoutesById[match.routeId]! - - const parentMatch = router.state.matches[match.index - 1] - const parentContext = parentMatch?.context ?? router.options.context ?? {} - - // `context()` was already executed by `matchRoutes`, however route context was not yet fully reconstructed - // so run it again and merge route context - const contextFnContext: RouteContextOptions = { - deps: match.loaderDeps, - params: match.params, - context: parentContext, - location: router.state.location, - navigate: (opts: any) => - router.navigate({ ...opts, _fromLocation: router.state.location }), - buildLocation: router.buildLocation, - cause: match.cause, - abortController: match.abortController, - preload: false, - matches, - } - match.__routeContext = route.options.context?.(contextFnContext) ?? {} + await Promise.all( + router.state.matches.map(async (match) => { + const route = router.looseRoutesById[match.routeId]! - match.context = { - ...parentContext, - ...match.__routeContext, - ...match.__beforeLoadContext, - } + const parentMatch = router.state.matches[match.index - 1] + const parentContext = parentMatch?.context ?? router.options.context ?? {} + + // `context()` was already executed by `matchRoutes`, however route context was not yet fully reconstructed + // so run it again and merge route context + const contextFnContext: RouteContextOptions = { + deps: match.loaderDeps, + params: match.params, + context: parentContext, + location: router.state.location, + navigate: (opts: any) => + router.navigate({ ...opts, _fromLocation: router.state.location }), + buildLocation: router.buildLocation, + cause: match.cause, + abortController: match.abortController, + preload: false, + matches, + } + match.__routeContext = route.options.context?.(contextFnContext) ?? {} - const assetContext = { - matches: router.state.matches, - match, - params: match.params, - loaderData: match.loaderData, - } - const headFnContent = route.options.head?.(assetContext) + match.context = { + ...parentContext, + ...match.__routeContext, + ...match.__beforeLoadContext, + } - const scripts = route.options.scripts?.(assetContext) + const assetContext = { + matches: router.state.matches, + match, + params: match.params, + loaderData: match.loaderData, + } + const headFnContent = await route.options.head?.(assetContext) - match.meta = headFnContent?.meta - match.links = headFnContent?.links - match.headScripts = headFnContent?.scripts - match.scripts = scripts - }) + const scripts = await route.options.scripts?.(assetContext) + + match.meta = headFnContent?.meta + match.links = headFnContent?.links + match.headScripts = headFnContent?.scripts + match.scripts = scripts + }), + ) + + if (matches[matches.length - 1]!.id !== lastMatchId) { + return await Promise.all([routeChunkPromise, router.load()]) + } return routeChunkPromise } diff --git a/packages/start-client-core/src/tests/createServerFn.test-d.ts b/packages/start-client-core/src/tests/createServerFn.test-d.ts index 5cb1305ebe..2abc7a409b 100644 --- a/packages/start-client-core/src/tests/createServerFn.test-d.ts +++ b/packages/start-client-core/src/tests/createServerFn.test-d.ts @@ -60,21 +60,25 @@ test('createServerFn with validator', () => { }) test('createServerFn with middleware and context', () => { - const middleware1 = createMiddleware().server(({ next }) => { - return next({ context: { a: 'a' } as const }) - }) + const middleware1 = createMiddleware({ type: 'function' }).server( + ({ next }) => { + return next({ context: { a: 'a' } as const }) + }, + ) - const middleware2 = createMiddleware().server(({ next }) => { - return next({ context: { b: 'b' } as const }) - }) + const middleware2 = createMiddleware({ type: 'function' }).server( + ({ next }) => { + return next({ context: { b: 'b' } as const }) + }, + ) - const middleware3 = createMiddleware() + const middleware3 = createMiddleware({ type: 'function' }) .middleware([middleware1, middleware2]) .client(({ next }) => { return next({ context: { c: 'c' } as const }) }) - const middleware4 = createMiddleware() + const middleware4 = createMiddleware({ type: 'function' }) .middleware([middleware3]) .client(({ context, next }) => { return next({ sendContext: context }) @@ -113,21 +117,24 @@ test('createServerFn with middleware and context', () => { }) describe('createServerFn with middleware and validator', () => { - const middleware1 = createMiddleware().validator( + const middleware1 = createMiddleware({ type: 'function' }).validator( (input: { readonly inputA: 'inputA' }) => ({ outputA: 'outputA', }) as const, ) - const middleware2 = createMiddleware().validator( + const middleware2 = createMiddleware({ type: 'function' }).validator( (input: { readonly inputB: 'inputB' }) => ({ outputB: 'outputB', }) as const, ) - const middleware3 = createMiddleware().middleware([middleware1, middleware2]) + const middleware3 = createMiddleware({ type: 'function' }).middleware([ + middleware1, + middleware2, + ]) test(`response: 'data'`, () => { const fn = createServerFn({ method: 'GET', response: 'data' }) @@ -222,7 +229,7 @@ describe('createServerFn with middleware and validator', () => { }) test('createServerFn overrides properties', () => { - const middleware1 = createMiddleware() + const middleware1 = createMiddleware({ type: 'function' }) .validator( () => ({ @@ -246,7 +253,7 @@ test('createServerFn overrides properties', () => { return next({ sendContext: newContext, context: newContext }) }) - const middleware2 = createMiddleware() + const middleware2 = createMiddleware({ type: 'function' }) .middleware([middleware1]) .validator( () => diff --git a/packages/start-client-core/src/tests/createServerMiddleware.test-d.ts b/packages/start-client-core/src/tests/createServerMiddleware.test-d.ts index 8ca1eaca36..5e61c970c8 100644 --- a/packages/start-client-core/src/tests/createServerMiddleware.test-d.ts +++ b/packages/start-client-core/src/tests/createServerMiddleware.test-d.ts @@ -1,10 +1,11 @@ import { expectTypeOf, test } from 'vitest' import { createMiddleware } from '../createMiddleware' +import type { RequestServerNextFn } from '../createMiddleware' import type { Constrain, Validator } from '@tanstack/router-core' import type { ConstrainValidator } from '../createServerFn' test('createServeMiddleware removes middleware after middleware,', () => { - const middleware = createMiddleware() + const middleware = createMiddleware({ type: 'function' }) expectTypeOf(middleware).toHaveProperty('middleware') expectTypeOf(middleware).toHaveProperty('server') @@ -45,51 +46,55 @@ test('createServeMiddleware removes middleware after middleware,', () => { }) test('createMiddleware merges server context', () => { - const middleware1 = createMiddleware().server(async (options) => { - expectTypeOf(options.context).toEqualTypeOf() - expectTypeOf(options.data).toEqualTypeOf() - expectTypeOf(options.method).toEqualTypeOf<'GET' | 'POST'>() + const middleware1 = createMiddleware({ type: 'function' }).server( + async (options) => { + expectTypeOf(options.context).toEqualTypeOf() + expectTypeOf(options.data).toEqualTypeOf() + expectTypeOf(options.method).toEqualTypeOf<'GET' | 'POST'>() - const result = await options.next({ context: { a: true } }) + const result = await options.next({ context: { a: true } }) - expectTypeOf(result).toEqualTypeOf<{ - 'use functions must return the result of next()': true - _types: { - context: { - a: boolean + expectTypeOf(result).toEqualTypeOf<{ + 'use functions must return the result of next()': true + _types: { + context: { + a: boolean + } + sendContext: undefined } + context: { a: boolean } sendContext: undefined - } - context: { a: boolean } - sendContext: undefined - }>() + }>() - return result - }) + return result + }, + ) - const middleware2 = createMiddleware().server(async (options) => { - expectTypeOf(options.context).toEqualTypeOf() - expectTypeOf(options.data).toEqualTypeOf() - expectTypeOf(options.method).toEqualTypeOf<'GET' | 'POST'>() + const middleware2 = createMiddleware({ type: 'function' }).server( + async (options) => { + expectTypeOf(options.context).toEqualTypeOf() + expectTypeOf(options.data).toEqualTypeOf() + expectTypeOf(options.method).toEqualTypeOf<'GET' | 'POST'>() - const result = await options.next({ context: { b: 'test' } }) + const result = await options.next({ context: { b: 'test' } }) - expectTypeOf(result).toEqualTypeOf<{ - 'use functions must return the result of next()': true - _types: { - context: { - b: string + expectTypeOf(result).toEqualTypeOf<{ + 'use functions must return the result of next()': true + _types: { + context: { + b: string + } + sendContext: undefined } + context: { b: string } sendContext: undefined - } - context: { b: string } - sendContext: undefined - }>() + }>() - return result - }) + return result + }, + ) - const middleware3 = createMiddleware() + const middleware3 = createMiddleware({ type: 'function' }) .middleware([middleware1, middleware2]) .server(async (options) => { expectTypeOf(options.context).toEqualTypeOf<{ a: boolean; b: string }>() @@ -111,7 +116,7 @@ test('createMiddleware merges server context', () => { return result }) - createMiddleware() + createMiddleware({ type: 'function' }) .middleware([middleware3]) .server(async (options) => { expectTypeOf(options.context).toEqualTypeOf<{ @@ -139,37 +144,41 @@ test('createMiddleware merges server context', () => { }) test('createMiddleware merges client context and sends to the server', () => { - const middleware1 = createMiddleware().client(async (options) => { - expectTypeOf(options.context).toEqualTypeOf() + const middleware1 = createMiddleware({ type: 'function' }).client( + async (options) => { + expectTypeOf(options.context).toEqualTypeOf() - const result = await options.next({ context: { a: true } }) + const result = await options.next({ context: { a: true } }) - expectTypeOf(result).toEqualTypeOf<{ - 'use functions must return the result of next()': true - context: { a: boolean } - sendContext: undefined - headers: HeadersInit - }>() + expectTypeOf(result).toEqualTypeOf<{ + 'use functions must return the result of next()': true + context: { a: boolean } + sendContext: undefined + headers: HeadersInit + }>() - return result - }) + return result + }, + ) - const middleware2 = createMiddleware().client(async (options) => { - expectTypeOf(options.context).toEqualTypeOf() + const middleware2 = createMiddleware({ type: 'function' }).client( + async (options) => { + expectTypeOf(options.context).toEqualTypeOf() - const result = await options.next({ context: { b: 'test' } }) + const result = await options.next({ context: { b: 'test' } }) - expectTypeOf(result).toEqualTypeOf<{ - 'use functions must return the result of next()': true - context: { b: string } - sendContext: undefined - headers: HeadersInit - }>() + expectTypeOf(result).toEqualTypeOf<{ + 'use functions must return the result of next()': true + context: { b: string } + sendContext: undefined + headers: HeadersInit + }>() - return result - }) + return result + }, + ) - const middleware3 = createMiddleware() + const middleware3 = createMiddleware({ type: 'function' }) .middleware([middleware1, middleware2]) .client(async (options) => { expectTypeOf(options.context).toEqualTypeOf<{ a: boolean; b: string }>() @@ -186,7 +195,7 @@ test('createMiddleware merges client context and sends to the server', () => { return result }) - const middleware4 = createMiddleware() + const middleware4 = createMiddleware({ type: 'function' }) .middleware([middleware3]) .client(async (options) => { expectTypeOf(options.context).toEqualTypeOf<{ @@ -209,7 +218,7 @@ test('createMiddleware merges client context and sends to the server', () => { return result }) - createMiddleware() + createMiddleware({ type: 'function' }) .middleware([middleware4]) .server(async (options) => { expectTypeOf(options.context).toEqualTypeOf<{ @@ -242,7 +251,7 @@ test('createMiddleware merges client context and sends to the server', () => { }) test('createMiddleware merges input', () => { - const middleware1 = createMiddleware() + const middleware1 = createMiddleware({ type: 'function' }) .validator(() => { return { a: 'a', @@ -253,7 +262,7 @@ test('createMiddleware merges input', () => { return next() }) - const middleware2 = createMiddleware() + const middleware2 = createMiddleware({ type: 'function' }) .middleware([middleware1]) .validator(() => { return { @@ -265,7 +274,7 @@ test('createMiddleware merges input', () => { return next() }) - createMiddleware() + createMiddleware({ type: 'function' }) .middleware([middleware2]) .validator(() => ({ c: 'c' }) as const) .server(({ next, data }) => { @@ -279,7 +288,7 @@ test('createMiddleware merges input', () => { }) test('createMiddleware merges server context and client context, sends server context to the client and merges ', () => { - const middleware1 = createMiddleware() + const middleware1 = createMiddleware({ type: 'function' }) .client(async (options) => { expectTypeOf(options.context).toEqualTypeOf() @@ -318,7 +327,7 @@ test('createMiddleware merges server context and client context, sends server co return result }) - const middleware2 = createMiddleware() + const middleware2 = createMiddleware({ type: 'function' }) .client(async (options) => { expectTypeOf(options.context).toEqualTypeOf() @@ -357,7 +366,7 @@ test('createMiddleware merges server context and client context, sends server co return result }) - const middleware3 = createMiddleware() + const middleware3 = createMiddleware({ type: 'function' }) .middleware([middleware1, middleware2]) .client(async (options) => { expectTypeOf(options.context).toEqualTypeOf<{ @@ -411,7 +420,7 @@ test('createMiddleware merges server context and client context, sends server co return result }) - const middleware4 = createMiddleware() + const middleware4 = createMiddleware({ type: 'function' }) .middleware([middleware3]) .client(async (options) => { expectTypeOf(options.context).toEqualTypeOf<{ @@ -475,7 +484,7 @@ test('createMiddleware merges server context and client context, sends server co return result }) - createMiddleware() + createMiddleware({ type: 'function' }) .middleware([middleware4]) .client(async (options) => { expectTypeOf(options.context).toEqualTypeOf<{ @@ -548,7 +557,7 @@ test('createMiddleware merges server context and client context, sends server co }) test('createMiddleware sendContext cannot send a function', () => { - createMiddleware() + createMiddleware({ type: 'function' }) .client(({ next }) => { expectTypeOf(next<{ func: () => 'func' }>) .parameter(0) @@ -570,7 +579,7 @@ test('createMiddleware sendContext cannot send a function', () => { }) test('createMiddleware cannot validate function', () => { - const validator = createMiddleware().validator< + const validator = createMiddleware({ type: 'function' }).validator< (input: { func: () => 'string' }) => { output: 'string' } > @@ -585,7 +594,7 @@ test('createMiddleware cannot validate function', () => { }) test('createMiddleware can validate Date', () => { - const validator = createMiddleware().validator< + const validator = createMiddleware({ type: 'function' }).validator< (input: Date) => { output: 'string' } > @@ -595,7 +604,7 @@ test('createMiddleware can validate Date', () => { }) test('createMiddleware can validate FormData', () => { - const validator = createMiddleware().validator< + const validator = createMiddleware({ type: 'function' }).validator< (input: FormData) => { output: 'string' } > @@ -606,8 +615,22 @@ test('createMiddleware can validate FormData', () => { >() }) +test('createMiddleware merging from parent with undefined validator', () => { + const middleware1 = createMiddleware({ type: 'function' }).validator( + (input: { test: string }) => input.test, + ) + + createMiddleware({ type: 'function' }) + .middleware([middleware1]) + .server((ctx) => { + expectTypeOf(ctx.data).toEqualTypeOf() + + return ctx.next() + }) +}) + test('createMiddleware validator infers unknown for default input type', () => { - createMiddleware() + createMiddleware({ type: 'function' }) .validator((input) => { expectTypeOf(input).toEqualTypeOf() @@ -621,3 +644,93 @@ test('createMiddleware validator infers unknown for default input type', () => { return next() }) }) + +test('createMiddleware with type request, no middleware or context', () => { + createMiddleware({ type: 'request' }).server(async (options) => { + expectTypeOf(options).toEqualTypeOf<{ + request: Request + next: RequestServerNextFn + pathname: string + context: undefined + }>() + + const result = await options.next() + + expectTypeOf(result).toEqualTypeOf<{ + context: undefined + pathname: string + request: Request + response: Response + }>() + + return result + }) +}) + +test('createMiddleware with type request, no middleware with context', () => { + createMiddleware({ type: 'request' }).server(async (options) => { + expectTypeOf(options).toEqualTypeOf<{ + request: Request + next: RequestServerNextFn + pathname: string + context: undefined + }>() + + const result = await options.next({ context: { a: 'a' } }) + + expectTypeOf(result).toEqualTypeOf<{ + context: { a: string } + pathname: string + request: Request + response: Response + }>() + + return result + }) +}) + +test('createMiddleware with type request, middleware and context', () => { + const middleware1 = createMiddleware({ type: 'request' }).server( + async (options) => { + expectTypeOf(options).toEqualTypeOf<{ + request: Request + next: RequestServerNextFn + pathname: string + context: undefined + }>() + + const result = await options.next({ context: { a: 'a' } }) + + expectTypeOf(result).toEqualTypeOf<{ + context: { a: string } + pathname: string + request: Request + response: Response + }>() + + return result + }, + ) + + createMiddleware({ type: 'request' }) + .middleware([middleware1]) + .server(async (options) => { + expectTypeOf(options).toEqualTypeOf<{ + request: Request + next: RequestServerNextFn + pathname: string + context: { a: string } + }>() + + const result = await options.next({ context: { b: 'b' } }) + + expectTypeOf(result).toEqualTypeOf<{ + context: { a: string; b: string } + pathname: string + request: Request + response: Response + }>() + + return result + }) +}) diff --git a/packages/start-client-core/vite.config.ts b/packages/start-client-core/vite.config.ts index ac2026fbb7..fb0b2664aa 100644 --- a/packages/start-client-core/vite.config.ts +++ b/packages/start-client-core/vite.config.ts @@ -16,5 +16,6 @@ export default mergeConfig( tanstackViteConfig({ srcDir: './src', entry: './src/index.tsx', + // externalDeps: ['node:fs', 'node:path', 'node:os', 'node:crypto'], }), ) diff --git a/packages/start-config/README.md b/packages/start-config/README.md deleted file mode 100644 index e3131543bd..0000000000 --- a/packages/start-config/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React applications! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/start-config/eslint.config.js b/packages/start-config/eslint.config.js deleted file mode 100644 index 931f0ec774..0000000000 --- a/packages/start-config/eslint.config.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check - -import pluginReact from '@eslint-react/eslint-plugin' -import pluginReactHooks from 'eslint-plugin-react-hooks' -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - ...pluginReact.configs.recommended, - files: ['**/*.{ts,tsx}'], - }, - { - plugins: { - 'react-hooks': pluginReactHooks, - }, - rules: { - '@eslint-react/no-unstable-context-value': 'off', - '@eslint-react/no-unstable-default-props': 'off', - '@eslint-react/dom/no-missing-button-type': 'off', - 'react-hooks/exhaustive-deps': 'error', - 'react-hooks/rules-of-hooks': 'error', - }, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/start-config/package.json b/packages/start-config/package.json deleted file mode 100644 index 8c5bb24691..0000000000 --- a/packages/start-config/package.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "@tanstack/start-config", - "version": "1.120.3", - "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/start-config" - }, - "homepage": "https://tanstack.com/start", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "keywords": [ - "react", - "location", - "router", - "routing", - "async", - "async router", - "typescript" - ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "build": "tsc", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0;vitest", - "test:eslint": "eslint ./src", - "test:types": "exit 0; vitest" - }, - "type": "module", - "types": "dist/esm/index.d.ts", - "exports": { - ".": { - "import": { - "types": "./dist/esm/index.d.ts", - "default": "./dist/esm/index.js" - } - }, - "./package.json": "./package.json" - }, - "sideEffects": false, - "files": [ - "dist", - "src" - ], - "engines": { - "node": ">=12" - }, - "dependencies": { - "@tanstack/react-router": "workspace:^", - "@tanstack/router-generator": "workspace:^", - "@tanstack/router-plugin": "workspace:^", - "@tanstack/server-functions-plugin": "workspace:^", - "@tanstack/react-start-plugin": "workspace:^", - "@tanstack/start-server-functions-handler": "workspace:^", - "@vitejs/plugin-react": "^4.3.4", - "import-meta-resolve": "^4.1.0", - "nitropack": "^2.10.4", - "ofetch": "^1.4.1", - "vite": "^6.1.0", - "vinxi": "0.5.3", - "zod": "^3.24.2" - }, - "peerDependencies": { - "react": ">=18.0.0 || >=19.0.0", - "react-dom": ">=18.0.0 || >=19.0.0", - "vite": "^6.0.0" - } -} diff --git a/packages/start-config/src/index.ts b/packages/start-config/src/index.ts deleted file mode 100644 index 4f67610504..0000000000 --- a/packages/start-config/src/index.ts +++ /dev/null @@ -1,663 +0,0 @@ -import path from 'node:path' -import { existsSync, readFileSync } from 'node:fs' -import { readFile } from 'node:fs/promises' -import { fileURLToPath } from 'node:url' -import viteReact from '@vitejs/plugin-react' -import { resolve } from 'import-meta-resolve' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' -import { getConfig } from '@tanstack/router-generator' -import { createApp } from 'vinxi' -import { config } from 'vinxi/plugins/config' -// // @ts-expect-error -// import { serverComponents } from '@vinxi/server-components/plugin' -import { createTanStackServerFnPlugin } from '@tanstack/server-functions-plugin' -import { createTanStackStartPlugin } from '@tanstack/react-start-plugin' -import { createFetch } from 'ofetch' -import { createNitro } from 'nitropack' -import { tanstackStartVinxiFileRouter } from './vinxi-file-router.js' -import { - checkDeploymentPresetInput, - getUserViteConfig, - inlineConfigSchema, - serverSchema, -} from './schema.js' -import type { configSchema } from '@tanstack/router-generator' -import type { z } from 'zod' -import type { - TanStackStartInputConfig, - TanStackStartOutputConfig, -} from './schema.js' -import type { App as VinxiApp } from 'vinxi' -import type { Manifest } from '@tanstack/react-router' -import type * as vite from 'vite' - -export type { - TanStackStartInputConfig, - TanStackStartOutputConfig, -} from './schema.js' - -function setTsrDefaults(config: TanStackStartOutputConfig['tsr']) { - // Normally these are `./src/___`, but we're using `./app/___` for Start stuff - const appDirectory = config?.appDirectory ?? './app' - return { - ...config, - appDirectory: config?.appDirectory ?? appDirectory, - routesDirectory: - config?.routesDirectory ?? path.join(appDirectory, 'routes'), - generatedRouteTree: - config?.generatedRouteTree ?? path.join(appDirectory, 'routeTree.gen.ts'), - } -} - -function mergeSsrOptions(options: Array) { - let ssrOptions: vite.SSROptions = {} - let noExternal: vite.SSROptions['noExternal'] = [] - for (const option of options) { - if (!option) { - continue - } - - if (option.noExternal) { - if (option.noExternal === true) { - noExternal = true - } else if (noExternal !== true) { - if (Array.isArray(option.noExternal)) { - noExternal.push(...option.noExternal) - } else { - noExternal.push(option.noExternal) - } - } - } - - ssrOptions = { - ...ssrOptions, - ...option, - noExternal, - } - } - - return ssrOptions -} - -export async function defineConfig( - inlineConfig: TanStackStartInputConfig = {}, -): Promise { - const opts = inlineConfigSchema.parse(inlineConfig) - - const { preset: configDeploymentPreset, ...serverOptions } = - serverSchema.parse(opts.server || {}) - - const deploymentPreset = checkDeploymentPresetInput(configDeploymentPreset) - const tsr = setTsrDefaults(opts.tsr) - const tsrConfig = getConfig(tsr) - - const appDirectory = tsr.appDirectory - const publicDir = opts.routers?.public?.dir || './public' - - const publicBase = opts.routers?.public?.base || '/' - const clientBase = opts.routers?.client?.base || '/_build' - const apiBase = opts.tsr?.apiBase || '/api' - const serverBase = opts.routers?.server?.base || '/_server' - - const apiMiddleware = opts.routers?.api?.middleware || undefined - const serverMiddleware = opts.routers?.server?.middleware || undefined - const ssrMiddleware = opts.routers?.ssr?.middleware || undefined - - const clientEntry = - opts.routers?.client?.entry || path.join(appDirectory, 'client.tsx') - const ssrEntry = - opts.routers?.ssr?.entry || path.join(appDirectory, 'ssr.tsx') - const apiEntry = opts.routers?.api?.entry || path.join(appDirectory, 'api.ts') - const globalMiddlewareEntry = - opts.routers?.server?.globalMiddlewareEntry || - path.join(appDirectory, 'global-middleware.ts') - const apiEntryExists = existsSync(apiEntry) - - const viteConfig = getUserViteConfig(opts.vite) - - const TanStackServerFnsPlugin = createTanStackServerFnPlugin({ - // This is the ID that will be available to look up and import - // our server function manifest and resolve its module - manifestVirtualImportId: 'tsr:server-fn-manifest', - client: { - getRuntimeCode: () => - `import { createClientRpc } from '@tanstack/start/server-functions-client'`, - replacer: (opts) => - `createClientRpc('${opts.functionId}', '${serverBase}')`, - }, - ssr: { - getRuntimeCode: () => - `import { createSsrRpc } from '@tanstack/start/server-functions-ssr'`, - replacer: (opts) => `createSsrRpc('${opts.functionId}', '${serverBase}')`, - }, - server: { - getRuntimeCode: () => - `import { createServerRpc } from '@tanstack/start/server-functions-server'`, - replacer: (opts) => - `createServerRpc('${opts.functionId}', '${serverBase}', ${opts.fn})`, - }, - }) - - const TanStackStartPlugin = createTanStackStartPlugin({ - globalMiddlewareEntry, - }) - - // Create a dummy nitro app to get the resolved public output path - const dummyNitroApp = await createNitro({ - preset: deploymentPreset, - compatibilityDate: '2024-12-01', - }) - - const nitroOutputPublicDir = dummyNitroApp.options.output.publicDir - await dummyNitroApp.close() - - let vinxiApp = createApp({ - server: { - ...serverOptions, - preset: deploymentPreset, - experimental: { - ...serverOptions.experimental, - asyncContext: true, - }, - }, - routers: [ - { - name: 'public', - type: 'static', - dir: publicDir, - base: publicBase, - }, - { - name: 'client', - type: 'client', - target: 'browser', - handler: clientEntry, - base: clientBase, - // @ts-expect-error - build: { - sourcemap: true, - }, - plugins: () => { - const routerType = 'client' - const clientViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-client', { - ...viteConfig.userConfig, - ...clientViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(clientViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - clientViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(clientViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: true, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.client, - TanStackServerFnsPlugin.client, - ...(viteConfig.plugins || []), - ...(clientViteConfig.plugins || []), - viteReact(opts.react), - // TODO: RSCS - enable this - // serverComponents.client(), - ] - }, - }, - { - name: 'ssr', - type: 'http', - target: 'server', - handler: ssrEntry, - middleware: ssrMiddleware, - // @ts-expect-error - link: { - client: 'client', - }, - plugins: () => { - const routerType = 'ssr' - const ssrViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-ssr', { - ...viteConfig.userConfig, - ...ssrViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(ssrViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - ssrViteConfig.userConfig.ssr, - { - noExternal, - external: ['@vinxi/react-server-dom/client'], - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(ssrViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.ssr, - TanStackServerFnsPlugin.ssr, - tsrRoutesManifest({ - tsrConfig, - clientBase, - }), - ...(getUserViteConfig(opts.vite).plugins || []), - ...(getUserViteConfig(opts.routers?.ssr?.vite).plugins || []), - viteReact(opts.react), - ] - }, - }, - { - name: 'server', - type: 'http', - target: 'server', - base: serverBase, - middleware: serverMiddleware, - // TODO: RSCS - enable this - // worker: true, - handler: importToProjectRelative( - '@tanstack/start-server-functions-handler', - ), - plugins: () => { - const routerType = 'server' - const serverViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-server', { - ...viteConfig.userConfig, - ...serverViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(serverViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv('TSS_SERVER_FN_BASE', serverBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - serverViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(serverViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.server, - TanStackServerFnsPlugin.server, - // TODO: RSCS - remove this - // resolve: { - // conditions: [], - // }, - // TODO: RSCs - add this - // serverComponents.serverActions({ - // resolve: { - // conditions: [ - // 'react-server', - // // 'node', - // 'import', - // process.env.NODE_ENV, - // ], - // }, - // runtime: '@vinxi/react-server-dom/runtime', - // transpileDeps: ['react', 'react-dom', '@vinxi/react-server-dom'], - // }), - ...(viteConfig.plugins || []), - ...(serverViteConfig.plugins || []), - ] - }, - }, - ], - }) - - const noExternal = [ - '@tanstack/start', - '@tanstack/react-start', - '@tanstack/react-start/server', - '@tanstack/react-start-client', - '@tanstack/react-start-server', - '@tanstack/start-server-functions-fetcher', - '@tanstack/start-server-functions-handler', - '@tanstack/start-server-functions-client', - '@tanstack/start-server-functions-ssr', - '@tanstack/start-server-functions-server', - '@tanstack/react-start-router-manifest', - '@tanstack/start-config', - '@tanstack/start-api-routes', - '@tanstack/server-functions-plugin', - 'tsr:routes-manifest', - 'tsr:server-fn-manifest', - ] - - // If API routes handler exists, add a router for it - if (apiEntryExists) { - vinxiApp = vinxiApp.addRouter({ - name: 'api', - type: 'http', - target: 'server', - base: apiBase, - handler: apiEntry, - middleware: apiMiddleware, - routes: tanstackStartVinxiFileRouter({ tsrConfig, apiBase }), - plugins: () => { - const viteConfig = getUserViteConfig(opts.vite) - const apiViteConfig = getUserViteConfig(opts.routers?.api?.vite) - - return [ - config('tsr-vite-config-api', { - ...viteConfig.userConfig, - ...apiViteConfig.userConfig, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - apiViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(apiViteConfig.userConfig.optimizeDeps || {}), - }, - define: { - ...(viteConfig.userConfig.define || {}), - ...(apiViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv('TSS_OUTPUT_PUBLIC_DIR', nitroOutputPublicDir), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - ...(viteConfig.plugins || []), - ...(apiViteConfig.plugins || []), - ] - }, - }) - } - - // Because Vinxi doesn't use the normal nitro dev server, it doesn't - // supply $fetch during dev. We need to hook into the dev server creation, - // nab the proper utils from the custom nitro instance that is used - // during dev and supply the $fetch to app. - // Hopefully and likely, this will just get removed when we move to - // Nitro directly. - vinxiApp.hooks.hook('app:dev:nitro:config', (devServer) => { - vinxiApp.hooks.hook( - 'app:dev:server:created', - ({ devApp: { localFetch } }) => { - const $fetch = createFetch({ - fetch: localFetch, - defaults: { - baseURL: devServer.nitro.options.runtimeConfig.app.baseURL, - }, - }) - - // @ts-expect-error - globalThis.$fetch = $fetch - }, - ) - }) - - return vinxiApp -} - -function importToProjectRelative(p: string) { - const resolved = fileURLToPath(resolve(p, import.meta.url)) - - const relative = path.relative(process.cwd(), resolved) - - return relative -} - -function tsrRoutesManifest(opts: { - tsrConfig: z.infer - clientBase: string -}): vite.Plugin { - let config: vite.ResolvedConfig - - return { - name: 'tsr-routes-manifest', - configResolved(resolvedConfig) { - config = resolvedConfig - }, - resolveId(id) { - if (id === 'tsr:routes-manifest') { - return id - } - return - }, - async load(id) { - if (id === 'tsr:routes-manifest') { - // If we're in development, return a dummy manifest - - if (config.command === 'serve') { - return `export default () => ({ - routes: {} - })` - } - - const clientViteManifestPath = path.resolve( - config.build.outDir, - `../client/${opts.clientBase}/.vite/manifest.json`, - ) - - type ViteManifest = Record< - string, - { - file: string - isEntry: boolean - imports: Array - } - > - - let manifest: ViteManifest - try { - manifest = JSON.parse(await readFile(clientViteManifestPath, 'utf-8')) - } catch (err) { - console.error(err) - throw new Error( - `Could not find the production client vite manifest at '${clientViteManifestPath}'!`, - ) - } - - const routeTreePath = path.resolve(opts.tsrConfig.generatedRouteTree) - - let routeTreeContent: string - try { - routeTreeContent = readFileSync(routeTreePath, 'utf-8') - } catch (err) { - console.error(err) - throw new Error( - `Could not find the generated route tree at '${routeTreePath}'!`, - ) - } - - // Extract the routesManifest JSON from the route tree file. - // It's located between the /* ROUTE_MANIFEST_START and ROUTE_MANIFEST_END */ comment block. - - const routerManifest = JSON.parse( - routeTreeContent.match( - /\/\* ROUTE_MANIFEST_START([\s\S]*?)ROUTE_MANIFEST_END \*\//, - )?.[1] || '{ routes: {} }', - ) as Manifest - - const routes = routerManifest.routes - - let entryFile: - | { - file: string - imports: Array - } - | undefined - - const filesByRouteFilePath: ViteManifest = Object.fromEntries( - Object.entries(manifest).map(([k, v]) => { - if (v.isEntry) { - entryFile = v - } - - const rPath = k.split('?')[0] - - return [rPath, v] - }, {}), - ) - - // Add preloads to the routes from the vite manifest - Object.entries(routes).forEach(([k, v]) => { - const file = - filesByRouteFilePath[ - path.join(opts.tsrConfig.routesDirectory, v.filePath as string) - ] - - if (file) { - const preloads = file.imports.map((d) => - path.join(opts.clientBase, manifest[d]!.file), - ) - - preloads.unshift(path.join(opts.clientBase, file.file)) - - routes[k] = { - ...v, - preloads, - } - } - }) - - if (entryFile) { - routes.__root__!.preloads = [ - path.join(opts.clientBase, entryFile.file), - ...entryFile.imports.map((d) => - path.join(opts.clientBase, manifest[d]!.file), - ), - ] - } - - const recurseRoute = ( - route: { - preloads?: Array - children?: Array - }, - seenPreloads = {} as Record, - ) => { - route.preloads = route.preloads?.filter((preload) => { - if (seenPreloads[preload]) { - return false - } - seenPreloads[preload] = true - return true - }) - - if (route.children) { - route.children.forEach((child) => { - const childRoute = routes[child]! - recurseRoute(childRoute, { ...seenPreloads }) - }) - } - } - - // @ts-expect-error - recurseRoute(routes.__root__) - - const routesManifest = { - routes, - } - - if (process.env.TSR_VITE_DEBUG) { - console.info( - 'Routes Manifest: \n' + JSON.stringify(routesManifest, null, 2), - ) - } - - return `export default () => (${JSON.stringify(routesManifest)})` - } - return - }, - } -} - -function injectDefineEnv( - key: TKey, - value: TValue, -): { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } { - return { - [`process.env.${key}`]: JSON.stringify(value), - [`import.meta.env.${key}`]: JSON.stringify(value), - } as { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } -} diff --git a/packages/start-config/src/schema.ts b/packages/start-config/src/schema.ts deleted file mode 100644 index 4529483793..0000000000 --- a/packages/start-config/src/schema.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { configSchema } from '@tanstack/router-generator' -import { z } from 'zod' -import type { PluginOption } from 'vite' -import type { AppOptions as VinxiAppOptions } from 'vinxi' -import type { NitroOptions } from 'nitropack' -import type { Options as ViteReactOptions } from '@vitejs/plugin-react' -import type { CustomizableConfig } from 'vinxi/dist/types/lib/vite-dev' - -type StartUserViteConfig = CustomizableConfig | (() => CustomizableConfig) - -export function getUserViteConfig(config?: StartUserViteConfig): { - plugins: Array | undefined - userConfig: CustomizableConfig -} { - const { plugins, ...userConfig } = - typeof config === 'function' ? config() : { ...config } - return { plugins, userConfig } -} - -/** - * Not all the deployment presets are fully functional or tested. - * @see https://github.com/TanStack/router/pull/2002 - */ -const vinxiDeploymentPresets = [ - 'alwaysdata', // untested - 'aws-amplify', // untested - 'aws-lambda', // untested - 'azure', // untested - 'azure-functions', // untested - 'base-worker', // untested - 'bun', // ✅ working - 'cleavr', // untested - 'cli', // untested - 'cloudflare', // untested - 'cloudflare-module', // untested - 'cloudflare-pages', // ✅ working - 'cloudflare-pages-static', // untested - 'deno', // untested - 'deno-deploy', // untested - 'deno-server', // untested - 'digital-ocean', // untested - 'edgio', // untested - 'firebase', // untested - 'flight-control', // untested - 'github-pages', // untested - 'heroku', // untested - 'iis', // untested - 'iis-handler', // untested - 'iis-node', // untested - 'koyeb', // untested - 'layer0', // untested - 'netlify', // ✅ working - 'netlify-builder', // untested - 'netlify-edge', // untested - 'netlify-static', // untested - 'nitro-dev', // untested - 'nitro-prerender', // untested - 'node', // partially working - 'node-cluster', // untested - 'node-server', // ✅ working - 'platform-sh', // untested - 'service-worker', // untested - 'static', // 🟧 partially working - 'stormkit', // untested - 'vercel', // ✅ working - 'vercel-edge', // untested - 'vercel-static', // untested - 'winterjs', // untested - 'zeabur', // untested - 'zeabur-static', // untested -] as const - -type DeploymentPreset = (typeof vinxiDeploymentPresets)[number] | (string & {}) - -const testedDeploymentPresets: Array = [ - 'bun', - 'netlify', - 'vercel', - 'cloudflare-pages', - 'node-server', -] - -export function checkDeploymentPresetInput( - preset?: string, -): DeploymentPreset | undefined { - if (preset) { - if (!vinxiDeploymentPresets.includes(preset as any)) { - console.warn( - `Invalid deployment preset "${preset}". Available presets are: ${vinxiDeploymentPresets - .map((p) => `"${p}"`) - .join(', ')}.`, - ) - } - - if (!testedDeploymentPresets.includes(preset as any)) { - console.warn( - `The deployment preset '${preset}' is not fully supported yet and may not work as expected.`, - ) - } - } - - return preset -} - -type HTTPSOptions = { - cert?: string - key?: string - pfx?: string - passphrase?: string - validityDays?: number - domains?: Array -} - -type ServerOptions_ = VinxiAppOptions['server'] & { - https?: boolean | HTTPSOptions -} - -type ServerOptions = { - [K in keyof ServerOptions_]: ServerOptions_[K] -} - -export const serverSchema = z - .object({ - routeRules: z.custom().optional(), - preset: z.custom().optional(), - static: z.boolean().optional(), - prerender: z - .object({ - routes: z.array(z.string()), - ignore: z - .array( - z.custom< - string | RegExp | ((path: string) => undefined | null | boolean) - >(), - ) - .optional(), - crawlLinks: z.boolean().optional(), - }) - .optional(), - }) - .and(z.custom()) - -const viteSchema = z.custom() - -const viteReactSchema = z.custom() - -const routersSchema = z.object({ - ssr: z - .object({ - entry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - client: z - .object({ - entry: z.string().optional(), - base: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - server: z - .object({ - base: z.string().optional(), - globalMiddlewareEntry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - api: z - .object({ - entry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - public: z - .object({ - dir: z.string().optional(), - base: z.string().optional(), - }) - .optional(), -}) - -const tsrConfig = configSchema.partial().extend({ - appDirectory: z.string().optional(), -}) - -export const inlineConfigSchema = z.object({ - react: viteReactSchema.optional(), - vite: viteSchema.optional(), - tsr: tsrConfig.optional(), - routers: routersSchema.optional(), - server: serverSchema.optional(), -}) - -export type TanStackStartInputConfig = z.input -export type TanStackStartOutputConfig = z.infer diff --git a/packages/start-config/src/vinxi-file-router.ts b/packages/start-config/src/vinxi-file-router.ts deleted file mode 100644 index 9e6d829d1b..0000000000 --- a/packages/start-config/src/vinxi-file-router.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { - BaseFileSystemRouter as VinxiBaseFileSystemRouter, - analyzeModule as vinxiFsRouterAnalyzeModule, - cleanPath as vinxiFsRouterCleanPath, -} from 'vinxi/fs-router' -import { - CONSTANTS as GENERATOR_CONSTANTS, - startAPIRouteSegmentsFromTSRFilePath, -} from '@tanstack/router-generator' -import type { configSchema } from '@tanstack/router-generator' -import type { - AppOptions as VinxiAppOptions, - RouterSchemaInput as VinxiRouterSchemaInput, -} from 'vinxi' -import type { z } from 'zod' - -export function tanstackStartVinxiFileRouter(opts: { - tsrConfig: z.infer - apiBase: string -}) { - const apiBaseSegment = opts.apiBase.split('/').filter(Boolean).join('/') - const isAPIPath = new RegExp(`/${apiBaseSegment}/`) - - return function (router: VinxiRouterSchemaInput, app: VinxiAppOptions) { - // Our own custom File Router that extends the VinxiBaseFileSystemRouter - // for splitting the API routes into its own "bundle" - // and adding the $APIRoute metadata to the route object - // This could be customized in future to support more complex splits - class TanStackStartFsRouter extends VinxiBaseFileSystemRouter { - toPath(src: string): string { - const inputPath = vinxiFsRouterCleanPath(src, this.config) - - const segments = startAPIRouteSegmentsFromTSRFilePath( - inputPath, - opts.tsrConfig, - ) - - const pathname = segments - .map((part) => { - if (part.type === 'splat') { - return `*splat` - } - - if (part.type === 'param') { - return `:${part.value}?` - } - - return part.value - }) - .join('/') - - return pathname.length > 0 ? `/${pathname}` : '/' - } - - toRoute(src: string) { - const webPath = this.toPath(src) - - const [_, exports] = vinxiFsRouterAnalyzeModule(src) - - const hasAPIRoute = exports.find( - (exp) => exp.n === GENERATOR_CONSTANTS.APIRouteExportVariable, - ) - - return { - path: webPath, - filePath: src, - $APIRoute: - isAPIPath.test(webPath) && hasAPIRoute - ? { - src, - pick: [GENERATOR_CONSTANTS.APIRouteExportVariable], - } - : undefined, - } - } - } - - return new TanStackStartFsRouter( - { - dir: opts.tsrConfig.routesDirectory, - extensions: ['js', 'jsx', 'ts', 'tsx'], - }, - router, - app, - ) - } -} diff --git a/packages/start-config/tsconfig.json b/packages/start-config/tsconfig.json deleted file mode 100644 index 940a9cce0a..0000000000 --- a/packages/start-config/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": ["src/index.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist/esm", - "target": "esnext", - "noEmit": false - } -} diff --git a/packages/start-plugin-core/README.md b/packages/start-plugin-core/README.md new file mode 100644 index 0000000000..fd4ca0fd33 --- /dev/null +++ b/packages/start-plugin-core/README.md @@ -0,0 +1,12 @@ + + +# TanStack Start - Plugin Core + +This package is not meant to be used directly. It is a dependency of the TanStack Start framework-specific packages: + +- [`@tanstack/react-start`](https://www.npmjs.com/package/@tanstack/react-start) +- [`@tanstack/solid-start`](https://www.npmjs.com/package/@tanstack/solid-start). + +It provides the core functionality for TanStack Start, which is a fullstack-framework made for SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router). + +Head over to [tanstack.com/start](https://tanstack.com/start) for more information about getting started. diff --git a/packages/start-plugin-core/eslint.config.js b/packages/start-plugin-core/eslint.config.js new file mode 100644 index 0000000000..8ce6ad05fc --- /dev/null +++ b/packages/start-plugin-core/eslint.config.js @@ -0,0 +1,5 @@ +// @ts-check + +import rootConfig from '../../eslint.config.js' + +export default [...rootConfig] diff --git a/packages/start-api-routes/package.json b/packages/start-plugin-core/package.json similarity index 63% rename from packages/start-api-routes/package.json rename to packages/start-plugin-core/package.json index 3c2acd77ee..a75e78259a 100644 --- a/packages/start-api-routes/package.json +++ b/packages/start-plugin-core/package.json @@ -1,13 +1,13 @@ { - "name": "@tanstack/start-api-routes", - "version": "1.120.3", - "description": "Modern and scalable routing for applications", + "name": "@tanstack/start-plugin-core", + "version": "1.121.0-alpha.11", + "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/start-api-routes" + "directory": "packages/start-plugin-core" }, "homepage": "https://tanstack.com/start", "funding": { @@ -15,6 +15,7 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "keywords": [ + "solid", "react", "location", "router", @@ -25,8 +26,9 @@ ], "scripts": { "clean": "rimraf ./dist && rimraf ./coverage", + "clean:snapshots": "rimraf **/*snapshot* --glob", "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", + "test:unit": "vitest", "test:eslint": "eslint ./src", "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", @@ -40,6 +42,8 @@ }, "type": "module", "types": "dist/esm/index.d.ts", + "main": "dist/cjs/index.cjs", + "module": "dist/esm/index.js", "exports": { ".": { "import": { @@ -62,11 +66,29 @@ "node": ">=12" }, "dependencies": { + "@babel/code-frame": "7.26.2", + "@babel/core": "^7.26.8", + "@babel/types": "^7.26.8", "@tanstack/router-core": "workspace:^", - "@tanstack/start-server-core": "workspace:^", - "vinxi": "0.5.3" + "@tanstack/router-generator": "workspace:^", + "@tanstack/router-plugin": "workspace:^", + "@tanstack/router-utils": "workspace:^", + "@tanstack/server-functions-plugin": "workspace:^", + "@types/babel__code-frame": "^7.0.6", + "@types/babel__core": "^7.20.5", + "babel-dead-code-elimination": "^1.0.9", + "cheerio": "^1.0.0", + "h3": "1.13.0", + "nitropack": "^2.11.8", + "pathe": "^2.0.3", + "ufo": "^1.5.4", + "xmlbuilder2": "^3.1.1", + "zod": "^3.24.2" }, "devDependencies": { - "typescript": "^5.7.2" + "vite": "^6.0.0" + }, + "peerDependencies": { + "vite": ">=6.0.0" } } diff --git a/packages/start-plugin-core/src/build-sitemap.ts b/packages/start-plugin-core/src/build-sitemap.ts new file mode 100644 index 0000000000..180ac876b2 --- /dev/null +++ b/packages/start-plugin-core/src/build-sitemap.ts @@ -0,0 +1,213 @@ +import { writeFileSync } from 'node:fs' +import path from 'node:path' +import { create } from 'xmlbuilder2' +import { createLogger } from './utils' +import type { TanStackStartOutputConfig } from './plugin' +import type { XMLBuilder } from 'xmlbuilder2/lib/interfaces' + +export type SitemapUrl = { + loc: string + lastmod: string + priority?: number + changefreq?: + | 'always' + | 'hourly' + | 'daily' + | 'weekly' + | 'monthly' + | 'yearly' + | 'never' + alternateRefs?: Array<{ + href: string + hreflang?: string + }> + images?: Array<{ + loc: string + title?: string + caption?: string + }> + news?: { + publication: { + name: string + language: string + } + publicationDate: string | Date + title: string + } +} + +export type SitemapData = { + urls: Array +} + +function buildSitemapJson( + pages: TanStackStartOutputConfig['pages'], + host: string, +): SitemapData { + const slash = checkSlash(host) + + const urls: Array = pages + .filter((page) => { + return page.sitemap?.exclude !== true + }) + .map((page) => ({ + loc: `${host}${slash}${page.path.replace(/^\/+/g, '')}`, + lastmod: page.sitemap?.lastmod + ? new Date(page.sitemap.lastmod).toISOString().split('T')[0]! + : new Date().toISOString().split('T')[0]!, + priority: page.sitemap?.priority, + changefreq: page.sitemap?.changefreq, + alternateRefs: page.sitemap?.alternateRefs, + images: page.sitemap?.images, + news: page.sitemap?.news, + })) + + return { urls } +} + +function jsonToXml(sitemapData: SitemapData): string { + const sitemap = createXml('urlset') + + for (const item of sitemapData.urls) { + const page = sitemap.ele('url') + page.ele('loc').txt(item.loc) + page.ele('lastmod').txt(item.lastmod) + + if (item.priority !== undefined) { + page.ele('priority').txt(item.priority.toString()) + } + if (item.changefreq) { + page.ele('changefreq').txt(item.changefreq) + } + + // Add alternate references + if (item.alternateRefs?.length) { + for (const ref of item.alternateRefs) { + const alternateRef = page.ele('xhtml:link') + alternateRef.att('rel', 'alternate') + alternateRef.att('href', ref.href) + if (ref.hreflang) { + alternateRef.att('hreflang', ref.hreflang) + } + } + } + + // Add images + if (item.images?.length) { + for (const image of item.images) { + const imageElement = page.ele('image:image') + imageElement.ele('image:loc').txt(image.loc) + if (image.title) { + imageElement.ele('image:title').txt(image.title) + } + if (image.caption) { + imageElement.ele('image:caption').txt(image.caption) + } + } + } + + // Add news + if (item.news) { + const newsElement = page.ele('news:news') + const publication = newsElement.ele('news:publication') + publication.ele('news:name').txt(item.news.publication.name) + publication.ele('news:language').txt(item.news.publication.language) + newsElement + .ele('news:publication_date') + .txt(new Date(item.news.publicationDate).toISOString().split('T')[0]!) + newsElement.ele('news:title').txt(item.news.title) + } + } + + return sitemap.end({ prettyPrint: true }) +} + +export function buildSitemap({ + options, + publicDir, +}: { + options: TanStackStartOutputConfig + publicDir: string +}) { + const logger = createLogger('sitemap') + + let sitemapOptions = options.sitemap + + if (!sitemapOptions && options.pages.length) { + sitemapOptions = { enabled: true, outputPath: 'sitemap.xml' } + } + + if (!sitemapOptions?.enabled) { + throw new Error('Sitemap is not enabled') + } + + const { host, outputPath } = sitemapOptions + + if (!host) { + if (!options.sitemap) { + logger.info( + 'Hint: Pages found, but no sitemap host has been set. To enable sitemap generation, set the `sitemap.host` option.', + ) + return + } + throw new Error( + 'Sitemap host is not set and required to build the sitemap.', + ) + } + + if (!outputPath) { + throw new Error('Sitemap output path is not set') + } + + const { pages } = options + + if (!pages.length) { + logger.info('No pages were found to build the sitemap. Skipping...') + return + } + + logger.info('Building Sitemap...') + + // Build the sitemap data + const sitemapData = buildSitemapJson(pages, host) + + // Generate output paths + const xmlOutputPath = path.join(publicDir, outputPath) + const pagesOutputPath = path.join(publicDir, 'pages.json') + + try { + // Write XML sitemap + logger.info(`Writing sitemap XML at ${xmlOutputPath}`) + writeFileSync(xmlOutputPath, jsonToXml(sitemapData)) + + // Write pages data for runtime use + logger.info(`Writing pages data at ${pagesOutputPath}`) + writeFileSync( + pagesOutputPath, + JSON.stringify( + { + pages, + host, + lastBuilt: new Date().toISOString(), + }, + null, + 2, + ), + ) + } catch (e) { + logger.error(`Unable to write sitemap files`, e) + } +} + +function createXml(elementName: 'urlset' | 'sitemapindex'): XMLBuilder { + return create({ version: '1.0', encoding: 'UTF-8' }) + .ele(elementName, { + xmlns: 'https://www.sitemaps.org/schemas/sitemap/0.9', + }) + .com(`This file was automatically generated by TanStack Start.`) +} + +function checkSlash(host: string): string { + const finalChar = host.slice(-1) + return finalChar === '/' ? '' : '/' +} diff --git a/packages/start-plugin-core/src/compilers.ts b/packages/start-plugin-core/src/compilers.ts new file mode 100644 index 0000000000..c589fe4b13 --- /dev/null +++ b/packages/start-plugin-core/src/compilers.ts @@ -0,0 +1,759 @@ +import * as babel from '@babel/core' +import * as t from '@babel/types' +import { codeFrameColumns } from '@babel/code-frame' + +import { + deadCodeElimination, + findReferencedIdentifiers, +} from 'babel-dead-code-elimination' +import { generateFromAst, parseAst } from '@tanstack/router-utils' +import type { GeneratorResult, ParseAstOptions } from '@tanstack/router-utils' + +export type CompileStartFrameworkOptions = 'react' | 'solid' + +export function compileStartOutputFactory( + framework: CompileStartFrameworkOptions, +) { + return function compileStartOutput(opts: CompileOptions): GeneratorResult { + const ast = parseAst(opts) + + const doDce = opts.dce ?? true + // find referenced identifiers *before* we transform anything + const refIdents = doDce ? findReferencedIdentifiers(ast) : undefined + + babel.traverse(ast, { + Program: { + enter(programPath) { + const identifiers: { + createServerFileRoute: IdentifierConfig + createServerFn: IdentifierConfig + createMiddleware: IdentifierConfig + serverOnly: IdentifierConfig + clientOnly: IdentifierConfig + createIsomorphicFn: IdentifierConfig + } = { + createServerFileRoute: { + name: 'createServerFileRoute', + handleCallExpression: + handleCreateServerFileRouteCallExpressionFactory(framework), + paths: [], + }, + createServerFn: { + name: 'createServerFn', + handleCallExpression: handleCreateServerFnCallExpression, + paths: [], + }, + createMiddleware: { + name: 'createMiddleware', + handleCallExpression: handleCreateMiddlewareCallExpression, + paths: [], + }, + serverOnly: { + name: 'serverOnly', + handleCallExpression: handleServerOnlyCallExpression, + paths: [], + }, + clientOnly: { + name: 'clientOnly', + handleCallExpression: handleClientOnlyCallExpression, + paths: [], + }, + createIsomorphicFn: { + name: 'createIsomorphicFn', + handleCallExpression: handleCreateIsomorphicFnCallExpression, + paths: [], + }, + } + + const identifierKeys = Object.keys(identifiers) as Array< + keyof typeof identifiers + > + + programPath.traverse({ + ImportDeclaration: (path) => { + if ( + path.node.source.value !== '@tanstack/react-start' && + path.node.source.value !== '@tanstack/solid-start' + ) { + return + } + + // handle a destructured imports being renamed like "import { createServerFn as myCreateServerFn } from '@tanstack/react-start';" + path.node.specifiers.forEach((specifier) => { + identifierKeys.forEach((identifierKey) => { + const identifier = identifiers[identifierKey] + + if ( + specifier.type === 'ImportSpecifier' && + specifier.imported.type === 'Identifier' + ) { + if (specifier.imported.name === identifierKey) { + identifier.name = specifier.local.name + } + } + + // handle namespace imports like "import * as TanStackStart from '@tanstack/react-start';" + if (specifier.type === 'ImportNamespaceSpecifier') { + identifier.name = `${specifier.local.name}.${identifierKey}` + } + }) + }) + }, + CallExpression: (path) => { + identifierKeys.forEach((identifierKey) => { + // Check to see if the call expression is a call to the + // identifiers[identifierKey].name + if ( + t.isIdentifier(path.node.callee) && + path.node.callee.name === identifiers[identifierKey].name + ) { + // The identifier could be a call to the original function + // in the source code. If this is case, we need to ignore it. + // Check the scope to see if the identifier is a function declaration. + // if it is, then we can ignore it. + + if ( + path.scope.getBinding(identifiers[identifierKey].name)?.path + .node.type === 'FunctionDeclaration' + ) { + return + } + + return identifiers[identifierKey].paths.push(path) + } + + if (t.isMemberExpression(path.node.callee)) { + if ( + t.isIdentifier(path.node.callee.object) && + t.isIdentifier(path.node.callee.property) + ) { + const callname = [ + path.node.callee.object.name, + path.node.callee.property.name, + ].join('.') + + if (callname === identifiers[identifierKey].name) { + identifiers[identifierKey].paths.push(path) + } + } + } + + return + }) + }, + }) + + identifierKeys.forEach((identifierKey) => { + identifiers[identifierKey].paths.forEach((path) => { + identifiers[identifierKey].handleCallExpression( + path as babel.NodePath, + opts, + ) + }) + }) + }, + }, + }) + + if (doDce) { + deadCodeElimination(ast, refIdents) + } + + return generateFromAst(ast, { + sourceMaps: true, + sourceFileName: opts.filename, + filename: opts.filename, + }) + } +} + +function handleCreateServerFileRouteCallExpressionFactory( + factory: CompileStartFrameworkOptions, +) { + return function handleCreateServerFileRouteCallExpression( + path: babel.NodePath, + opts: CompileOptions, + ) { + const PACKAGES = { start: `@tanstack/${factory}-start/server` } + + let highestParent: babel.NodePath = path + + while (highestParent.parentPath && !highestParent.parentPath.isProgram()) { + highestParent = highestParent.parentPath + } + + const programPath = highestParent.parentPath as babel.NodePath + + // // Find the root call expression and all of the methods that are called on it + // const rootCallExpression = getRootCallExpression(path) + + // const callExpressionPaths = { + // validator: null as babel.NodePath | null, + // middleware: null as babel.NodePath | null, + // methods: null as babel.NodePath | null, + // } + + // const validMethods = Object.keys(callExpressionPaths) + + // rootCallExpression.traverse({ + // MemberExpression(memberExpressionPath) { + // if (t.isIdentifier(memberExpressionPath.node.property)) { + // const name = memberExpressionPath.node.property + // .name as keyof typeof callExpressionPaths + + // if ( + // validMethods.includes(name) && + // memberExpressionPath.parentPath.isCallExpression() + // ) { + // callExpressionPaths[name] = memberExpressionPath.parentPath + // } + // } + // }, + // }) + + // const manifest = { middleware: false, methods: {} as any } + + // Object.entries(callExpressionPaths).forEach(([key, callPath]) => { + // if (callPath && t.isMemberExpression(callPath.node.callee)) { + // if (key === 'middleware') { + // manifest.middleware = true + // } else if (key === 'methods') { + // // Get the methods object from the methods call + // const methodsArg = callPath.node.arguments[0] + + // // Handle the case where methods is a function that returns an object + // if ( + // t.isArrowFunctionExpression(methodsArg) && + // t.isObjectExpression(methodsArg.body) + // ) { + // methodsArg.body.properties.forEach((prop) => { + // if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) { + // const methodName = prop.key.name + // manifest.methods[methodName] = { + // middleware: false, + // } + + // // Check if this method has a middleware + // if (t.isCallExpression(prop.value)) { + // const method = prop.value + // method.arguments.forEach((arg) => { + // if (t.isObjectExpression(arg)) { + // arg.properties.forEach((methodProp) => { + // if ( + // t.isObjectProperty(methodProp) && + // t.isIdentifier(methodProp.key) + // ) { + // if (methodProp.key.name === 'middleware') { + // manifest.methods[methodName].middleware = true + // } + // } + // }) + // } + // }) + // } + // } + // }) + // } + // // Handle the case where methods is a direct object + // else if (t.isObjectExpression(methodsArg)) { + // methodsArg.properties.forEach((prop) => { + // if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) { + // const methodName = prop.key.name + // manifest.methods[methodName] = { + // middleware: false, + // } + // } + // }) + // } + // } + + // if (opts.env === 'client') { + // callPath.replaceWith(callPath.node.callee.object) + // } + // } + // }) + + // If we're on the client, remove the entire variable + if (opts.env === 'client') { + // console.debug('createServerFileRoute -> manifest:\n', manifest) + highestParent.remove() + return + } + + // path.replaceWith( + // t.callExpression(t.identifier('createServerFileRoute'), [ + // t.identifier('undefined'), + // t.callExpression( + // t.memberExpression(t.identifier('Object'), t.identifier('assign')), + // [ + // t.objectExpression( + // path.node.arguments + // .map((arg) => { + // if (t.isIdentifier(arg)) { + // return t.objectProperty(t.identifier(arg.name), arg) + // } + // // Handle other cases or return a default value if necessary + // return null // or throw an error, or handle accordingly + // }) + // .filter( + // (property): property is t.ObjectProperty => property !== null, + // ), + // ), + // t.objectExpression([ + // t.objectProperty( + // t.identifier('manifest'), + // t.valueToNode(manifest), + // ), + // ]), + // ], + // ), + // ]), + // ) + + let isCreateServerFileRouteImported = false as boolean + + programPath.traverse({ + ImportDeclaration(importPath) { + const importSource = importPath.node.source.value + if (importSource === PACKAGES.start) { + const specifiers = importPath.node.specifiers + isCreateServerFileRouteImported = specifiers.some((specifier) => { + return ( + t.isImportSpecifier(specifier) && + t.isIdentifier(specifier.imported) && + specifier.imported.name === 'createServerFileRoute' + ) + }) + } + }, + }) + + if (!isCreateServerFileRouteImported) { + const importDeclaration = t.importDeclaration( + [ + t.importSpecifier( + t.identifier('createServerFileRoute'), + t.identifier('createServerFileRoute'), + ), + ], + t.stringLiteral(PACKAGES.start), + ) + programPath.node.body.unshift(importDeclaration) + } + } +} + +// build these once and reuse them +export const handleServerOnlyCallExpression = + buildEnvOnlyCallExpressionHandler('server') +export const handleClientOnlyCallExpression = + buildEnvOnlyCallExpressionHandler('client') + +export type CompileOptions = ParseAstOptions & { + env: 'server' | 'client' + dce?: boolean + filename: string +} + +export type IdentifierConfig = { + name: string + handleCallExpression: ( + path: babel.NodePath, + opts: CompileOptions, + ) => void + paths: Array +} + +export function handleCreateServerFnCallExpression( + path: babel.NodePath, + opts: CompileOptions, +) { + // The function is the 'fn' property of the object passed to createServerFn + + // const firstArg = path.node.arguments[0] + // if (t.isObjectExpression(firstArg)) { + // // Was called with some options + // } + + // Traverse the member expression and find the call expressions for + // the validator, handler, and middleware methods. Check to make sure they + // are children of the createServerFn call expression. + + const calledOptions = path.node.arguments[0] + ? (path.get('arguments.0') as babel.NodePath) + : null + + const shouldValidateClient = !!calledOptions?.node.properties.find((prop) => { + return ( + t.isObjectProperty(prop) && + t.isIdentifier(prop.key) && + prop.key.name === 'validateClient' && + t.isBooleanLiteral(prop.value) && + prop.value.value === true + ) + }) + + const callExpressionPaths = { + middleware: null as babel.NodePath | null, + validator: null as babel.NodePath | null, + handler: null as babel.NodePath | null, + } + + const validMethods = Object.keys(callExpressionPaths) + + const rootCallExpression = getRootCallExpression(path) + + // if (debug) + // console.info( + // 'Handling createServerFn call expression:', + // rootCallExpression.toString(), + // ) + + // Check if the call is assigned to a variable + if (!rootCallExpression.parentPath.isVariableDeclarator()) { + throw new Error('createServerFn must be assigned to a variable!') + } + + // Get the identifier name of the variable + const variableDeclarator = rootCallExpression.parentPath.node + const existingVariableName = (variableDeclarator.id as t.Identifier).name + + rootCallExpression.traverse({ + MemberExpression(memberExpressionPath) { + if (t.isIdentifier(memberExpressionPath.node.property)) { + const name = memberExpressionPath.node.property + .name as keyof typeof callExpressionPaths + + if ( + validMethods.includes(name) && + memberExpressionPath.parentPath.isCallExpression() + ) { + callExpressionPaths[name] = memberExpressionPath.parentPath + } + } + }, + }) + + if (callExpressionPaths.validator) { + const innerInputExpression = callExpressionPaths.validator.node.arguments[0] + + if (!innerInputExpression) { + throw new Error( + 'createServerFn().validator() must be called with a validator!', + ) + } + + // If we're on the client, and we're not validating the client, remove the validator call expression + if ( + opts.env === 'client' && + !shouldValidateClient && + t.isMemberExpression(callExpressionPaths.validator.node.callee) + ) { + callExpressionPaths.validator.replaceWith( + callExpressionPaths.validator.node.callee.object, + ) + } + } + + // First, we need to move the handler function to a nested function call + // that is applied to the arguments passed to the server function. + + const handlerFnPath = callExpressionPaths.handler?.get( + 'arguments.0', + ) as babel.NodePath + + if (!callExpressionPaths.handler || !handlerFnPath.node) { + throw codeFrameError( + opts.code, + path.node.callee.loc!, + `createServerFn must be called with a "handler" property!`, + ) + } + + const handlerFn = handlerFnPath.node + + // So, the way we do this is we give the handler function a way + // to access the serverFn ctx on the server via function scope. + // The 'use server' extracted function will be called with the + // payload from the client, then use the scoped serverFn ctx + // to execute the handler function. + // This way, we can do things like data and middleware validation + // in the __execute function without having to AST transform the + // handler function too much itself. + + // .handler((optsOut, ctx) => { + // return ((optsIn) => { + // 'use server' + // ctx.__execute(handlerFn, optsIn) + // })(optsOut) + // }) + + // If the handler function is an identifier and we're on the client, we need to + // remove the bound function from the file. + // If we're on the server, you can leave it, since it will get referenced + // as a second argument. + + if (t.isIdentifier(handlerFn)) { + if (opts.env === 'client') { + // Find the binding for the handler function + const binding = handlerFnPath.scope.getBinding(handlerFn.name) + // Remove it + if (binding) { + binding.path.remove() + } + } + // If the env is server, just leave it alone + } + + handlerFnPath.replaceWith( + t.arrowFunctionExpression( + [t.identifier('opts'), t.identifier('signal')], + t.blockStatement( + // Everything in here is server-only, since the client + // will strip out anything in the 'use server' directive. + [ + t.returnStatement( + t.callExpression( + t.identifier(`${existingVariableName}.__executeServer`), + [t.identifier('opts'), t.identifier('signal')], + ), + ), + ], + [t.directive(t.directiveLiteral('use server'))], + ), + ), + ) + + if (opts.env === 'server') { + callExpressionPaths.handler.node.arguments.push(handlerFn) + } +} + +export function handleCreateMiddlewareCallExpression( + path: babel.NodePath, + opts: CompileOptions, +) { + const rootCallExpression = getRootCallExpression(path) + + // if (debug) + // console.info( + // 'Handling createMiddleware call expression:', + // rootCallExpression.toString(), + // ) + + const callExpressionPaths = { + middleware: null as babel.NodePath | null, + validator: null as babel.NodePath | null, + client: null as babel.NodePath | null, + server: null as babel.NodePath | null, + } + + const validMethods = Object.keys(callExpressionPaths) + + rootCallExpression.traverse({ + MemberExpression(memberExpressionPath) { + if (t.isIdentifier(memberExpressionPath.node.property)) { + const name = memberExpressionPath.node.property + .name as keyof typeof callExpressionPaths + + if ( + validMethods.includes(name) && + memberExpressionPath.parentPath.isCallExpression() + ) { + callExpressionPaths[name] = memberExpressionPath.parentPath + } + } + }, + }) + + if (callExpressionPaths.validator) { + const innerInputExpression = callExpressionPaths.validator.node.arguments[0] + + if (!innerInputExpression) { + throw new Error( + 'createMiddleware().validator() must be called with a validator!', + ) + } + + // If we're on the client, remove the validator call expression + if (opts.env === 'client') { + if (t.isMemberExpression(callExpressionPaths.validator.node.callee)) { + callExpressionPaths.validator.replaceWith( + callExpressionPaths.validator.node.callee.object, + ) + } + } + } + + const serverFnPath = callExpressionPaths.server?.get( + 'arguments.0', + ) as babel.NodePath + + if ( + callExpressionPaths.server && + serverFnPath.node && + opts.env === 'client' + ) { + // If we're on the client, remove the server call expression + if (t.isMemberExpression(callExpressionPaths.server.node.callee)) { + callExpressionPaths.server.replaceWith( + callExpressionPaths.server.node.callee.object, + ) + } + } +} + +function buildEnvOnlyCallExpressionHandler(env: 'client' | 'server') { + return function envOnlyCallExpressionHandler( + path: babel.NodePath, + opts: CompileOptions, + ) { + // if (debug) + // console.info(`Handling ${env}Only call expression:`, path.toString()) + + const isEnvMatch = + env === 'client' ? opts.env === 'client' : opts.env === 'server' + + if (isEnvMatch) { + // extract the inner function from the call expression + const innerInputExpression = path.node.arguments[0] + + if (!t.isExpression(innerInputExpression)) { + throw new Error( + `${env}Only() functions must be called with a function!`, + ) + } + + path.replaceWith(innerInputExpression) + return + } + + // If we're on the wrong environment, replace the call expression + // with a function that always throws an error. + path.replaceWith( + t.arrowFunctionExpression( + [], + t.blockStatement([ + t.throwStatement( + t.newExpression(t.identifier('Error'), [ + t.stringLiteral( + `${env}Only() functions can only be called on the ${env}!`, + ), + ]), + ), + ]), + ), + ) + } +} + +export function handleCreateIsomorphicFnCallExpression( + path: babel.NodePath, + opts: CompileOptions, +) { + const rootCallExpression = getRootCallExpression(path) + + // if (debug) + // console.info( + // 'Handling createIsomorphicFn call expression:', + // rootCallExpression.toString(), + // ) + + const callExpressionPaths = { + client: null as babel.NodePath | null, + server: null as babel.NodePath | null, + } + + const validMethods = Object.keys(callExpressionPaths) + + rootCallExpression.traverse({ + MemberExpression(memberExpressionPath) { + if (t.isIdentifier(memberExpressionPath.node.property)) { + const name = memberExpressionPath.node.property + .name as keyof typeof callExpressionPaths + + if ( + validMethods.includes(name) && + memberExpressionPath.parentPath.isCallExpression() + ) { + callExpressionPaths[name] = memberExpressionPath.parentPath + } + } + }, + }) + + if ( + validMethods.every( + (method) => + !callExpressionPaths[method as keyof typeof callExpressionPaths], + ) + ) { + const variableId = rootCallExpression.parentPath.isVariableDeclarator() + ? rootCallExpression.parentPath.node.id + : null + console.warn( + 'createIsomorphicFn called without a client or server implementation!', + 'This will result in a no-op function.', + 'Variable name:', + t.isIdentifier(variableId) ? variableId.name : 'unknown', + ) + } + + const envCallExpression = callExpressionPaths[opts.env] + + if (!envCallExpression) { + // if we don't have an implementation for this environment, default to a no-op + rootCallExpression.replaceWith( + t.arrowFunctionExpression([], t.blockStatement([])), + ) + return + } + + const innerInputExpression = envCallExpression.node.arguments[0] + + if (!t.isExpression(innerInputExpression)) { + throw new Error( + `createIsomorphicFn().${opts.env}(func) must be called with a function!`, + ) + } + + rootCallExpression.replaceWith(innerInputExpression) +} + +export function getRootCallExpression(path: babel.NodePath) { + // Find the highest callExpression parent + let rootCallExpression: babel.NodePath = path + + // Traverse up the chain of CallExpressions + while (rootCallExpression.parentPath.isMemberExpression()) { + const parent = rootCallExpression.parentPath + if (parent.parentPath.isCallExpression()) { + rootCallExpression = parent.parentPath + } + } + + return rootCallExpression +} + +function codeFrameError( + code: string, + loc: { + start: { line: number; column: number } + end: { line: number; column: number } + }, + message: string, +) { + const frame = codeFrameColumns( + code, + { + start: loc.start, + end: loc.end, + }, + { + highlightCode: true, + message, + }, + ) + + return new Error(frame) +} diff --git a/packages/start-plugin-core/src/constants.ts b/packages/start-plugin-core/src/constants.ts new file mode 100644 index 0000000000..5ae26d8748 --- /dev/null +++ b/packages/start-plugin-core/src/constants.ts @@ -0,0 +1,6 @@ +export const VITE_ENVIRONMENT_NAMES = { + // 'ssr' is chosen as the name for the server environment to ensure backwards compatibility + // with vite plugins that are not compatible with the new vite environment API (e.g. tailwindcss) + server: 'ssr', + client: 'client', +} as const diff --git a/packages/start-plugin-core/src/extractHtmlScripts.ts b/packages/start-plugin-core/src/extractHtmlScripts.ts new file mode 100644 index 0000000000..41e3ac44a9 --- /dev/null +++ b/packages/start-plugin-core/src/extractHtmlScripts.ts @@ -0,0 +1,19 @@ +import * as cheerio from 'cheerio' + +export function extractHtmlScripts( + html: string, +): Array<{ content?: string; src?: string }> { + const $ = cheerio.load(html) + const scripts: Array<{ content?: string; src?: string }> = [] + + $('script').each((_, element) => { + const src = $(element).attr('src') + const content = $(element).html() ?? undefined + scripts.push({ + src, + content, + }) + }) + + return scripts +} diff --git a/packages/start-plugin-core/src/index.ts b/packages/start-plugin-core/src/index.ts new file mode 100644 index 0000000000..fe6dd7fa90 --- /dev/null +++ b/packages/start-plugin-core/src/index.ts @@ -0,0 +1,8 @@ +export { + createTanStackConfig, + createTanStackStartOptionsSchema, + pageSchema, +} from './schema' + +export { TanStackStartVitePluginCore } from './plugin' +export { resolveViteId } from './utils' diff --git a/packages/start-plugin-core/src/nitro/dev-server-plugin.ts b/packages/start-plugin-core/src/nitro/dev-server-plugin.ts new file mode 100644 index 0000000000..3fc02ba95e --- /dev/null +++ b/packages/start-plugin-core/src/nitro/dev-server-plugin.ts @@ -0,0 +1,169 @@ +import { createEvent, getHeader, sendWebResponse } from 'h3' +import { isRunnableDevEnvironment } from 'vite' +import { extractHtmlScripts } from '../extractHtmlScripts' +import { VITE_ENVIRONMENT_NAMES } from '../constants' +import type { Connect, DevEnvironment, Plugin, ViteDevServer } from 'vite' + +declare global { + // eslint-disable-next-line no-var + var TSS_INJECTED_HEAD_SCRIPTS: string | undefined +} + +export function devServerPlugin(): Plugin { + // let config: UserConfig + let isTest = false + + return { + name: 'start-dev-ssr-plugin', + config(userConfig, { mode }) { + // config = userConfig + isTest = isTest ? isTest : mode === 'test' + }, + configureServer(viteDevServer) { + if (isTest) { + return + } + + ;(globalThis as any).viteDevServer = viteDevServer + + return () => { + remove_html_middlewares(viteDevServer.middlewares) + let cachedScripts: string | undefined + viteDevServer.middlewares.use(async (req, res) => { + const event = createEvent(req, res) + const serverEnv = viteDevServer.environments[ + VITE_ENVIRONMENT_NAMES.server + ] as DevEnvironment | undefined + + try { + if (!serverEnv) { + throw new Error( + `Server environment ${VITE_ENVIRONMENT_NAMES.server} not found`, + ) + } + if (!isRunnableDevEnvironment(serverEnv)) { + throw new Error( + `Expected server environment ${VITE_ENVIRONMENT_NAMES.server} to be a RunnableDevEnvironment. This can be caused by multiple vite versions being installed in the project.`, + ) + } + if (cachedScripts === undefined) { + const templateHtml = `` + const transformedHtml = await viteDevServer.transformIndexHtml( + req.url || '/', + templateHtml, + ) + const scripts = extractHtmlScripts(transformedHtml) + globalThis.TSS_INJECTED_HEAD_SCRIPTS = scripts + .map((script) => script.content ?? '') + .join(';') + } + const serverEntry = await serverEnv.runner.import( + '/~start/server-entry', + ) + const response = await serverEntry['default'](event) + + return sendWebResponse(event, response) + } catch (e) { + console.error(e) + viteDevServer.ssrFixStacktrace(e as Error) + + if ( + getHeader(event, 'content-type')?.includes('application/json') + ) { + return sendWebResponse( + event, + new Response( + JSON.stringify( + { + status: 500, + error: 'Internal Server Error', + message: + 'An unexpected error occurred. Please try again later.', + timestamp: new Date().toISOString(), + }, + null, + 2, + ), + { + status: 500, + headers: { + 'Content-Type': 'application/json', + }, + }, + ), + ) + } + + return sendWebResponse( + event, + new Response( + ` + + + + + Error + + + + + + `, + { + status: 500, + headers: { + 'Content-Type': 'text/html', + }, + }, + ), + ) + } + }) + } + }, + } +} + +/** + * Removes Vite internal middleware + * + * @param server + */ +function remove_html_middlewares(server: ViteDevServer['middlewares']) { + const html_middlewares = [ + 'viteIndexHtmlMiddleware', + 'vite404Middleware', + 'viteSpaFallbackMiddleware', + ] + for (let i = server.stack.length - 1; i > 0; i--) { + if ( + html_middlewares.includes( + // @ts-expect-error + server.stack[i].handle.name, + ) + ) { + server.stack.splice(i, 1) + } + } +} + +/** + * Formats error for SSR message in error overlay + * @param req + * @param error + * @returns + */ +function prepareError(req: Connect.IncomingMessage, error: unknown) { + const e = error as Error + return { + message: `An error occured while server rendering ${req.url}:\n\n\t${ + typeof e === 'string' ? e : e.message + } `, + stack: typeof e === 'string' ? '' : e.stack, + } +} diff --git a/packages/start-plugin-core/src/nitro/nitro-plugin.ts b/packages/start-plugin-core/src/nitro/nitro-plugin.ts new file mode 100644 index 0000000000..2e8df9fad3 --- /dev/null +++ b/packages/start-plugin-core/src/nitro/nitro-plugin.ts @@ -0,0 +1,235 @@ +import path from 'node:path' +import { rmSync } from 'node:fs' +import * as fsp from 'node:fs/promises' +import { build, copyPublicAssets, createNitro, prepare } from 'nitropack' +import { dirname, resolve } from 'pathe' +import { clientDistDir, ssrEntryFile } from '../plugin' +import { prerender } from '../prerender' +import { VITE_ENVIRONMENT_NAMES } from '../constants' +import { buildSitemap } from '../build-sitemap' +import { devServerPlugin } from './dev-server-plugin' +import type { + EnvironmentOptions, + PluginOption, + Rollup, + ViteBuilder, +} from 'vite' +import type { Nitro, NitroConfig } from 'nitropack' +import type { TanStackStartOutputConfig } from '../plugin' + +export function nitroPlugin( + options: TanStackStartOutputConfig, + getSsrBundle: () => Rollup.OutputBundle, +): Array { + const buildPreset = + process.env['START_TARGET'] ?? (options.target as string | undefined) + + return [ + devServerPlugin(), + { + name: 'tanstack-vite-plugin-nitro', + configEnvironment(name) { + if (name === VITE_ENVIRONMENT_NAMES.server) { + return { + build: { + commonjsOptions: { + include: [], + }, + ssr: true, + sourcemap: true, + rollupOptions: { + input: '/~start/server-entry', + }, + }, + } satisfies EnvironmentOptions + } + + return null + }, + config() { + return { + builder: { + sharedPlugins: true, + async buildApp(builder) { + const clientEnv = + builder.environments[VITE_ENVIRONMENT_NAMES.client] + const serverEnv = + builder.environments[VITE_ENVIRONMENT_NAMES.server] + + if (!clientEnv) { + throw new Error('Client environment not found') + } + + if (!serverEnv) { + throw new Error('SSR environment not found') + } + + const clientOutputDir = resolve(options.root, clientDistDir) + rmSync(clientOutputDir, { recursive: true, force: true }) + await builder.build(clientEnv) + + await builder.build(serverEnv) + + const nitroConfig: NitroConfig = { + dev: false, + // TODO do we need this? should this be made configurable? + compatibilityDate: '2024-11-19', + logLevel: 3, + preset: buildPreset, + publicAssets: [ + { + dir: path.resolve(options.root, clientDistDir), + }, + ], + typescript: { + generateTsConfig: false, + }, + prerender: undefined, + renderer: ssrEntryFile, + rollupConfig: { + plugins: [virtualBundlePlugin(getSsrBundle())], + }, + } + + const nitro = await createNitro(nitroConfig) + + await buildNitroApp(builder, nitro, options) + }, + }, + } + }, + }, + ] +} + +/** + * Correctly co-ordinates the nitro app build process to make sure that the + * app is built, while also correctly handling the prerendering and sitemap + * generation and including their outputs in the final build. + */ +async function buildNitroApp( + builder: ViteBuilder, + nitro: Nitro, + options: TanStackStartOutputConfig, +) { + // Cleans the public and server directories for a fresh build + // i.e the `.output/public` and `.output/server` directories + await prepare(nitro) + + // Creates the `.output/public` directory and copies the public assets + await copyPublicAssets(nitro) + + // If the user has not set a prerender option, we need to set it to true + // if the pages array is not empty and has sub options requiring for prerendering + if (options.prerender?.enabled !== false) { + options.prerender = { + ...options.prerender, + enabled: options.pages.some((d) => + typeof d === 'string' ? false : !!d.prerender?.enabled, + ), + } + } + + // Setup the options for prerendering the SPA shell (i.e `src/routes/__root.tsx`) + if (options.spa?.enabled) { + options.prerender = { + ...options.prerender, + enabled: true, + } + + const maskUrl = new URL(options.spa.maskPath, 'http://localhost') + + maskUrl.searchParams.set('__TSS_SHELL', 'true') + + options.pages.push({ + path: maskUrl.toString().replace('http://localhost', ''), + prerender: options.spa.prerender, + sitemap: { + exclude: true, + }, + }) + } + + // Run the prerendering process + if (options.prerender.enabled) { + await prerender({ + options, + nitro, + builder, + }) + } + + // Run the sitemap build process + if (options.pages.length) { + buildSitemap({ + options, + publicDir: nitro.options.output.publicDir, + }) + } + + // Build the nitro app + await build(nitro) + + // Cleanup the vite public directory + // As a part of the build process, a `.vite/` directory + // is copied over from `.tanstack-start/build/client-dist/` + // to the nitro `publicDir` (e.g. `.output/public/`). + // This directory (and its contents including the vite client manifest) + // should not be included in the final build, so we remove it. + const nitroPublicDir = nitro.options.output.publicDir + const viteDir = path.resolve(nitroPublicDir, '.vite') + if (await fsp.stat(viteDir).catch(() => false)) { + await fsp.rm(viteDir, { recursive: true, force: true }) + } + + // Close the nitro instance + await nitro.close() + nitro.logger.success( + 'Client and Server bundles for TanStack Start have been successfully built.', + ) +} + +function virtualBundlePlugin(ssrBundle: Rollup.OutputBundle): Rollup.Plugin { + type VirtualModule = { code: string; map: string | null } + const _modules = new Map() + + // group chunks and source maps + for (const [fileName, content] of Object.entries(ssrBundle)) { + if (content.type === 'chunk') { + const virtualModule: VirtualModule = { + code: content.code, + map: null, + } + const maybeMap = ssrBundle[`${fileName}.map`] + if (maybeMap && maybeMap.type === 'asset') { + virtualModule.map = maybeMap.source as string + } + _modules.set(fileName, virtualModule) + _modules.set(resolve(fileName), virtualModule) + } + } + + return { + name: 'virtual-bundle', + resolveId(id, importer) { + if (_modules.has(id)) { + return resolve(id) + } + + if (importer) { + const resolved = resolve(dirname(importer), id) + if (_modules.has(resolved)) { + return resolved + } + } + return null + }, + load(id) { + const m = _modules.get(id) + if (!m) { + return null + } + return m + }, + } +} diff --git a/packages/start-plugin-core/src/plugin.ts b/packages/start-plugin-core/src/plugin.ts new file mode 100644 index 0000000000..60daa41b3e --- /dev/null +++ b/packages/start-plugin-core/src/plugin.ts @@ -0,0 +1,216 @@ +import path from 'node:path' +import { createNitro } from 'nitropack' +import { tanstackRouter } from '@tanstack/router-plugin/vite' +import { TanStackServerFnPluginEnv } from '@tanstack/server-functions-plugin' +import * as vite from 'vite' +import { + createTanStackConfig, + createTanStackStartOptionsSchema, +} from './schema' +import { nitroPlugin } from './nitro/nitro-plugin' +import { startManifestPlugin } from './routesManifestPlugin' +import { TanStackStartCompilerPlugin } from './start-compiler-plugin' +import { VITE_ENVIRONMENT_NAMES } from './constants' +import { TanStackStartServerRoutesVite } from './start-server-routes-plugin/plugin' +import type { PluginOption, Rollup } from 'vite' +import type { z } from 'zod' +import type { CompileStartFrameworkOptions } from './compilers' + +const TanStackStartOptionsSchema = createTanStackStartOptionsSchema() +export type TanStackStartInputConfig = z.input< + typeof TanStackStartOptionsSchema +> + +const defaultConfig = createTanStackConfig() +export function getTanStackStartOptions(opts?: TanStackStartInputConfig) { + return defaultConfig.parse(opts) +} + +export type TanStackStartOutputConfig = ReturnType< + typeof getTanStackStartOptions +> + +export const clientDistDir = '.tanstack-start/build/client-dist' +export const ssrEntryFile = 'ssr.mjs' + +export interface TanStackStartVitePluginCoreOptions { + framework: CompileStartFrameworkOptions +} +// this needs to live outside of the TanStackStartVitePluginCore since it will be invoked multiple times by vite +let ssrBundle: Rollup.OutputBundle + +export function TanStackStartVitePluginCore( + opts: TanStackStartVitePluginCoreOptions, + startConfig: TanStackStartOutputConfig, +): Array { + return [ + tanstackRouter({ + verboseFileRoutes: false, + ...startConfig.tsr, + target: opts.framework, + enableRouteGeneration: true, + autoCodeSplitting: true, + }), + { + name: 'tanstack-start-core:config-client', + async config() { + const nitroOutputPublicDir = await (async () => { + // Create a dummy nitro app to get the resolved public output path + const dummyNitroApp = await createNitro({ + preset: startConfig.target, + compatibilityDate: '2024-12-01', + }) + + const nitroOutputPublicDir = dummyNitroApp.options.output.publicDir + await dummyNitroApp.close() + + return nitroOutputPublicDir + })() + + const getClientEntryPath = (startConfig: TanStackStartOutputConfig) => { + // when the user specifies a custom client entry path, we need to resolve it + // relative to the root of the project, keeping in mind that if not specified + // it will be /~start/default-client-entry which is a virtual path + // that is resolved by vite to the actual client entry path + const entry = startConfig.clientEntryPath.startsWith( + '/~start/default-client-entry', + ) + ? startConfig.clientEntryPath + : vite.normalizePath( + path.join( + '/@fs', + path.resolve(startConfig.root, startConfig.clientEntryPath), + ), + ) + + return entry + } + + return { + environments: { + [VITE_ENVIRONMENT_NAMES.client]: { + consumer: 'client', + build: { + manifest: true, + rollupOptions: { + input: { + main: getClientEntryPath(startConfig), + }, + output: { + dir: path.resolve(startConfig.root, clientDistDir), + }, + // TODO this should be removed + external: ['node:fs', 'node:path', 'node:os', 'node:crypto'], + }, + }, + }, + [VITE_ENVIRONMENT_NAMES.server]: { + consumer: 'server', + build: { + ssr: true, + // we don't write to the file system as the below 'capture-output' plugin will + // capture the output and write it to the virtual file system + write: false, + copyPublicDir: false, + rollupOptions: { + output: { + entryFileNames: ssrEntryFile, + }, + plugins: [ + { + name: 'capture-output', + generateBundle(options, bundle) { + // TODO can this hook be called more than once? + ssrBundle = bundle + }, + }, + ], + }, + commonjsOptions: { + include: [/node_modules/], + }, + }, + }, + }, + resolve: { + noExternal: [ + '@tanstack/start-client', + '@tanstack/start-client-core', + '@tanstack/start-server', + '@tanstack/start-server-core', + '@tanstack/start-server-functions-fetcher', + '@tanstack/start-server-functions-client', + '@tanstack/start-server-functions-server', + '@tanstack/start-router-manifest', + '@tanstack/start-config', + '@tanstack/server-functions-plugin', + 'tanstack-start-router-manifest:v', + 'tanstack-start-server-fn-manifest:v', + 'nitropack', + '@tanstack/**', + ], + }, + /* prettier-ignore */ + define: { + ...injectDefineEnv('TSS_PUBLIC_BASE', startConfig.public.base), + ...injectDefineEnv('TSS_CLIENT_BASE', startConfig.client.base), + ...injectDefineEnv('TSS_CLIENT_ENTRY', getClientEntryPath(startConfig)), // This is consumed by the router-manifest, where the entry point is imported after the dev refresh runtime is resolved + ...injectDefineEnv('TSS_SERVER_FN_BASE', startConfig.serverFns.base), + ...injectDefineEnv('TSS_OUTPUT_PUBLIC_DIR', nitroOutputPublicDir), + }, + } + }, + }, + // N.B. TanStackStartCompilerPlugin must be before the TanStackServerFnPluginEnv + TanStackStartCompilerPlugin(opts.framework, { + client: { envName: VITE_ENVIRONMENT_NAMES.client }, + server: { envName: VITE_ENVIRONMENT_NAMES.server }, + }), + TanStackServerFnPluginEnv({ + // This is the ID that will be available to look up and import + // our server function manifest and resolve its module + manifestVirtualImportId: 'tanstack-start-server-fn-manifest:v', + manifestOutputFilename: + '.tanstack-start/build/server/server-functions-manifest.json', + client: { + getRuntimeCode: () => + `import { createClientRpc } from '@tanstack/${opts.framework}-start/server-functions-client'`, + replacer: (d) => + `createClientRpc('${d.functionId}', '${startConfig.serverFns.base}')`, + envName: VITE_ENVIRONMENT_NAMES.client, + }, + server: { + getRuntimeCode: () => + `import { createServerRpc } from '@tanstack/${opts.framework}-start/server-functions-server'`, + replacer: (d) => + `createServerRpc('${d.functionId}', '${startConfig.serverFns.base}', ${d.fn})`, + envName: VITE_ENVIRONMENT_NAMES.server, + }, + importer: (fn) => { + const serverEnv = (globalThis as any).viteDevServer.environments[ + VITE_ENVIRONMENT_NAMES.server + ] + if (!serverEnv) { + throw new Error(`'ssr' vite dev environment not found`) + } + return serverEnv.runner.import(fn.extractedFilename) + }, + }), + startManifestPlugin(startConfig), + nitroPlugin(startConfig, () => ssrBundle), + TanStackStartServerRoutesVite({ + ...startConfig.tsr, + target: opts.framework, + }), + ] +} + +function injectDefineEnv( + key: TKey, + value: TValue, +): { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } { + return { + [`process.env.${key}`]: JSON.stringify(value), + [`import.meta.env.${key}`]: JSON.stringify(value), + } as { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } +} diff --git a/packages/start-plugin-core/src/prerender.ts b/packages/start-plugin-core/src/prerender.ts new file mode 100644 index 0000000000..36606c0d90 --- /dev/null +++ b/packages/start-plugin-core/src/prerender.ts @@ -0,0 +1,245 @@ +import { promises as fsp } from 'node:fs' +import os from 'node:os' +import path from 'node:path' +import { getRollupConfig } from 'nitropack/rollup' +import { build as buildNitro, createNitro } from 'nitropack' +import { joinURL, withBase, withoutBase } from 'ufo' +import { Queue } from './queue' +import { VITE_ENVIRONMENT_NAMES } from './constants' +import { createLogger } from './utils' +import type { ViteBuilder } from 'vite' +import type { $Fetch, Nitro } from 'nitropack' +import type { TanStackStartOutputConfig } from './plugin' +import type { Page } from './schema' + +export async function prerender({ + options, + nitro, + builder, +}: { + options: TanStackStartOutputConfig + nitro: Nitro + builder: ViteBuilder +}) { + const logger = createLogger('prerender') + logger.info('Prendering pages...') + + // If prerender is enabled but no pages are provided, default to prerendering the root page + if (options.prerender?.enabled && !options.pages.length) { + options.pages = [ + { + path: '/', + }, + ] + } + + const serverEnv = builder.environments[VITE_ENVIRONMENT_NAMES.server] + + if (!serverEnv) { + throw new Error( + `Vite's "${VITE_ENVIRONMENT_NAMES.server}" environment not found`, + ) + } + + const prerenderOutputDir = path.resolve( + options.root, + '.tanstack-start/build/prerenderer', + ) + + const nodeNitro = await createNitro({ + ...nitro.options._config, + preset: 'nitro-prerender', + logLevel: 0, + output: { + dir: prerenderOutputDir, + serverDir: path.resolve(prerenderOutputDir, 'server'), + publicDir: path.resolve(prerenderOutputDir, 'public'), + }, + }) + + const nodeNitroRollupOptions = getRollupConfig(nodeNitro) + + const build = serverEnv.config.build + + build.outDir = prerenderOutputDir + + build.rollupOptions = { + ...build.rollupOptions, + ...nodeNitroRollupOptions, + output: { + ...build.rollupOptions.output, + ...nodeNitroRollupOptions.output, + sourcemap: undefined, + }, + } + + await buildNitro(nodeNitro) + + // Import renderer entry + const serverFilename = + typeof nodeNitroRollupOptions.output.entryFileNames === 'string' + ? nodeNitroRollupOptions.output.entryFileNames + : 'index.mjs' + + const serverEntrypoint = path.resolve( + path.join(nodeNitro.options.output.serverDir, serverFilename), + ) + + const { closePrerenderer, localFetch } = (await import(serverEntrypoint)) as { + closePrerenderer: () => void + localFetch: $Fetch + } + + try { + // Crawl all pages + const pages = await prerenderPages() + + logger.info(`Prerendered ${pages.length} pages:`) + pages.forEach((page) => { + logger.info(`- ${page}`) + }) + + // TODO: Write the prerendered pages to the output directory + } catch (error) { + logger.error(error) + } finally { + // Ensure server is always closed + // server.process.kill() + closePrerenderer() + } + + function extractLinks(html: string): Array { + const linkRegex = /]+href=["']([^"']+)["'][^>]*>/g + const links: Array = [] + let match + + while ((match = linkRegex.exec(html)) !== null) { + const href = match[1] + if (href && (href.startsWith('/') || href.startsWith('./'))) { + links.push(href) + } + } + + return links + } + + async function prerenderPages() { + const seen = new Set() + const retriesByPath = new Map() + const concurrency = options.prerender?.concurrency ?? os.cpus().length + logger.info(`Concurrency: ${concurrency}`) + const queue = new Queue({ concurrency }) + + options.pages.forEach((page) => addCrawlPageTask(page)) + + await queue.start() + + return Array.from(seen) + + function addCrawlPageTask(page: Page) { + // Was the page already seen? + if (seen.has(page.path)) return + + // Add the page to the seen set + seen.add(page.path) + + if (page.fromCrawl) { + options.pages.push(page) + } + + // If not enabled, skip + if (!(page.prerender?.enabled ?? true)) return + + // If there is a filter link, check if the page should be prerendered + if (options.prerender?.filter && !options.prerender.filter(page)) return + + // Resolve the merged default and page-specific prerender options + const prerenderOptions = { + ...options.prerender, + ...page.prerender, + } + + // Add the task + queue.add(async () => { + logger.info(`Crawling: ${page.path}`) + const retries = retriesByPath.get(page.path) || 0 + try { + // Fetch the route + const encodedRoute = encodeURI(page.path) + + const res = await localFetch( + withBase(encodedRoute, nodeNitro.options.baseURL), + { + headers: { 'x-nitro-prerender': encodedRoute }, + }, + ) + + if (!res.ok) { + throw new Error(`Failed to fetch ${page.path}: ${res.statusText}`, { + cause: res, + }) + } + + const cleanPagePath = ( + prerenderOptions.outputPath || page.path + ).split(/[?#]/)[0]! + + // Guess route type and populate fileName + const contentType = res.headers.get('content-type') || '' + const isImplicitHTML = + !cleanPagePath.endsWith('.html') && contentType.includes('html') + // && + // !JsonSigRx.test(dataBuff.subarray(0, 32).toString('utf8')) + const routeWithIndex = cleanPagePath.endsWith('/') + ? cleanPagePath + 'index' + : cleanPagePath + + const htmlPath = + cleanPagePath.endsWith('/') || prerenderOptions.autoSubfolderIndex + ? joinURL(cleanPagePath, 'index.html') + : cleanPagePath + '.html' + + const filename = withoutBase( + isImplicitHTML ? htmlPath : routeWithIndex, + nitro.options.baseURL, + ) + + const html = await res.text() + + const filepath = path.join(nitro.options.output.publicDir, filename) + + await fsp.mkdir(path.dirname(filepath), { + recursive: true, + }) + + await fsp.writeFile(filepath, html) + + const newPage = await prerenderOptions.onSuccess?.({ page, html }) + + if (newPage) { + Object.assign(page, newPage) + } + + // Find new links + if (prerenderOptions.crawlLinks ?? true) { + const links = extractLinks(html) + for (const link of links) { + addCrawlPageTask({ path: link, fromCrawl: true }) + } + } + } catch (error) { + if (retries < (prerenderOptions.retryCount ?? 0)) { + logger.warn(`Encountered error, retrying: ${page.path} in 500ms`) + await new Promise((resolve) => + setTimeout(resolve, prerenderOptions.retryDelay), + ) + retriesByPath.set(page.path, retries + 1) + addCrawlPageTask(page) + } else { + throw error + } + } + }) + } + } +} diff --git a/packages/start-plugin-core/src/queue.ts b/packages/start-plugin-core/src/queue.ts new file mode 100644 index 0000000000..279146fdb2 --- /dev/null +++ b/packages/start-plugin-core/src/queue.ts @@ -0,0 +1,153 @@ +interface PoolConfig { + concurrency?: number + started?: boolean + tasks?: Array<() => Promise> +} + +const defaultConfig: PoolConfig = { + concurrency: 5, + started: false, + tasks: [], +} + +export class Queue { + private onSettles: Array<(res: any, error: any) => void> = [] + private onErrors: Array<(error: any, task: () => Promise) => void> = [] + private onSuccesses: Array<(result: any, task: () => Promise) => void> = + [] + private running: boolean + private active: Array<() => Promise> = [] + private pending: Array<() => Promise> + private currentConcurrency: number + + constructor(config: PoolConfig = defaultConfig) { + const { concurrency, started, tasks } = { + ...defaultConfig, + ...config, + } + this.running = started! + this.pending = tasks as Array<() => Promise> + this.currentConcurrency = concurrency! + } + + private tick() { + if (!this.running) { + return + } + while ( + this.active.length < this.currentConcurrency && + this.pending.length + ) { + const nextFn = this.pending.shift() + if (!nextFn) { + throw new Error('Found task that is not a function') + } + this.active.push(nextFn) + ;(async () => { + let success = false + let res!: T + let error: any + try { + res = await nextFn() + success = true + } catch (e) { + error = e + } + this.active = this.active.filter((d) => d !== nextFn) + if (success) { + this.onSuccesses.forEach((d) => d(res, nextFn)) + } else { + this.onErrors.forEach((d) => d(error, nextFn)) + } + this.onSettles.forEach((d) => d(res, error)) + this.tick() + })() + } + } + + add(fn: () => Promise | T, { priority }: { priority?: boolean } = {}) { + return new Promise((resolve, reject) => { + const task = () => + Promise.resolve(fn()) + .then((res) => { + resolve(res) + return res + }) + .catch((err) => { + reject(err) + throw err + }) + if (priority) { + this.pending.unshift(task) + } else { + this.pending.push(task) + } + this.tick() + }) + } + + throttle(n: number) { + this.currentConcurrency = n + } + + onSettled(cb: () => void) { + this.onSettles.push(cb) + return () => { + this.onSettles = this.onSettles.filter((d) => d !== cb) + } + } + + onError(cb: (error: any, task: () => Promise) => void) { + this.onErrors.push(cb) + return () => { + this.onErrors = this.onErrors.filter((d) => d !== cb) + } + } + + onSuccess(cb: (result: any, task: () => Promise) => void) { + this.onSuccesses.push(cb) + return () => { + this.onSuccesses = this.onSuccesses.filter((d) => d !== cb) + } + } + + stop() { + this.running = false + } + + start() { + this.running = true + this.tick() + return new Promise((resolve) => { + this.onSettled(() => { + if (this.isSettled()) { + resolve() + } + }) + }) + } + + clear() { + this.pending = [] + } + + getActive() { + return this.active + } + + getPending() { + return this.pending + } + + getAll() { + return [...this.active, ...this.pending] + } + + isRunning() { + return this.running + } + + isSettled() { + return !this.active.length && !this.pending.length + } +} diff --git a/packages/start-plugin-core/src/routesManifestPlugin.ts b/packages/start-plugin-core/src/routesManifestPlugin.ts new file mode 100644 index 0000000000..c46dbb4577 --- /dev/null +++ b/packages/start-plugin-core/src/routesManifestPlugin.ts @@ -0,0 +1,220 @@ +import { readFileSync } from 'node:fs' +import path from 'node:path' +import { joinURL } from 'ufo' +import { rootRouteId } from '@tanstack/router-core' +import { resolveViteId } from './utils' +import type { + PluginOption, + ResolvedConfig, + Manifest as ViteManifest, + ManifestChunk as ViteManifestChunk, +} from 'vite' +import type { Manifest, RouterManagedTag } from '@tanstack/router-core' +import type { TanStackStartOutputConfig } from './plugin' + +export function startManifestPlugin( + opts: TanStackStartOutputConfig, +): PluginOption { + let config: ResolvedConfig + + const moduleId = 'tanstack-start-router-manifest:v' + const resolvedModuleId = resolveViteId(moduleId) + + return { + name: 'tsr-routes-manifest', + enforce: 'pre', + + configResolved(resolvedConfig) { + config = resolvedConfig + }, + // configEnvironment(env, envConfig) { + // config = envConfig. + // }, + resolveId(id) { + if (id === moduleId) { + return resolvedModuleId + } + return + }, + load(id) { + if (id === resolvedModuleId) { + if (this.environment.config.consumer !== 'server') { + // this will ultimately fail the build if the plugin is used outside the server environment + // TODO: do we need special handling for `serve`? + return `export default {}` + } + // If we're in development, return a dummy manifest + + if (config.command === 'serve') { + return `export const tsrStartManifest = () => ({ + entry: "$${process.env.TSS_CLIENT_BASE}/", + routes: {} + })` + } + + const clientViteManifestPath = path.resolve( + opts.root, + '.tanstack-start/build/client-dist/.vite/manifest.json', + ) + + let viteManifest: ViteManifest + try { + viteManifest = JSON.parse( + readFileSync(clientViteManifestPath, 'utf-8'), + ) + } catch (err) { + console.error(err) + throw new Error( + `Could not find the production client vite manifest at '${clientViteManifestPath}'!`, + ) + } + + const routeTreePath = path.resolve(opts.tsr.generatedRouteTree) + + let routeTreeContent: string + try { + routeTreeContent = readFileSync(routeTreePath, 'utf-8') + } catch (err) { + console.error(err) + throw new Error( + `Could not find the generated route tree at '${routeTreePath}'!`, + ) + } + + // Extract the routesManifest JSON from the route tree file. + // It's located between the /* ROUTE_MANIFEST_START and ROUTE_MANIFEST_END */ comment block. + + const routerManifest = JSON.parse( + routeTreeContent.match( + /\/\* ROUTE_MANIFEST_START([\s\S]*?)ROUTE_MANIFEST_END \*\//, + )?.[1] || '{ routes: {} }', + ) as Manifest + + const routes = routerManifest.routes + + let entryFile: ViteManifestChunk | undefined + + const filesByRouteFilePath: ViteManifest = Object.fromEntries( + Object.entries(viteManifest).map(([k, v]) => { + if (v.isEntry) { + entryFile = v + } + + const rPath = k.split('?')[0] + + return [rPath, v] + }, {}), + ) + + const routesDirectoryFromRoot = path.relative( + opts.root, + opts.tsr.routesDirectory, + ) + + // Add preloads to the routes from the vite manifest + Object.entries(routes).forEach(([k, v]) => { + const file = + filesByRouteFilePath[ + path.join(routesDirectoryFromRoot, v.filePath as string) + ] + + if (file) { + const preloads = (file.imports ?? []).map((d) => + path.join('/', viteManifest[d]!.file), + ) + + if (file.file) { + preloads.unshift(path.join('/', file.file)) + } + + const cssFiles = file.css ?? [] + const cssAssetsList: Array = cssFiles.map( + (cssFile) => ({ + tag: 'link', + attrs: { + rel: 'stylesheet', + href: joinURL('/', cssFile), + type: 'text/css', + }, + }), + ) + + routes[k] = { + ...v, + assets: [...(v.assets || []), ...cssAssetsList], + preloads, + } + } + }) + + if (entryFile) { + routes[rootRouteId]!.preloads = [ + path.join('/', entryFile.file), + ...(entryFile.imports?.map((d) => + path.join('/', viteManifest[d]!.file), + ) || []), + ] + + // Gather all the CSS files from the entry file in + // the `css` key and add them to the root route + const entryCssFiles = entryFile.css ?? [] + const entryCssAssetsList: Array = entryCssFiles.map( + (cssFile) => ({ + tag: 'link', + attrs: { + rel: 'stylesheet', + href: joinURL('/', cssFile), + type: 'text/css', + }, + }), + ) + + routes[rootRouteId]!.assets = [ + ...(routes[rootRouteId]!.assets || []), + ...entryCssAssetsList, + { + tag: 'script', + attrs: { + src: joinURL('/', entryFile.file), + type: 'module', + }, + }, + ] + } + + const recurseRoute = ( + route: { + preloads?: Array + children?: Array + }, + seenPreloads = {} as Record, + ) => { + route.preloads = route.preloads?.filter((preload) => { + if (seenPreloads[preload]) { + return false + } + seenPreloads[preload] = true + return true + }) + + if (route.children) { + route.children.forEach((child) => { + const childRoute = routes[child]! + recurseRoute(childRoute, { ...seenPreloads }) + }) + } + } + + // @ts-expect-error + recurseRoute(routes[rootRouteId]) + + const routesManifest = { + routes, + } + + return `export const tsrStartManifest = () => (${JSON.stringify(routesManifest)})` + } + return + }, + } +} diff --git a/packages/start-plugin-core/src/schema.ts b/packages/start-plugin-core/src/schema.ts new file mode 100644 index 0000000000..71e1420daa --- /dev/null +++ b/packages/start-plugin-core/src/schema.ts @@ -0,0 +1,220 @@ +import path from 'node:path' +import { existsSync } from 'node:fs' +import { z } from 'zod' +import { configSchema, getConfig } from '@tanstack/router-generator' +import type { NitroConfig } from 'nitropack' + +const tsrConfig = configSchema + .omit({ autoCodeSplitting: true }) + .partial() + .extend({ + srcDirectory: z.string().optional().default('src'), + }) + +export function createTanStackConfig< + TFrameworkPlugin extends Record, +>(frameworkPlugin?: TFrameworkPlugin) { + const schema = createTanStackStartOptionsSchema(frameworkPlugin) + + return { + schema, + parse: (opts?: z.input) => { + const options = schema.parse(opts) + + const srcDirectory = options.tsr.srcDirectory + + const routesDirectory = + options.tsr.routesDirectory ?? path.join(srcDirectory, 'routes') + + const generatedRouteTree = + options.tsr.generatedRouteTree ?? + path.join(srcDirectory, 'routeTree.gen.ts') + + const clientEntryPath = (() => { + if (options.client.entry) { + return path.join(srcDirectory, options.client.entry) + } + + if (existsSync(path.join(srcDirectory, 'client.tsx'))) { + return path.join(srcDirectory, 'client.tsx') + } + + return '/~start/default-client-entry' + })() + + const serverEntryPath = (() => { + if (options.server.entry) { + return path.join(srcDirectory, options.server.entry) + } + + if (existsSync(path.join(srcDirectory, 'server.tsx'))) { + return path.join(srcDirectory, 'server.tsx') + } + + if (existsSync(path.join(srcDirectory, 'server.ts'))) { + return path.join(srcDirectory, 'server.ts') + } + + if (existsSync(path.join(srcDirectory, 'server.js'))) { + return path.join(srcDirectory, 'server.js') + } + + return '/~start/default-server-entry' + })() + + return { + ...options, + tsr: { + ...options.tsr, + ...getConfig({ + ...options.tsr, + routesDirectory, + generatedRouteTree, + }), + }, + clientEntryPath, + serverEntryPath, + } + }, + } +} + +export function createTanStackStartOptionsSchema( + frameworkPlugin: Record = {}, +) { + return z + .object({ + root: z.string().optional().default(process.cwd()), + target: z.custom().optional(), + ...frameworkPlugin, + tsr: tsrConfig.optional().default({}), + client: z + .object({ + entry: z.string().optional(), + base: z.string().optional().default('/_build'), + }) + .optional() + .default({}), + server: z + .object({ + entry: z.string().optional(), + }) + .optional() + .default({}), + serverFns: z + .object({ + base: z.string().optional().default('/_serverFn'), + }) + .optional() + .default({}), + public: z + .object({ + dir: z.string().optional().default('public'), + base: z.string().optional().default('/'), + }) + .optional() + .default({}), + pages: z.array(pageSchema).optional().default([]), + sitemap: z + .object({ + enabled: z.boolean().optional().default(true), + host: z.string().optional(), + outputPath: z.string().optional().default('sitemap.xml'), + }) + .optional(), + prerender: z + .object({ + enabled: z.boolean().optional(), + concurrency: z.number().optional(), + filter: z.function().args(pageSchema).returns(z.any()).optional(), + failOnError: z.boolean().optional(), + }) + .and(pagePrerenderOptionsSchema.optional()) + .optional(), + spa: spaSchema.optional(), + }) + .optional() + .default({}) +} + +const pageSitemapOptionsSchema = z.object({ + exclude: z.boolean().optional(), + priority: z.number().min(0).max(1).optional(), + changefreq: z + .enum(['always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never']) + .optional(), + lastmod: z.union([z.string(), z.date()]).optional(), + alternateRefs: z + .array( + z.object({ + href: z.string(), + hreflang: z.string(), + }), + ) + .optional(), + images: z + .array( + z.object({ + loc: z.string(), + caption: z.string().optional(), + title: z.string().optional(), + }), + ) + .optional(), + news: z + .object({ + publication: z.object({ + name: z.string(), + language: z.string(), + }), + publicationDate: z.union([z.string(), z.date()]), + title: z.string(), + }) + .optional(), +}) + +const pageBaseSchema = z.object({ + path: z.string(), + sitemap: pageSitemapOptionsSchema.optional(), + fromCrawl: z.boolean().optional(), +}) + +const pagePrerenderOptionsSchema = z.object({ + enabled: z.boolean().optional(), + outputPath: z.string().optional(), + autoSubfolderIndex: z.boolean().optional(), + crawlLinks: z.boolean().optional(), + retryCount: z.number().optional(), + retryDelay: z.number().optional(), + onSuccess: z + .function() + .args( + z.object({ + page: pageBaseSchema, + html: z.string(), + }), + ) + .returns(z.any()) + .optional(), +}) + +const spaSchema = z.object({ + enabled: z.boolean().optional().default(true), + maskPath: z.string().optional().default('/'), + prerender: pagePrerenderOptionsSchema + .optional() + .default({}) + .transform((opts) => ({ + outputPath: opts.outputPath ?? '/_shell', + crawlLinks: false, + retryCount: 0, + ...opts, + enabled: true, + })), +}) + +export const pageSchema = pageBaseSchema.extend({ + prerender: pagePrerenderOptionsSchema.optional(), +}) + +export type Page = z.infer diff --git a/packages/start-plugin-core/src/start-compiler-plugin.ts b/packages/start-plugin-core/src/start-compiler-plugin.ts new file mode 100644 index 0000000000..e381536c4b --- /dev/null +++ b/packages/start-plugin-core/src/start-compiler-plugin.ts @@ -0,0 +1,111 @@ +import { fileURLToPath, pathToFileURL } from 'node:url' +import { logDiff } from '@tanstack/router-utils' + +import { compileStartOutputFactory } from './compilers' +import type { Plugin } from 'vite' +import type { CompileStartFrameworkOptions } from './compilers' + +const debug = + process.env.TSR_VITE_DEBUG && + ['true', 'start-plugin'].includes(process.env.TSR_VITE_DEBUG) + +export type TanStackStartViteOptions = { + globalMiddlewareEntry: string +} + +const transformFuncs = [ + 'createServerFn', + 'createMiddleware', + 'serverOnly', + 'clientOnly', + 'createIsomorphicFn', + 'createServerFileRoute', +] + +const tokenRegex = new RegExp(transformFuncs.join('|')) + +export function TanStackStartCompilerPlugin( + framework: CompileStartFrameworkOptions, + inputOpts?: { + client?: { + envName?: string + } + server?: { + envName?: string + } + }, +): Plugin { + const opts = { + client: { + envName: 'client', + ...inputOpts?.client, + }, + server: { + envName: 'server', + ...inputOpts?.server, + }, + } + + return { + name: 'vite-plugin-tanstack-start-create-server-fn', + enforce: 'pre', + applyToEnvironment(env) { + return [opts.client.envName, opts.server.envName].includes(env.name) + }, + transform(code, id) { + const env = + this.environment.name === opts.client.envName + ? 'client' + : this.environment.name === opts.server.envName + ? 'server' + : (() => { + throw new Error( + `Environment ${this.environment.name} not configured`, + ) + })() + + return transformCode({ + code, + id, + env, + framework, + }) + }, + } +} + +function transformCode(opts: { + code: string + id: string + env: 'server' | 'client' + framework: CompileStartFrameworkOptions +}) { + const { code, env, framework } = opts + let { id } = opts + + const url = pathToFileURL(id) + url.searchParams.delete('v') + id = fileURLToPath(url).replace(/\\/g, '/') + + const includesToken = tokenRegex.test(code) + + if (!includesToken) { + return null + } + + if (debug) console.info(`${env} Compiling Start: `, id) + + const compileStartOutput = compileStartOutputFactory(framework) + const compiled = compileStartOutput({ + code, + filename: id, + env, + }) + + if (debug) { + logDiff(code, compiled.code) + console.log('Output:\n', compiled.code + '\n\n') + } + + return compiled +} diff --git a/packages/start-plugin-core/src/start-server-routes-plugin/config.ts b/packages/start-plugin-core/src/start-server-routes-plugin/config.ts new file mode 100644 index 0000000000..d9fc413975 --- /dev/null +++ b/packages/start-plugin-core/src/start-server-routes-plugin/config.ts @@ -0,0 +1,8 @@ +import { baseConfigSchema } from '@tanstack/router-generator' +import { z } from 'zod' + +export const configSchema = baseConfigSchema.extend({ + srcDirectory: z.string().optional().default('src'), +}) + +export type Config = z.infer diff --git a/packages/start-plugin-core/src/start-server-routes-plugin/plugin.ts b/packages/start-plugin-core/src/start-server-routes-plugin/plugin.ts new file mode 100644 index 0000000000..0ff4bf0e1a --- /dev/null +++ b/packages/start-plugin-core/src/start-server-routes-plugin/plugin.ts @@ -0,0 +1,899 @@ +import path, { isAbsolute, join, normalize } from 'node:path' +import fs from 'node:fs' +import fsp from 'node:fs/promises' +import { + format, + logging, + multiSortBy, + physicalGetRouteNodes, + removeExt, + removeUnderscores, + replaceBackslash, + resetRegex, + rootPathId, + routePathToVariable, + trimPathLeft, + virtualGetRouteNodes, + writeIfDifferent, +} from '@tanstack/router-generator' +import { rootRouteId } from '@tanstack/router-core' +import { fillTemplate, getTargetTemplate } from './template' +import type { GetRouteNodesResult, RouteNode } from '@tanstack/router-generator' +import type { Config } from './config' +import type { Plugin } from 'vite' + +let lock = false +const checkLock = () => lock +const setLock = (bool: boolean) => { + lock = bool +} + +export function TanStackStartServerRoutesVite(config: Config): Plugin { + let ROOT: string = process.cwd() + const moduleId = 'tanstack-start-server-routes-manifest:v' + + const getRoutesDirectoryPath = () => { + return isAbsolute(config.routesDirectory) + ? config.routesDirectory + : join(ROOT, config.routesDirectory) + } + + const generate = async () => { + if (checkLock()) { + return + } + + setLock(true) + + try { + await generator(config, ROOT) + } catch (err) { + console.error(err) + console.info() + } finally { + setLock(false) + } + } + + const handleFile = async (file: string) => { + const filePath = normalize(file) + + const routesDirectoryPath = getRoutesDirectoryPath() + if (filePath.startsWith(routesDirectoryPath)) { + await generate() + } + } + + return { + name: 'tanstack-start-server-routes-plugin', + configureServer(server) { + server.watcher.on('all', (event, path) => { + handleFile(path) + }) + }, + configResolved(config) { + ROOT = config.root + }, + async buildStart() { + await generate() + // if (this.environment.name === 'server') { + // } + }, + sharedDuringBuild: true, + resolveId(id) { + if (id === moduleId) { + const generatedRouteTreePath = getGeneratedRouteTreePath(ROOT) + return generatedRouteTreePath + } + return null + }, + } +} + +// Maybe import this from `@tanstack/router-core` in the future??? +let latestTask = 0 +const routeGroupPatternRegex = /\(.+\)/g +const possiblyNestedRouteGroupPatternRegex = /\([^/]+\)\/?/g + +let isFirst = false +let skipMessage = false + +function getGeneratedRouteTreePath(root: string) { + return path.resolve(root, '.tanstack-start/server-routes/routeTree.gen.ts') +} + +async function generator(config: Config, root: string) { + const generatedServerRouteTreePath = getGeneratedRouteTreePath(root) + const ROUTE_TEMPLATE = getTargetTemplate(config.target) + const logger = logging({ disabled: config.disableLogging }) + + if (!isFirst) { + // logger.log('♻️ Generating server routes...') + isFirst = true + } else if (skipMessage) { + skipMessage = false + } else { + // logger.log('♻️ Regenerating server routes...') + } + + const taskId = latestTask + 1 + latestTask = taskId + + const checkLatest = () => { + if (latestTask !== taskId) { + skipMessage = true + return false + } + + return true + } + + const start = Date.now() + + let getRouteNodesResult: GetRouteNodesResult + + if (config.virtualRouteConfig) { + getRouteNodesResult = await virtualGetRouteNodes(config, root) + } else { + getRouteNodesResult = await physicalGetRouteNodes(config, root) + } + + const { rootRouteNode, routeNodes: beforeRouteNodes } = getRouteNodesResult + if (rootRouteNode === undefined) { + let errorMessage = `rootRouteNode must not be undefined. Make sure you've added your root route into the route-tree.` + if (!config.virtualRouteConfig) { + errorMessage += `\nMake sure that you add a "${rootPathId}.tsx" file to your routes directory.\nAdd the file in: "${config.routesDirectory}/${rootPathId}.tsx"` + } + throw new Error(errorMessage) + } + + const preRouteNodes = multiSortBy(beforeRouteNodes, [ + (d) => (d.routePath === '/' ? -1 : 1), + (d) => d.routePath?.split('/').length, + (d) => + d.filePath.match(new RegExp(`[./]${config.indexToken}[.]`)) ? 1 : -1, + (d) => + d.filePath.match( + /[./](component|errorComponent|pendingComponent|loader|lazy)[.]/, + ) + ? 1 + : -1, + (d) => + d.filePath.match(new RegExp(`[./]${config.routeToken}[.]`)) ? -1 : 1, + (d) => (d.routePath?.endsWith('/') ? -1 : 1), + (d) => d.routePath, + ]).filter((d) => ![`/${rootPathId}`].includes(d.routePath || '')) + + const routeTree: Array = [] + + // Loop over the flat list of routeNodes and + // build up a tree based on the routeNodes' routePath + const routeNodes: Array = [] + + // the handleRootNode function is not being collapsed into the handleNode function + // because it requires only a subset of the logic that the handleNode function requires + // and it's easier to read and maintain this way + const handleRootNode = async (node?: RouteNode) => { + if (!node) { + // currently this is not being handled, but it could be in the future + // for example to handle a virtual root route + return + } + + // from here on, we are only handling the root node that's present in the file system + const routeCode = fs.readFileSync(node.fullPath, 'utf-8') + + if (!routeCode) { + const _rootTemplate = ROUTE_TEMPLATE.rootRoute + const replaced = await fillTemplate(config, _rootTemplate.template(), { + tsrImports: _rootTemplate.imports.tsrImports(), + tsrPath: rootPathId, + tsrExportStart: _rootTemplate.imports.tsrExportStart(), + tsrExportEnd: _rootTemplate.imports.tsrExportEnd(), + }) + + await writeIfDifferent( + node.fullPath, + '', // Empty string because the file doesn't exist yet + replaced, + { + beforeWrite: () => { + // logger.log(`🟡 Creating ${node.fullPath}`) + }, + }, + ) + } + } + + await handleRootNode(rootRouteNode) + + const handleNode = async (node: RouteNode) => { + // Do not remove this as we need to set the lastIndex to 0 as it + // is necessary to reset the regex's index when using the global flag + // otherwise it might not match the next time it's used + resetRegex(routeGroupPatternRegex) + + let parentRoute = hasParentRoute(routeNodes, node, node.routePath) + + // if the parent route is a virtual parent route, we need to find the real parent route + if (parentRoute?.isVirtualParentRoute && parentRoute.children?.length) { + // only if this sub-parent route returns a valid parent route, we use it, if not leave it as it + const possibleParentRoute = hasParentRoute( + parentRoute.children, + node, + node.routePath, + ) + if (possibleParentRoute) { + parentRoute = possibleParentRoute + } + } + + if (parentRoute) node.parent = parentRoute + + node.path = determineNodePath(node) + + const trimmedPath = trimPathLeft(node.path ?? '') + + const split = trimmedPath.split('/') + const lastRouteSegment = split[split.length - 1] ?? trimmedPath + + node.isNonPath = + lastRouteSegment.startsWith('_') || + routeGroupPatternRegex.test(lastRouteSegment) + + node.cleanedPath = removeGroups( + removeUnderscores(removeLayoutSegments(node.path)) ?? '', + ) + + const routeCode = node.fullPath + ? fs.readFileSync(node.fullPath, 'utf-8') + : '' + + // Ensure the boilerplate for the route exists, which can be skipped for virtual parent routes and virtual routes + if (!node.isVirtualParentRoute && !node.isVirtual) { + // const escapedRoutePath = node.routePath?.replaceAll('$', '$$') ?? '' + // let replaced = routeCode + // await writeIfDifferent(node.fullPath, routeCode, replaced, { + // beforeWrite: () => { + // // logger.log(`🟡 Updating ${node.fullPath}`) + // }, + // }) + } + + const cleanedPathIsEmpty = (node.cleanedPath || '').length === 0 + const nonPathRoute = + node._fsRouteType === 'pathless_layout' && node.isNonPath + + node.isVirtualParentRequired = + node._fsRouteType === 'pathless_layout' || nonPathRoute + ? !cleanedPathIsEmpty + : false + + if (!node.isVirtual && node.isVirtualParentRequired) { + const parentRoutePath = removeLastSegmentFromPath(node.routePath) || '/' + const parentVariableName = routePathToVariable(parentRoutePath) + + const anchorRoute = routeNodes.find( + (d) => d.routePath === parentRoutePath, + ) + + if (!anchorRoute) { + const parentNode: RouteNode = { + ...node, + path: removeLastSegmentFromPath(node.path) || '/', + filePath: removeLastSegmentFromPath(node.filePath) || '/', + fullPath: removeLastSegmentFromPath(node.fullPath) || '/', + routePath: parentRoutePath, + variableName: parentVariableName, + isVirtual: true, + _fsRouteType: 'layout', // layout since this route will wrap other routes + isVirtualParentRoute: true, + isVirtualParentRequired: false, + } + + parentNode.children = parentNode.children ?? [] + parentNode.children.push(node) + + node.parent = parentNode + + if (node._fsRouteType === 'pathless_layout') { + // since `node.path` is used as the `id` on the route definition, we need to update it + node.path = determineNodePath(node) + } + + await handleNode(parentNode) + } else { + anchorRoute.children = anchorRoute.children ?? [] + anchorRoute.children.push(node) + + node.parent = anchorRoute + } + } + + if ( + !routeCode + .split('\n') + .some((line) => line.trim().startsWith('export const ServerRoute')) + ) { + return + } + + if (node.parent) { + if (!node.isVirtualParentRequired) { + node.parent.children = node.parent.children ?? [] + node.parent.children.push(node) + } + } else { + routeTree.push(node) + } + + routeNodes.push(node) + } + + for (const node of preRouteNodes) { + await handleNode(node) + } + + // This is run against the `routeNodes` array since it + // has the accumulated (intended) Server Route nodes + // Since TSR allows multiple way of defining a route, + // we need to ensure that a user hasn't defined the + // same route in multiple ways (i.e. `flat`, `nested`, `virtual`) + checkRouteFullPathUniqueness(routeNodes, config) + + function buildRouteTreeConfig(nodes: Array, depth = 1): string { + const children = nodes.map((node) => { + if (node._fsRouteType === '__root') { + return + } + + if (node._fsRouteType === 'pathless_layout' && !node.children?.length) { + return + } + + const route = `${node.variableName}Route` + + if (node.children?.length) { + const childConfigs = buildRouteTreeConfig(node.children, depth + 1) + + const childrenDeclaration = `interface ${route}Children { + ${node.children.map((child) => `${child.variableName}Route: typeof ${getResolvedRouteNodeVariableName(child)}`).join(',')} +}` + + const children = `const ${route}Children: ${route}Children = { + ${node.children.map((child) => `${child.variableName}Route: ${getResolvedRouteNodeVariableName(child)}`).join(',')} +}` + + const routeWithChildren = `const ${route}WithChildren = ${route}._addFileChildren(${route}Children)` + + return [ + childConfigs, + childrenDeclaration, + children, + routeWithChildren, + ].join('\n\n') + } + + return undefined + }) + + return children.filter(Boolean).join('\n\n') + } + + const routeConfigChildrenText = buildRouteTreeConfig(routeTree) + + const sortedRouteNodes = multiSortBy(routeNodes, [ + (d) => (d.routePath?.includes(`/${rootPathId}`) ? -1 : 1), + (d) => d.routePath?.split('/').length, + (d) => (d.routePath?.endsWith(config.indexToken) ? -1 : 1), + (d) => d, + ]) + + const imports = Object.entries({ + createFileRoute: sortedRouteNodes.some((d) => d.isVirtual), + }) + .filter((d) => d[1]) + .map((d) => d[0]) + + const virtualRouteNodes = sortedRouteNodes.filter((d) => d.isVirtual) + + function getImportPath(node: RouteNode) { + return replaceBackslash( + removeExt( + path.relative( + path.dirname(generatedServerRouteTreePath), + path.resolve(config.routesDirectory, node.filePath), + ), + ), + ) + } + + const rootRouteExists = fs.existsSync(rootRouteNode.fullPath) + const rootRouteCode = rootRouteExists + ? fs.readFileSync(rootRouteNode.fullPath, 'utf-8') + : '' + const hasServerRootRoute = + rootRouteExists && rootRouteCode.includes('export const ServerRoute') + + const routeImports = [ + ...config.routeTreeFileHeader, + `// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.`, + imports.length + ? `import { ${imports.join(', ')} } from '${ROUTE_TEMPLATE.fullPkg}'\n` + : '', + '// Import Routes', + [ + `import type { FileRoutesByPath, CreateServerFileRoute } from '${ROUTE_TEMPLATE.fullPkg}'`, + `import { createServerRoute, createServerFileRoute } from '${ROUTE_TEMPLATE.fullPkg}'`, + hasServerRootRoute + ? `import { ServerRoute as rootRouteImport } from './${getImportPath(rootRouteNode)}'` + : '', + ...sortedRouteNodes + .filter((d) => !d.isVirtual) + .map((node) => { + return `import { ServerRoute as ${ + node.variableName + }RouteImport } from './${getImportPath(node)}'` + }), + ].join('\n'), + virtualRouteNodes.length ? '// Create Virtual Routes' : '', + virtualRouteNodes + .map((node) => { + return `const ${ + node.variableName + }RouteImport = createFileRoute('${node.routePath}')()` + }) + .join('\n'), + '// Create/Update Routes', + !hasServerRootRoute + ? ` + const rootRoute = createServerRoute() + ` + : '', + sortedRouteNodes + .map((node) => { + return [ + [ + `const ${node.variableName}Route = ${node.variableName}RouteImport.update({ + ${[ + `id: '${node.path}'`, + !node.isNonPath ? `path: '${node.cleanedPath}'` : undefined, + `getParentRoute: () => ${node.parent?.variableName ?? 'root'}Route`, + ] + .filter(Boolean) + .join(',')} + } as any)`, + ].join(''), + ].join('\n\n') + }) + .join('\n\n'), + '', + + '// Populate the FileRoutesByPath interface', + `declare module '${ROUTE_TEMPLATE.fullPkg}' { + interface FileRoutesByPath { + ${routeNodes + .map((routeNode) => { + const filePathId = routeNode.routePath + + return `'${filePathId}': { + id: '${filePathId}' + path: '${inferPath(routeNode)}' + fullPath: '${inferFullPath(routeNode)}' + preLoaderRoute: typeof ${routeNode.variableName}RouteImport + parentRoute: typeof ${ + routeNode.isVirtualParentRequired + ? `${routeNode.parent?.variableName}Route` + : routeNode.parent?.variableName + ? `${routeNode.parent.variableName}RouteImport` + : 'rootRoute' + } + }` + }) + .join('\n')} + } +}`, + `// Add type-safety to the createFileRoute function across the route tree`, + routeNodes + .map((routeNode) => { + return `declare module './${getImportPath(routeNode)}' { +const createServerFileRoute: CreateServerFileRoute< +FileRoutesByPath['${routeNode.routePath}']['parentRoute'], +FileRoutesByPath['${routeNode.routePath}']['id'], +FileRoutesByPath['${routeNode.routePath}']['path'], +FileRoutesByPath['${routeNode.routePath}']['fullPath'], +${routeNode.children?.length ? `${routeNode.variableName}RouteChildren` : 'unknown'} +> +}` + }) + .join('\n'), + '// Create and export the route tree', + routeConfigChildrenText, + `export interface FileRoutesByFullPath { + ${[...createRouteNodesByFullPath(routeNodes).entries()].map( + ([fullPath, routeNode]) => { + return `'${fullPath}': typeof ${getResolvedRouteNodeVariableName(routeNode)}` + }, + )} +}`, + `export interface FileRoutesByTo { + ${[...createRouteNodesByTo(routeNodes).entries()].map(([to, routeNode]) => { + return `'${to}': typeof ${getResolvedRouteNodeVariableName(routeNode)}` + })} +}`, + `export interface FileRoutesById { + '${rootRouteId}': typeof rootRoute, + ${[...createRouteNodesById(routeNodes).entries()].map(([id, routeNode]) => { + return `'${id}': typeof ${getResolvedRouteNodeVariableName(routeNode)}` + })} +}`, + `export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: ${routeNodes.length > 0 ? [...createRouteNodesByFullPath(routeNodes).keys()].map((fullPath) => `'${fullPath}'`).join('|') : 'never'} + fileRoutesByTo: FileRoutesByTo + to: ${routeNodes.length > 0 ? [...createRouteNodesByTo(routeNodes).keys()].map((to) => `'${to}'`).join('|') : 'never'} + id: ${[`'${rootRouteId}'`, ...[...createRouteNodesById(routeNodes).keys()].map((id) => `'${id}'`)].join('|')} + fileRoutesById: FileRoutesById +}`, + `export interface RootRouteChildren { + ${routeTree.map((child) => `${child.variableName}Route: typeof ${getResolvedRouteNodeVariableName(child)}`).join(',')} +}`, + `const rootRouteChildren: RootRouteChildren = { + ${routeTree.map((child) => `${child.variableName}Route: ${getResolvedRouteNodeVariableName(child)}`).join(',')} +}`, + `export const routeTree = rootRoute._addFileChildren(rootRouteChildren)._addFileTypes()`, + ] + .filter(Boolean) + .join('\n\n') + + const createRouteManifest = () => { + const routesManifest = { + [rootRouteId]: { + filePath: rootRouteNode.filePath, + children: routeTree.map((d) => d.routePath), + }, + ...Object.fromEntries( + routeNodes.map((d) => { + const filePathId = d.routePath + + return [ + filePathId, + { + filePath: d.filePath, + parent: d.parent?.routePath ? d.parent.routePath : undefined, + children: d.children?.map((childRoute) => childRoute.routePath), + }, + ] + }), + ), + } + + return JSON.stringify( + { + routes: routesManifest, + }, + null, + 2, + ) + } + + const includeManifest = ['react', 'solid'] + const routeConfigFileContent = !includeManifest.includes(config.target) + ? routeImports + : [ + routeImports, + '\n', + '/* ROUTE_MANIFEST_START', + createRouteManifest(), + 'ROUTE_MANIFEST_END */', + ].join('\n') + + if (!checkLatest()) return + + const existingRouteTreeContent = await fsp + .readFile(path.resolve(generatedServerRouteTreePath), 'utf-8') + .catch((err) => { + if (err.code === 'ENOENT') { + return '' + } + + throw err + }) + + if (!checkLatest()) return + + // Ensure the directory exists + await fsp.mkdir(path.dirname(path.resolve(generatedServerRouteTreePath)), { + recursive: true, + }) + + if (!checkLatest()) return + + // Write the route tree file, if it has changed + const routeTreeWriteResult = await writeIfDifferent( + path.resolve(generatedServerRouteTreePath), + await format(existingRouteTreeContent, config), + await format(routeConfigFileContent, config), + { + beforeWrite: () => { + // logger.log(`🟡 Updating ${generatedRouteTreePath}`) + }, + }, + ) + + // Write declaration file + const startDeclarationFilePath = path.join( + path.resolve(root, config.srcDirectory), + 'tanstack-start.d.ts', + ) + const serverRoutesRelativePath = removeExt( + path.relative( + path.dirname(startDeclarationFilePath), + generatedServerRouteTreePath, + ), + ) + const startDeclarationFileContent = buildStartDeclarationFile({ + serverRoutesRelativePath, + }) + if (!fs.existsSync(startDeclarationFilePath)) { + await writeIfDifferent( + startDeclarationFilePath, + '', + startDeclarationFileContent, + { + beforeWrite: () => { + logger.log(`🟡 Creating tanstack-start.d.ts`) + }, + }, + ) + } else { + const existingDeclarationFileContent = await fsp + .readFile(startDeclarationFilePath, 'utf-8') + .catch((err) => { + if (err.code === 'ENOENT') { + return '' + } + throw err + }) + await writeIfDifferent( + startDeclarationFilePath, + existingDeclarationFileContent, + startDeclarationFileContent, + { + beforeWrite: () => { + logger.log(`🟡 Updating tanstack-start.d.ts`) + }, + }, + ) + } + + if (routeTreeWriteResult && !checkLatest()) { + return + } + + // logger.log( + // `✅ Processed ${routeNodes.length === 1 ? 'server route' : 'server routes'} in ${ + // Date.now() - start + // }ms`, + // ) +} + +function buildStartDeclarationFile({ + serverRoutesRelativePath, +}: { + serverRoutesRelativePath: string +}) { + const serverRoutesPath = replaceBackslash(serverRoutesRelativePath) + return ( + [ + '/// ', + `import '${serverRoutesPath}'`, + ].join('\n') + '\n' + ) +} + +function removeGroups(s: string) { + return s.replace(possiblyNestedRouteGroupPatternRegex, '') +} + +/** + * 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. + * @param node - The node to determine the path for. + * @returns The correct path for the given node. + */ +function determineNodePath(node: RouteNode) { + return (node.path = node.parent + ? node.routePath?.replace(node.parent.routePath ?? '', '') || '/' + : node.routePath) +} + +/** + * Removes the last segment from a given path. Segments are considered to be separated by a '/'. + * + * @param {string} routePath - The path from which to remove the last segment. Defaults to '/'. + * @returns {string} The path with the last segment removed. + * @example + * removeLastSegmentFromPath('/workspace/_auth/foo') // '/workspace/_auth' + */ +function removeLastSegmentFromPath(routePath: string = '/'): string { + const segments = routePath.split('/') + segments.pop() // Remove the last segment + return segments.join('/') +} + +/** + * Removes all segments from a given path that start with an underscore ('_'). + * + * @param {string} routePath - The path from which to remove segments. Defaults to '/'. + * @returns {string} The path with all underscore-prefixed segments removed. + * @example + * removeLayoutSegments('/workspace/_auth/foo') // '/workspace/foo' + */ +function removeLayoutSegments(routePath: string = '/'): string { + const segments = routePath.split('/') + const newSegments = segments.filter((segment) => !segment.startsWith('_')) + return newSegments.join('/') +} + +function hasParentRoute( + routes: Array, + node: RouteNode, + routePathToCheck: string | undefined, +): RouteNode | null { + if (!routePathToCheck || routePathToCheck === '/') { + return null + } + + const sortedNodes = multiSortBy(routes, [ + (d) => d.routePath!.length * -1, + (d) => d.variableName, + ]).filter((d) => d.routePath !== `/${rootPathId}`) + + for (const route of sortedNodes) { + if (route.routePath === '/') continue + + if ( + routePathToCheck.startsWith(`${route.routePath}/`) && + route.routePath !== routePathToCheck + ) { + return route + } + } + + const segments = routePathToCheck.split('/') + segments.pop() // Remove the last segment + const parentRoutePath = segments.join('/') + + return hasParentRoute(routes, node, parentRoutePath) +} + +/** + * Gets the final variable name for a route + */ +const getResolvedRouteNodeVariableName = (routeNode: RouteNode): string => { + return routeNode.children?.length + ? `${routeNode.variableName}RouteWithChildren` + : `${routeNode.variableName}Route` +} + +/** + * Creates a map from fullPath to routeNode + */ +const createRouteNodesByFullPath = ( + routeNodes: Array, +): Map => { + return new Map( + routeNodes.map((routeNode) => [inferFullPath(routeNode), routeNode]), + ) +} + +/** + * Create a map from 'to' to a routeNode + */ +const createRouteNodesByTo = ( + routeNodes: Array, +): Map => { + return new Map( + dedupeBranchesAndIndexRoutes(routeNodes).map((routeNode) => [ + inferTo(routeNode), + routeNode, + ]), + ) +} + +/** + * Create a map from 'id' to a routeNode + */ +const createRouteNodesById = ( + routeNodes: Array, +): Map => { + return new Map( + routeNodes.map((routeNode) => { + const id = routeNode.routePath ?? '' + return [id, routeNode] + }), + ) +} + +/** + * Infers the full path for use by TS + */ +const inferFullPath = (routeNode: RouteNode): string => { + const fullPath = removeGroups( + removeUnderscores(removeLayoutSegments(routeNode.routePath)) ?? '', + ) + + return routeNode.cleanedPath === '/' ? fullPath : fullPath.replace(/\/$/, '') +} + +/** + * Infers the path for use by TS + */ +const inferPath = (routeNode: RouteNode): string => { + return routeNode.cleanedPath === '/' + ? routeNode.cleanedPath + : (routeNode.cleanedPath?.replace(/\/$/, '') ?? '') +} + +/** + * Infers to path + */ +const inferTo = (routeNode: RouteNode): string => { + const fullPath = inferFullPath(routeNode) + + if (fullPath === '/') return fullPath + + return fullPath.replace(/\/$/, '') +} + +/** + * Dedupes branches and index routes + */ +const dedupeBranchesAndIndexRoutes = ( + routes: Array, +): Array => { + return routes.filter((route) => { + if (route.children?.find((child) => child.cleanedPath === '/')) return false + return true + }) +} + +function checkUnique(routes: Array, key: keyof TElement) { + // Check no two routes have the same `key` + // if they do, throw an error with the conflicting filePaths + const keys = routes.map((d) => d[key]) + const uniqueKeys = new Set(keys) + if (keys.length !== uniqueKeys.size) { + const duplicateKeys = keys.filter((d, i) => keys.indexOf(d) !== i) + const conflictingFiles = routes.filter((d) => + duplicateKeys.includes(d[key]), + ) + return conflictingFiles + } + return undefined +} + +function checkRouteFullPathUniqueness( + _routes: Array, + config: Config, +) { + const routes = _routes.map((d) => { + const inferredFullPath = inferFullPath(d) + return { ...d, inferredFullPath } + }) + + const conflictingFiles = checkUnique(routes, 'inferredFullPath') + + if (conflictingFiles !== undefined) { + const errorMessage = `Conflicting configuration paths were found for the following route${conflictingFiles.length > 1 ? 's' : ''}: ${conflictingFiles + .map((p) => `"${p.inferredFullPath}"`) + .join(', ')}. +Please ensure each Server Route has a unique full path. +Conflicting files: \n ${conflictingFiles.map((d) => path.resolve(config.routesDirectory, d.filePath)).join('\n ')}\n` + console.error(errorMessage) + process.exit(1) + } +} diff --git a/packages/start-plugin-core/src/start-server-routes-plugin/template.ts b/packages/start-plugin-core/src/start-server-routes-plugin/template.ts new file mode 100644 index 0000000000..9599efeb2a --- /dev/null +++ b/packages/start-plugin-core/src/start-server-routes-plugin/template.ts @@ -0,0 +1,164 @@ +import { format } from '@tanstack/router-generator' +import type { Config } from './config' + +type TemplateTag = 'tsrImports' | 'tsrPath' | 'tsrExportStart' | 'tsrExportEnd' + +export function fillTemplate( + config: Config, + template: string, + values: Record, +) { + const replaced = template.replace( + /%%(\w+)%%/g, + (_, key) => values[key as TemplateTag] || '', + ) + return format(replaced, config) +} + +type TargetTemplate = { + fullPkg: string + subPkg: string + rootRoute: { + template: () => string + imports: { + tsrImports: () => string + tsrExportStart: () => string + tsrExportEnd: () => string + } + } + route: { + template: () => string + imports: { + tsrImports: () => string + tsrExportStart: (routePath: string) => string + tsrExportEnd: () => string + } + } + lazyRoute: { + template: () => string + imports: { + tsrImports: () => string + tsrExportStart: (routePath: string) => string + tsrExportEnd: () => string + } + } +} + +export function getTargetTemplate(target: Config['target']): TargetTemplate { + switch (target) { + // TODO: Remove this disabled eslint rule when more target types are added. + + case 'react': + return { + fullPkg: '@tanstack/react-start/server', + subPkg: 'react-start/server', + // TODO: Clean this up if it's not used + rootRoute: { + template: () => + [ + 'import * as React from "react"\n', + '%%tsrImports%%', + '\n\n', + '%%tsrExportStart%%{\n component: RootComponent\n }%%tsrExportEnd%%\n\n', + 'function RootComponent() { return (
Hello "%%tsrPath%%"!
) };\n', + ].join(''), + imports: { + tsrImports: () => + "import { Outlet, createRootRoute } from '@tanstack/react-router';", + tsrExportStart: () => 'export const Route = createRootRoute(', + tsrExportEnd: () => ');', + }, + }, + route: { + template: () => + [ + '%%tsrImports%%', + '\n\n', + '%%tsrExportStart%%{\n component: RouteComponent\n }%%tsrExportEnd%%\n\n', + 'function RouteComponent() { return
Hello "%%tsrPath%%"!
};\n', + ].join(''), + imports: { + tsrImports: () => '', + tsrExportStart: () => `export const Route = createFileRoute(`, + tsrExportEnd: () => ');', + }, + }, + lazyRoute: { + template: () => + [ + '%%tsrImports%%', + '\n\n', + '%%tsrExportStart%%{\n component: RouteComponent\n }%%tsrExportEnd%%\n\n', + 'function RouteComponent() { return
Hello "%%tsrPath%%"!
};\n', + ].join(''), + imports: { + tsrImports: () => + "import { createLazyFileRoute } from '@tanstack/react-router';", + tsrExportStart: (routePath) => + `export const Route = createLazyFileRoute('${routePath}')(`, + tsrExportEnd: () => ');', + }, + }, + } + case 'solid': + return { + fullPkg: '@tanstack/solid-start/server', + subPkg: 'solid-start/server', + rootRoute: { + template: () => + [ + 'import * as Solid from "solid-js"\n', + '%%tsrImports%%', + '\n\n', + '%%tsrExportStart%%{\n component: RootComponent\n }%%tsrExportEnd%%\n\n', + 'function RootComponent() { return (<>
Hello "%%tsrPath%%"!
) };\n', + ].join(''), + imports: { + tsrImports: () => + "import { Outlet, createRootRoute } from '@tanstack/solid-router';", + tsrExportStart: () => 'export const Route = createRootRoute(', + tsrExportEnd: () => ');', + }, + }, + route: { + template: () => + [ + '%%tsrImports%%', + '\n\n', + '%%tsrExportStart%%{\n component: RouteComponent\n }%%tsrExportEnd%%\n\n', + 'function RouteComponent() { return
Hello "%%tsrPath%%"!
};\n', + ].join(''), + imports: { + tsrImports: () => '', + tsrExportStart: () => `export const Route = createFileRoute(`, + tsrExportEnd: () => ');', + }, + }, + lazyRoute: { + template: () => + [ + '%%tsrImports%%', + '\n\n', + '%%tsrExportStart%%{\n component: RouteComponent\n }%%tsrExportEnd%%\n\n', + 'function RouteComponent() { return
Hello "%%tsrPath%%"!
};\n', + ].join(''), + imports: { + tsrImports: () => + "import { createLazyFileRoute } from '@tanstack/solid-router';", + tsrExportStart: (routePath) => + `export const Route = createLazyFileRoute('${routePath}')(`, + tsrExportEnd: () => ');', + }, + }, + } + default: + throw new Error(`router-generator: Unknown target type: ${target}`) + } +} + +export const defaultServerRouteTemplate = [ + 'import { json } from "@tanstack/react-start";\n', + '%%tsrImports%%', + '\n\n', + '%%tsrExportStart%%{ GET: ({ request, params }) => { return json({ message:\'Hello "%%tsrPath%%"!\' }) }}%%tsrExportEnd%%\n', +].join('') diff --git a/packages/start-plugin-core/src/utils.ts b/packages/start-plugin-core/src/utils.ts new file mode 100644 index 0000000000..252712ef66 --- /dev/null +++ b/packages/start-plugin-core/src/utils.ts @@ -0,0 +1,14 @@ +export function resolveViteId(id: string) { + return `\0${id}` +} + +export function createLogger(prefix: string) { + const label = `[${prefix}]` + return { + log: (...args: any) => console.log(label, ...args), + debug: (...args: any) => console.debug(label, ...args), + info: (...args: any) => console.info(label, ...args), + warn: (...args: any) => console.warn(label, ...args), + error: (...args: any) => console.error(label, ...args), + } +} diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/createIsomorphicFn.test.ts b/packages/start-plugin-core/tests/createIsomorphicFn/createIsomorphicFn.test.ts similarity index 93% rename from packages/react-start-plugin/tests/createIsomorphicFn/createIsomorphicFn.test.ts rename to packages/start-plugin-core/tests/createIsomorphicFn/createIsomorphicFn.test.ts index 32a31d401c..249a3851fc 100644 --- a/packages/react-start-plugin/tests/createIsomorphicFn/createIsomorphicFn.test.ts +++ b/packages/start-plugin-core/tests/createIsomorphicFn/createIsomorphicFn.test.ts @@ -2,7 +2,9 @@ import { readFile, readdir } from 'node:fs/promises' import path from 'node:path' import { afterAll, describe, expect, test, vi } from 'vitest' -import { compileStartOutput } from '../../src/compilers' +import { compileStartOutputFactory } from '../../src/compilers' + +const compileStartOutput = compileStartOutputFactory('react') async function getFilenames() { return await readdir(path.resolve(import.meta.dirname, './test-files')) @@ -39,7 +41,6 @@ describe('createIsomorphicFn compiles correctly', async () => { const compiledResult = compileStartOutput({ env, code, - root: './test-files', filename, dce: false, }) @@ -57,7 +58,6 @@ describe('createIsomorphicFn compiles correctly', async () => { code: ` import { createIsomorphicFn } from '@tanstack/react-start' const clientOnly = createIsomorphicFn().client()`, - root: './test-files', filename: 'no-fn.ts', dce: false, }) @@ -68,7 +68,6 @@ describe('createIsomorphicFn compiles correctly', async () => { code: ` import { createIsomorphicFn } from '@tanstack/react-start' const serverOnly = createIsomorphicFn().server()`, - root: './test-files', filename: 'no-fn.ts', dce: false, }) @@ -80,7 +79,6 @@ describe('createIsomorphicFn compiles correctly', async () => { code: ` import { createIsomorphicFn } from '@tanstack/react-start' const noImpl = createIsomorphicFn()`, - root: './test-files', filename: 'no-fn.ts', dce: false, }) diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx diff --git a/packages/solid-start-plugin/tests/createMiddleware/createMiddleware.test.ts b/packages/start-plugin-core/tests/createMiddleware/createMiddleware.test.ts similarity index 88% rename from packages/solid-start-plugin/tests/createMiddleware/createMiddleware.test.ts rename to packages/start-plugin-core/tests/createMiddleware/createMiddleware.test.ts index 05d57dd32d..92af2feb31 100644 --- a/packages/solid-start-plugin/tests/createMiddleware/createMiddleware.test.ts +++ b/packages/start-plugin-core/tests/createMiddleware/createMiddleware.test.ts @@ -2,7 +2,9 @@ import { readFile, readdir } from 'node:fs/promises' import path from 'node:path' import { describe, expect, test } from 'vitest' -import { compileStartOutput } from '../../src/compilers' +import { compileStartOutputFactory } from '../../src/compilers' + +const compileStartOutput = compileStartOutputFactory('react') async function getFilenames() { return await readdir(path.resolve(import.meta.dirname, './test-files')) @@ -23,7 +25,6 @@ describe('createMiddleware compiles correctly', async () => { const compiledResult = compileStartOutput({ env, code, - root: './test-files', filename, dce: false, }) diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx b/packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx rename to packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx b/packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx rename to packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx b/packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx rename to packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareValidator.tsx b/packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareValidator.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareValidator.tsx rename to packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareValidator.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/createServerFn.test.ts b/packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts similarity index 95% rename from packages/react-start-plugin/tests/createServerFn/createServerFn.test.ts rename to packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts index 5c93ae90bc..c8c013dc99 100644 --- a/packages/react-start-plugin/tests/createServerFn/createServerFn.test.ts +++ b/packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts @@ -2,7 +2,9 @@ import { readFile, readdir } from 'node:fs/promises' import path from 'node:path' import { describe, expect, test } from 'vitest' -import { compileStartOutput } from '../../src/compilers' +import { compileStartOutputFactory } from '../../src/compilers' + +const compileStartOutput = compileStartOutputFactory('react') async function getFilenames() { return await readdir(path.resolve(import.meta.dirname, './test-files')) @@ -23,7 +25,6 @@ describe('createServerFn compiles correctly', async () => { const compiledResult = compileStartOutput({ env, code, - root: './test-files', filename, dce: false, }) @@ -42,7 +43,6 @@ describe('createServerFn compiles correctly', async () => { code: ` import { createServerFn } from '@tanstack/react-start' createServerFn()`, - root: './test-files', filename: 'no-fn.ts', dce: false, }) @@ -56,7 +56,6 @@ describe('createServerFn compiles correctly', async () => { code: ` import { createServerFn } from '@tanstack/react-start' createServerFn().handler(async () => {})`, - root: './test-files', filename: 'no-fn.ts', dce: false, }) @@ -72,7 +71,6 @@ describe('createServerFn compiles correctly', async () => { const myServerFn = createServerFn().handler(myFunc)` const compiledResultClient = compileStartOutput({ - root: '/test', filename: 'test.ts', code, env: 'client', @@ -80,7 +78,6 @@ describe('createServerFn compiles correctly', async () => { }) const compiledResultServer = compileStartOutput({ - root: '/test', filename: 'test.ts', code, env: 'server', @@ -123,7 +120,6 @@ describe('createServerFn compiles correctly', async () => { // Client const compiledResult = compileStartOutput({ - root: '/test', filename: 'test.ts', code, env: 'client', @@ -146,7 +142,6 @@ describe('createServerFn compiles correctly', async () => { // Server const compiledResultServer = compileStartOutput({ - root: '/test', filename: 'test.ts', code, env: 'server', diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnValidator.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnValidator.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnValidator.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnValidator.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnValidator.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnValidator.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnValidator.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnValidator.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/test-files/createServerFnDestructured.tsx b/packages/start-plugin-core/tests/createServerFn/test-files/createServerFnDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/test-files/createServerFnDestructured.tsx rename to packages/start-plugin-core/tests/createServerFn/test-files/createServerFnDestructured.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx b/packages/start-plugin-core/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx rename to packages/start-plugin-core/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/test-files/createServerFnStarImport.tsx b/packages/start-plugin-core/tests/createServerFn/test-files/createServerFnStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/test-files/createServerFnStarImport.tsx rename to packages/start-plugin-core/tests/createServerFn/test-files/createServerFnStarImport.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/test-files/createServerFnValidator.tsx b/packages/start-plugin-core/tests/createServerFn/test-files/createServerFnValidator.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/test-files/createServerFnValidator.tsx rename to packages/start-plugin-core/tests/createServerFn/test-files/createServerFnValidator.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/createMiddleware.test.ts b/packages/start-plugin-core/tests/createServerRoute/createServerRoute.test.ts similarity index 86% rename from packages/react-start-plugin/tests/createMiddleware/createMiddleware.test.ts rename to packages/start-plugin-core/tests/createServerRoute/createServerRoute.test.ts index 05d57dd32d..6ab449670d 100644 --- a/packages/react-start-plugin/tests/createMiddleware/createMiddleware.test.ts +++ b/packages/start-plugin-core/tests/createServerRoute/createServerRoute.test.ts @@ -2,7 +2,9 @@ import { readFile, readdir } from 'node:fs/promises' import path from 'node:path' import { describe, expect, test } from 'vitest' -import { compileStartOutput } from '../../src/compilers' +import { compileStartOutputFactory } from '../../src/compilers' + +const compileStartOutput = compileStartOutputFactory('react') async function getFilenames() { return await readdir(path.resolve(import.meta.dirname, './test-files')) @@ -23,9 +25,8 @@ describe('createMiddleware compiles correctly', async () => { const compiledResult = compileStartOutput({ env, code, - root: './test-files', filename, - dce: false, + dce: true, }) await expect(compiledResult.code).toMatchFileSnapshot( diff --git a/packages/react-start-client/src/routesManifest.ts b/packages/start-plugin-core/tests/createServerRoute/snapshots/client/nonImported.tsx similarity index 100% rename from packages/react-start-client/src/routesManifest.ts rename to packages/start-plugin-core/tests/createServerRoute/snapshots/client/nonImported.tsx diff --git a/packages/start-plugin-core/tests/createServerRoute/snapshots/server/nonImported.tsx b/packages/start-plugin-core/tests/createServerRoute/snapshots/server/nonImported.tsx new file mode 100644 index 0000000000..265eba8dbc --- /dev/null +++ b/packages/start-plugin-core/tests/createServerRoute/snapshots/server/nonImported.tsx @@ -0,0 +1,11 @@ +import { createServerFileRoute } from "@tanstack/react-start/server"; +import { z } from 'zod'; +export const ServerRoute = createServerFileRoute().validator(z.number()).middleware(({ + input +}) => input + 1).methods({ + GET: async ({ + input + }) => { + return input + 1; + } +}); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createServerRoute/test-files/nonImported.tsx b/packages/start-plugin-core/tests/createServerRoute/test-files/nonImported.tsx new file mode 100644 index 0000000000..d782a05448 --- /dev/null +++ b/packages/start-plugin-core/tests/createServerRoute/test-files/nonImported.tsx @@ -0,0 +1,10 @@ +import { z } from 'zod' + +export const ServerRoute = createServerFileRoute() + .validator(z.number()) + .middleware(({ input }) => input + 1) + .methods({ + GET: async ({ input }) => { + return input + 1 + }, + }) diff --git a/packages/react-start-plugin/tests/envOnly/envOnly.test.ts b/packages/start-plugin-core/tests/envOnly/envOnly.test.ts similarity index 91% rename from packages/react-start-plugin/tests/envOnly/envOnly.test.ts rename to packages/start-plugin-core/tests/envOnly/envOnly.test.ts index 0fae21d3af..4ce873cc23 100644 --- a/packages/react-start-plugin/tests/envOnly/envOnly.test.ts +++ b/packages/start-plugin-core/tests/envOnly/envOnly.test.ts @@ -2,7 +2,9 @@ import { readFile, readdir } from 'node:fs/promises' import path from 'node:path' import { describe, expect, test } from 'vitest' -import { compileStartOutput } from '../../src/compilers' +import { compileStartOutputFactory } from '../../src/compilers' + +const compileStartOutput = compileStartOutputFactory('react') async function getFilenames() { return await readdir(path.resolve(import.meta.dirname, './test-files')) @@ -23,7 +25,6 @@ describe('envOnly functions compile correctly', async () => { const compiledResult = compileStartOutput({ env, code, - root: './test-files', filename, dce: false, }) @@ -41,7 +42,6 @@ describe('envOnly functions compile correctly', async () => { code: ` import { clientOnly } from '@tanstack/react-start' const fn = clientOnly()`, - root: './test-files', filename: 'no-fn.ts', dce: false, }) @@ -52,7 +52,6 @@ describe('envOnly functions compile correctly', async () => { code: ` import { serverOnly } from '@tanstack/react-start' const fn = serverOnly()`, - root: './test-files', filename: 'no-fn.ts', dce: false, }) diff --git a/packages/react-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructured.tsx b/packages/start-plugin-core/tests/envOnly/snapshots/client/envOnlyDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructured.tsx rename to packages/start-plugin-core/tests/envOnly/snapshots/client/envOnlyDestructured.tsx diff --git a/packages/react-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx b/packages/start-plugin-core/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx rename to packages/start-plugin-core/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/envOnly/snapshots/client/envOnlyStarImport.tsx b/packages/start-plugin-core/tests/envOnly/snapshots/client/envOnlyStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/snapshots/client/envOnlyStarImport.tsx rename to packages/start-plugin-core/tests/envOnly/snapshots/client/envOnlyStarImport.tsx diff --git a/packages/react-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructured.tsx b/packages/start-plugin-core/tests/envOnly/snapshots/server/envOnlyDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructured.tsx rename to packages/start-plugin-core/tests/envOnly/snapshots/server/envOnlyDestructured.tsx diff --git a/packages/react-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx b/packages/start-plugin-core/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx rename to packages/start-plugin-core/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/envOnly/snapshots/server/envOnlyStarImport.tsx b/packages/start-plugin-core/tests/envOnly/snapshots/server/envOnlyStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/snapshots/server/envOnlyStarImport.tsx rename to packages/start-plugin-core/tests/envOnly/snapshots/server/envOnlyStarImport.tsx diff --git a/packages/react-start-plugin/tests/envOnly/test-files/envOnlyDestructured.tsx b/packages/start-plugin-core/tests/envOnly/test-files/envOnlyDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/test-files/envOnlyDestructured.tsx rename to packages/start-plugin-core/tests/envOnly/test-files/envOnlyDestructured.tsx diff --git a/packages/react-start-plugin/tests/envOnly/test-files/envOnlyDestructuredRename.tsx b/packages/start-plugin-core/tests/envOnly/test-files/envOnlyDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/test-files/envOnlyDestructuredRename.tsx rename to packages/start-plugin-core/tests/envOnly/test-files/envOnlyDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/envOnly/test-files/envOnlyStarImport.tsx b/packages/start-plugin-core/tests/envOnly/test-files/envOnlyStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/test-files/envOnlyStarImport.tsx rename to packages/start-plugin-core/tests/envOnly/test-files/envOnlyStarImport.tsx diff --git a/packages/start-plugin-core/tsconfig.json b/packages/start-plugin-core/tsconfig.json new file mode 100644 index 0000000000..3ed8e1dc0f --- /dev/null +++ b/packages/start-plugin-core/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src", "vite.config.ts", "tests"], + "exclude": ["tests/**/test-files/**", "tests/**/snapshots/**"], + "compilerOptions": { + "target": "esnext", + "noEmit": true + } +} diff --git a/packages/start-server-functions-ssr/vite.config.ts b/packages/start-plugin-core/vite.config.ts similarity index 75% rename from packages/start-server-functions-ssr/vite.config.ts rename to packages/start-plugin-core/vite.config.ts index 976bb5c87f..2c711fd181 100644 --- a/packages/start-server-functions-ssr/vite.config.ts +++ b/packages/start-plugin-core/vite.config.ts @@ -1,14 +1,13 @@ import { defineConfig, mergeConfig } from 'vitest/config' import { tanstackViteConfig } from '@tanstack/config/vite' import packageJson from './package.json' -import type { ViteUserConfig } from 'vitest/config' const config = defineConfig({ - plugins: [] as ViteUserConfig['plugins'], test: { name: packageJson.name, + dir: './tests', watch: false, - environment: 'jsdom', + typecheck: { enabled: true }, }, }) @@ -17,5 +16,6 @@ export default mergeConfig( tanstackViteConfig({ entry: './src/index.ts', srcDir: './src', + outDir: './dist', }), ) diff --git a/packages/start-server-core/README.md b/packages/start-server-core/README.md index bb009b0c87..0c0d4cc215 100644 --- a/packages/start-server-core/README.md +++ b/packages/start-server-core/README.md @@ -1,33 +1,12 @@ -> 🤫 we're cooking up something special! - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) +# TanStack Start - Server Core -🤖 Type-safe router w/ built-in caching & URL state management for React! +This package is not meant to be used directly. It is a dependency of the TanStack Start framework-specific packages: - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - +- [`@tanstack/react-start`](https://www.npmjs.com/package/@tanstack/react-start) +- [`@tanstack/solid-start`](https://www.npmjs.com/package/@tanstack/solid-start). -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) +It provides the core functionality for TanStack Start, which is a fullstack-framework made for SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router). -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! +Head over to [tanstack.com/start](https://tanstack.com/start) for more information about getting started. diff --git a/packages/start-server-core/package.json b/packages/start-server-core/package.json index 95f7e6799a..e0cc77ac12 100644 --- a/packages/start-server-core/package.json +++ b/packages/start-server-core/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/start-server-core", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -65,15 +65,17 @@ "@tanstack/history": "workspace:^", "@tanstack/router-core": "workspace:^", "@tanstack/start-client-core": "workspace:^", - "tiny-warning": "^1.0.3", "h3": "1.13.0", "isbot": "^5.1.22", "jsesc": "^3.1.0", + "tiny-invariant": "^1.3.3", + "tiny-warning": "^1.0.3", "unctx": "^2.4.1" }, "devDependencies": { "@types/jsesc": "^3.0.3", "esbuild": "^0.25.0", - "typescript": "^5.7.2" + "typescript": "^5.7.2", + "vite": "^6.3.5" } } diff --git a/packages/start-server-core/src/createRequestHandler.ts b/packages/start-server-core/src/createRequestHandler.ts index 0e7b975d13..061e458468 100644 --- a/packages/start-server-core/src/createRequestHandler.ts +++ b/packages/start-server-core/src/createRequestHandler.ts @@ -66,9 +66,7 @@ function getRequestHeaders(opts: { router: AnyRouter }): Headers { const { redirect } = opts.router.state if (redirect) { - headers = mergeHeaders(headers, redirect.headers, { - Location: redirect.href, - }) + headers = mergeHeaders(headers, redirect.headers) } return headers diff --git a/packages/start-server-core/src/createStartHandler.ts b/packages/start-server-core/src/createStartHandler.ts index 7604efbdef..0765fb4cfa 100644 --- a/packages/start-server-core/src/createStartHandler.ts +++ b/packages/start-server-core/src/createStartHandler.ts @@ -1,82 +1,408 @@ import { createMemoryHistory } from '@tanstack/history' -import { mergeHeaders } from '@tanstack/start-client-core' -import { eventHandler, getResponseHeaders, toWebRequest } from 'h3' +import { + flattenMiddlewares, + json, + mergeHeaders, +} from '@tanstack/start-client-core' +import { + getMatchedRoutes, + isRedirect, + isResolvedRedirect, + joinPaths, + processRouteTree, + rootRouteId, + trimPath, +} from '@tanstack/router-core' +import { getResponseHeaders, requestHandler } from './h3' import { attachRouterServerSsrUtils, dehydrateRouter } from './ssr-server' +import { getStartManifest } from './router-manifest' +import { handleServerAction } from './server-functions-handler' +import type { AnyServerRoute, AnyServerRouteWithTypes } from './serverRoute' +import type { RequestHandler } from './h3' +import type { AnyRouter } from '@tanstack/router-core' import type { HandlerCallback } from './handlerCallback' -import type { EventHandlerResponse, H3Event } from 'h3' -import type { AnyRouter, Manifest } from '@tanstack/router-core' - -export type CustomizeStartHandler< - TRouter extends AnyRouter, - TResponse extends EventHandlerResponse = EventHandlerResponse, -> = (cb: HandlerCallback) => ReturnType - -export function createStartHandler< - TRouter extends AnyRouter, - TResponse extends EventHandlerResponse = EventHandlerResponse, ->({ + +type TODO = any + +export type CustomizeStartHandler = ( + cb: HandlerCallback, +) => RequestHandler + +export function getStartResponseHeaders(opts: { router: AnyRouter }) { + let headers = mergeHeaders( + getResponseHeaders(), + { + 'Content-Type': 'text/html; charset=UTF-8', + }, + ...opts.router.state.matches.map((match) => { + return match.headers + }), + ) + // Handle Redirects + const { redirect } = opts.router.state + + if (redirect) { + headers = mergeHeaders(headers, redirect.headers) + } + return headers +} + +export function createStartHandler({ createRouter, - getRouterManifest, }: { createRouter: () => TRouter - getRouterManifest?: () => Manifest | Promise -}): CustomizeStartHandler { +}): CustomizeStartHandler { return (cb) => { - return eventHandler(async (event) => { - const request = toWebRequest(event) + const originalFetch = globalThis.fetch + + const startRequestResolver: RequestHandler = async ({ request }) => { + // Patching fetch function to use our request resolver + // if the input starts with `/` which is a common pattern for + // client-side routing. + // When we encounter similar requests, we can assume that the + // user wants to use the same origin as the current request. + globalThis.fetch = async function (input, init) { + function resolve(url: URL, requestOptions: RequestInit | undefined) { + const fetchRequest = new Request(url, requestOptions) + return startRequestResolver({ request: fetchRequest }) + } + + function getOrigin() { + return ( + request.headers.get('Origin') || + request.headers.get('Referer') || + 'http://localhost' + ) + } + + if (typeof input === 'string' && input.startsWith('/')) { + // e.g: fetch('/api/data') + const url = new URL(input, getOrigin()) + return resolve(url, init) + } else if ( + typeof input === 'object' && + 'url' in input && + typeof input.url === 'string' && + input.url.startsWith('/') + ) { + // e.g: fetch(new Request('/api/data')) + const url = new URL(input.url, getOrigin()) + return resolve(url, init) + } + + // If not, it should just use the original fetch + return originalFetch(input, init) + } const url = new URL(request.url) const href = url.href.replace(url.origin, '') - // Create a history for the router + // Create a history for the client-side router const history = createMemoryHistory({ initialEntries: [href], }) + // Create the client-side router const router = createRouter() - attachRouterServerSsrUtils(router, await getRouterManifest?.()) + // Attach the server-side SSR utils to the client-side router + attachRouterServerSsrUtils(router, getStartManifest()) - // Update the router with the history and context + // Update the client-side router with the history and context router.update({ history, }) - await router.load() + const response = await (async () => { + try { + if (!process.env.TSS_SERVER_FN_BASE) { + throw new Error( + 'tanstack/start-server-core: TSS_SERVER_FN_BASE must be defined in your environment for createStartHandler()', + ) + } - dehydrateRouter(router) + // First, let's attempt to handle server functions + // Add trailing slash to sanitise user defined TSS_SERVER_FN_BASE + const serverFnBase = joinPaths([ + '/', + trimPath(process.env.TSS_SERVER_FN_BASE), + '/', + ]) + if (href.startsWith(serverFnBase)) { + return await handleServerAction({ request }) + } - const responseHeaders = getStartResponseHeaders({ event, router }) - const response = await cb({ - request, - router, - responseHeaders, - }) + // Then move on to attempting to load server routes + const serverRouteTreeModule = await (async () => { + try { + return (await import( + // @ts-expect-error + 'tanstack-start-server-routes-manifest:v' + )) as { routeTree: AnyServerRoute } + } catch (e) { + console.log(e) + return undefined + } + })() + + // If we have a server route tree, then we try matching to see if we have a + // server route that matches the request. + if (serverRouteTreeModule) { + const [_matchedRoutes, response] = await handleServerRoutes({ + routeTree: serverRouteTreeModule.routeTree, + request, + }) + + if (response) return response + } + + const requestAcceptHeader = request.headers.get('Accept') || '*/*' + const splitRequestAcceptHeader = requestAcceptHeader.split(',') + + const supportedMimeTypes = ['*/*', 'text/html'] + const isRouterAcceptSupported = supportedMimeTypes.some((mimeType) => + splitRequestAcceptHeader.some((acceptedMimeType) => + acceptedMimeType.trim().startsWith(mimeType), + ), + ) + + if (!isRouterAcceptSupported) { + return json( + { + error: 'Only HTML requests are supported here', + }, + { + status: 500, + }, + ) + } + + // If no Server Routes were found, so fallback to normal SSR matching using + // the router + + await router.load() + + // If there was a redirect, skip rendering the page at all + if (router.state.redirect) return router.state.redirect + + dehydrateRouter(router) + + const responseHeaders = getStartResponseHeaders({ router }) + const response = await cb({ + request, + router, + responseHeaders, + }) + + return response + } catch (err) { + if (err instanceof Response) { + return err + } + + throw err + } + })() + + if (isRedirect(response)) { + if (isResolvedRedirect(response)) { + if (request.headers.get('x-tsr-redirect') === 'manual') { + return json( + { + ...response.options, + isSerializedRedirect: true, + }, + { + headers: response.headers, + }, + ) + } + return response + } + if ( + response.options.to && + typeof response.options.to === 'string' && + !response.options.to.startsWith('/') + ) { + throw new Error( + `Server side redirects must use absolute paths via the 'href' or 'to' options. Received: ${JSON.stringify(response.options)}`, + ) + } + + if ( + ['params', 'search', 'hash'].some( + (d) => typeof (response.options as any)[d] === 'function', + ) + ) { + throw new Error( + `Server side redirects must use static search, params, and hash values and do not support functional values. Received functional values for: ${Object.keys( + response.options, + ) + .filter((d) => typeof (response.options as any)[d] === 'function') + .map((d) => `"${d}"`) + .join(', ')}`, + ) + } + + const redirect = router.resolveRedirect(response) + + if (request.headers.get('x-tsr-redirect') === 'manual') { + return json( + { + ...response.options, + isSerializedRedirect: true, + }, + { + headers: response.headers, + }, + ) + } + + return redirect + } return response - }) + } + + return requestHandler(startRequestResolver) } } -function getStartResponseHeaders(opts: { event: H3Event; router: AnyRouter }) { - let headers = mergeHeaders( - getResponseHeaders(opts.event), - (opts.event as any).___ssrRpcResponseHeaders, - { - 'Content-Type': 'text/html; charset=UTF-8', +async function handleServerRoutes({ + routeTree, + request, +}: { + routeTree: AnyServerRouteWithTypes + request: Request +}) { + const { flatRoutes, routesById, routesByPath } = processRouteTree({ + routeTree, + initRoute: (route, i) => { + route.init({ + originalIndex: i, + }) }, - ...opts.router.state.matches.map((match) => { - return match.headers - }), - ) + }) - // Handle Redirects - const { redirect } = opts.router.state + const url = new URL(request.url) + const pathname = url.pathname - if (redirect) { - headers = mergeHeaders(headers, redirect.headers, { - Location: redirect.href, + const history = createMemoryHistory({ + initialEntries: [pathname], + }) + + const { matchedRoutes, foundRoute, routeParams } = + getMatchedRoutes({ + pathname: history.location.pathname, + basepath: '/', + caseSensitive: true, + routesByPath, + routesById, + flatRoutes, }) + + let response: Response | undefined + + if (foundRoute && foundRoute.id !== rootRouteId) { + // We've found a server route that matches the request, so we can call it. + // TODO: Get the input type-signature correct + // TODO: Perform the middlewares? + // TODO: Error handling? What happens when its `throw redirect()` vs `throw new Error()`? + + const method = Object.keys(foundRoute.options.methods).find( + (method) => method.toLowerCase() === request.method.toLowerCase(), + ) + + if (method) { + const handler = foundRoute.options.methods[method] + + if (handler) { + const middlewares = flattenMiddlewares( + matchedRoutes.flatMap((r) => r.options.middleware).filter(Boolean), + ).map((d) => d.options.server) + + middlewares.push(handlerToMiddleware(handler) as TODO) + + // TODO: This is starting to feel too much like a server function + // Do generalize the existing middleware execution? Or do we need to + // build a new middleware execution system for server routes? + const ctx = await executeMiddleware(middlewares, { + request, + context: {}, + params: routeParams, + pathname: history.location.pathname, + }) + + response = ctx.response + } + } } - return headers + + // We return the matched routes too so if + // the app router happens to match the same path, + // it can use any request middleware from server routes + return [matchedRoutes, response] as const +} + +function handlerToMiddleware( + handler: AnyServerRouteWithTypes['options']['methods'][string], +) { + return async ({ next: _next, ...rest }: TODO) => ({ + response: await handler(rest), + }) +} + +function executeMiddleware(middlewares: TODO, ctx: TODO) { + let index = -1 + + const next = async (ctx: TODO) => { + index++ + const middleware = middlewares[index] + if (!middleware) return ctx + + const result = await middleware({ + ...ctx, + // Allow the middleware to call the next middleware in the chain + next: async (nextCtx: TODO) => { + // Allow the caller to extend the context for the next middleware + const nextResult = await next({ ...ctx, ...nextCtx }) + + // Merge the result into the context\ + return Object.assign(ctx, handleCtxResult(nextResult)) + }, + // Allow the middleware result to extend the return context + }).catch((err: TODO) => { + if (isSpecialResponse(err)) { + return { + response: err, + } + } + + throw err + }) + + // Merge the middleware result into the context, just in case it + // returns a partial context + return Object.assign(ctx, handleCtxResult(result)) + } + + return handleCtxResult(next(ctx)) +} + +function handleCtxResult(result: TODO) { + if (isSpecialResponse(result)) { + return { + response: result, + } + } + + return result +} + +function isSpecialResponse(err: TODO) { + return isResponse(err) || isRedirect(err) +} + +function isResponse(response: Response): response is Response { + return response instanceof Response } diff --git a/packages/start-server-core/src/h3.ts b/packages/start-server-core/src/h3.ts index d5a2c94844..72108f0c2d 100644 --- a/packages/start-server-core/src/h3.ts +++ b/packages/start-server-core/src/h3.ts @@ -11,7 +11,9 @@ import { clearResponseHeaders as _clearResponseHeaders, clearSession as _clearSession, defaultContentType as _defaultContentType, + defineEventHandler as _defineEventHandler, deleteCookie as _deleteCookie, + eventHandler as _eventHandler, fetchWithEvent as _fetchWithEvent, getCookie as _getCookie, getHeader as _getHeader, @@ -61,20 +63,24 @@ import { setResponseHeader as _setResponseHeader, setResponseHeaders as _setResponseHeaders, setResponseStatus as _setResponseStatus, + toWebRequest as _toWebRequest, unsealSession as _unsealSession, updateSession as _updateSession, useSession as _useSession, writeEarlyHints as _writeEarlyHints, } from 'h3' -import { getContext as getUnctxContext } from 'unctx' + import type { Encoding, + EventHandler, HTTPHeaderName, InferEventInput, _RequestMiddleware, _ResponseMiddleware, } from 'h3' +const eventStorage = new AsyncLocalStorage() + function _setContext(event: H3Event, key: string, value: any) { event.context[key] = value } @@ -90,46 +96,38 @@ export function defineMiddleware(options: { return options } -function toWebRequestH3(event: H3Event) { - /** - * @type {ReadableStream | undefined} - */ - let readableStream: ReadableStream | undefined +// function toWebRequestH3(event: H3Event) { +// /** +// * @type {ReadableStream | undefined} +// */ +// let readableStream: ReadableStream | undefined - const url = getRequestURL(event) - const base = { - // @ts-ignore Undici option - duplex: 'half', - method: event.method, - headers: event.headers, - } - - if ((event.node.req as any).body instanceof ArrayBuffer) { - return new Request(url, { - ...base, - body: (event.node.req as any).body, - }) - } +// const url = _getRequestURL(event) +// const base = { +// // @ts-ignore Undici option +// duplex: 'half', +// method: event.method, +// headers: event.headers, +// } - return new Request(url, { - ...base, - get body() { - if (readableStream) { - return readableStream - } - readableStream = getRequestWebStream(event) - return readableStream - }, - }) -} +// if ((event.node.req as any).body instanceof ArrayBuffer) { +// return new Request(url, { +// ...base, +// body: (event.node.req as any).body, +// }) +// } -export function toWebRequest(event: H3Event) { - event.web ??= { - request: toWebRequestH3(event), - url: getRequestURL(event), - } - return event.web.request -} +// return new Request(url, { +// ...base, +// get body() { +// if (readableStream) { +// return readableStream +// } +// readableStream = _getRequestWebStream(event) +// return readableStream +// }, +// }) +// } export { H3Error, @@ -140,7 +138,6 @@ export { createAppEventHandler, createEvent, createRouter, - defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, @@ -148,7 +145,6 @@ export { defineResponseMiddleware, dynamicEventHandler, defineWebSocket, - eventHandler, splitCookiesString, fromNodeMiddleware, fromPlainHandler, @@ -163,6 +159,7 @@ export { toNodeListener, toPlainHandler, toWebHandler, + toWebRequest, isCorsOriginAllowed, isStream, createError, @@ -221,8 +218,33 @@ export { type _ResponseMiddleware, } from 'h3' -function getHTTPEvent() { - return getEvent() +export function defineEventHandler(handler: EventHandler) { + return _defineEventHandler((event) => { + return runWithEvent(event, () => handler(event)) + }) +} + +export function eventHandler(handler: EventHandler) { + return _eventHandler((event) => { + return runWithEvent(event, () => handler(event)) + }) +} + +export async function runWithEvent( + event: H3Event, + fn: () => T | Promise, +): Promise { + return eventStorage.run(event, fn) +} + +export function getEvent() { + const event = eventStorage.getStore() as H3Event | undefined + if (!event) { + throw new Error( + `No HTTPEvent found in AsyncLocalStorage. Make sure you are using the function within the server runtime.`, + ) + } + return event } export const HTTPEventSymbol = Symbol('$HTTPEvent') @@ -262,12 +284,7 @@ function createWrapperFunction) => any>( return function (...args: Array) { const event = args[0] if (!isEvent(event)) { - if (!(globalThis as any).app.config.server.experimental?.asyncContext) { - throw new Error( - 'AsyncLocalStorage was not enabled. Use the `server.experimental.asyncContext: true` option in your app configuration to enable it. Or, pass the instance of HTTPEvent that you have as the first argument to the function.', - ) - } - args.unshift(getHTTPEvent()) + args.unshift(getEvent()) } else { args[0] = event instanceof H3Event || (event as any).__is_event__ @@ -463,37 +480,13 @@ export const readValidatedBody: PrependOverload< export const removeResponseHeader = createWrapperFunction(_removeResponseHeader) export const getContext = createWrapperFunction(_getContext) export const setContext = createWrapperFunction(_setContext) - export const clearResponseHeaders = createWrapperFunction(_clearResponseHeaders) +export const getWebRequest = createWrapperFunction(_toWebRequest) -export const getWebRequest = createWrapperFunction(toWebRequest) - -export { createApp as createServer } from 'h3' - -function getNitroAsyncContext() { - const nitroAsyncContext = getUnctxContext('nitro-app', { - asyncContext: (globalThis as any).app.config.server.experimental - ?.asyncContext - ? true - : false, - AsyncLocalStorage, - }) - - return nitroAsyncContext -} - -export function getEvent() { - const event = (getNitroAsyncContext().use() as any).event as - | H3Event - | undefined - if (!event) { - throw new Error( - `No HTTPEvent found in AsyncLocalStorage. Make sure you are using the function within the server runtime.`, - ) - } - return event -} +export type RequestHandler = (ctx: { + request: Request +}) => Promise | Response -export async function handleHTTPEvent(event: H3Event) { - return await (globalThis as any).$handle(event) +export function requestHandler(handler: RequestHandler) { + return handler } diff --git a/packages/start-server-core/src/handlerCallback.ts b/packages/start-server-core/src/handlerCallback.ts index a109f9b94a..a167955389 100644 --- a/packages/start-server-core/src/handlerCallback.ts +++ b/packages/start-server-core/src/handlerCallback.ts @@ -1,22 +1,15 @@ -import type { EventHandlerResponse } from 'h3' import type { AnyRouter } from '@tanstack/router-core' -export interface HandlerCallback< - TRouter extends AnyRouter, - TResponse extends EventHandlerResponse = EventHandlerResponse, -> { +export interface HandlerCallback { (ctx: { request: Request router: TRouter responseHeaders: Headers - }): TResponse + }): Response | Promise } -export function defineHandlerCallback< - TRouter extends AnyRouter, - TResponse = EventHandlerResponse, ->( - handler: HandlerCallback, -): HandlerCallback { +export function defineHandlerCallback( + handler: HandlerCallback, +): HandlerCallback { return handler } diff --git a/packages/start-server-core/src/index.tsx b/packages/start-server-core/src/index.tsx index d24477934d..9337b7c4cd 100644 --- a/packages/start-server-core/src/index.tsx +++ b/packages/start-server-core/src/index.tsx @@ -3,10 +3,20 @@ export { transformPipeableStreamWithRouter, } from './transformStreamWithRouter' -export { createStartHandler } from './createStartHandler' +export { + getStartResponseHeaders, + createStartHandler, +} from './createStartHandler' +export type { CustomizeStartHandler } from './createStartHandler' export { createRequestHandler } from './createRequestHandler' export { defineHandlerCallback } from './handlerCallback' export type { HandlerCallback } from './handlerCallback' +export { attachRouterServerSsrUtils, dehydrateRouter } from './ssr-server' +export { handleServerAction } from './server-functions-handler' + export * from './h3' + +export { createServerRoute, createServerFileRoute } from './serverRoute' +export type { CreateServerFileRoute } from './serverRoute' diff --git a/packages/start-server-core/src/router-manifest.ts b/packages/start-server-core/src/router-manifest.ts new file mode 100644 index 0000000000..ca08026e62 --- /dev/null +++ b/packages/start-server-core/src/router-manifest.ts @@ -0,0 +1,79 @@ +import { tsrStartManifest } from 'tanstack-start-router-manifest:v' +import { rootRouteId } from '@tanstack/router-core' + +declare global { + // eslint-disable-next-line no-var + var TSS_INJECTED_HEAD_SCRIPTS: string | undefined +} + +/** + * @description Returns the router manifest that should be sent to the client. + * This includes only the assets and preloads for the current route and any + * special assets that are needed for the client. It does not include relationships + * between routes or any other data that is not needed for the client. + */ +export function getStartManifest() { + const startManifest = tsrStartManifest() + + const rootRoute = (startManifest.routes[rootRouteId] = + startManifest.routes[rootRouteId] || {}) + + rootRoute.assets = rootRoute.assets || [] + + // Get the entry for the client + // const ClientManifest = getManifest('client') + + // const importPath = + // ClientManifest.inputs[ClientManifest.handler]?.output.path + // if (!importPath) { + // invariant(importPath, 'Could not find client entry in manifest') + // } + + if (process.env.NODE_ENV === 'development' && !process.env.TSS_CLIENT_ENTRY) { + throw new Error( + 'tanstack/start-server-core: TSS_CLIENT_ENTRY must be defined in your environment for getStartManifest()', + ) + } + + if (process.env.NODE_ENV === 'development') { + // Always fake that HMR is ready + // const CLIENT_BASE = sanitizeBase(process.env.TSS_CLIENT_BASE || '') + + // if (!CLIENT_BASE) { + // throw new Error( + // 'tanstack/start-router-manifest: TSS_CLIENT_BASE must be defined in your environment for getFullRouterManifest()', + // ) + // } + + const script = `${globalThis.TSS_INJECTED_HEAD_SCRIPTS ? globalThis.TSS_INJECTED_HEAD_SCRIPTS + '; ' : ''}import(${JSON.stringify(process.env.TSS_CLIENT_ENTRY)})` + + rootRoute.assets.push({ + tag: 'script', + attrs: { + type: 'module', + suppressHydrationWarning: true, + async: true, + }, + children: script, + }) + } + + const manifest = { + ...startManifest, + routes: Object.fromEntries( + Object.entries(startManifest.routes).map(([k, v]) => { + const { preloads, assets } = v + return [ + k, + { + preloads, + assets, + }, + ] + }), + ), + } + + // Strip out anything that isn't needed for the client + return manifest +} diff --git a/packages/start-server-functions-handler/src/index.ts b/packages/start-server-core/src/server-functions-handler.ts similarity index 73% rename from packages/start-server-functions-handler/src/index.ts rename to packages/start-server-core/src/server-functions-handler.ts index 85cbe87783..460711e54c 100644 --- a/packages/start-server-functions-handler/src/index.ts +++ b/packages/start-server-core/src/server-functions-handler.ts @@ -1,21 +1,9 @@ -import { isNotFound, isRedirect } from '@tanstack/router-core' +import { isNotFound } from '@tanstack/router-core' import invariant from 'tiny-invariant' -import { - eventHandler, - getEvent, - getResponseStatus, - toWebRequest, -} from '@tanstack/start-server-core' import { startSerializer } from '@tanstack/start-client-core' // @ts-expect-error -import _serverFnManifest from 'tsr:server-fn-manifest' -import type { H3Event } from '@tanstack/start-server-core' - -// NOTE: This is a dummy export to silence warnings about -// only having a default export. -export const dummy = 1 - -export default eventHandler(handleServerAction) +import _serverFnManifest from 'tanstack-start-server-fn-manifest:v' +import { getEvent, getResponseStatus } from './h3' const serverFnManifest = _serverFnManifest as Record< string, @@ -26,16 +14,6 @@ const serverFnManifest = _serverFnManifest as Record< } > -async function handleServerAction(event: H3Event) { - const request = toWebRequest(event)! - - const response = await handleServerRequest({ - request, - event, - }) - return response -} - function sanitizeBase(base: string | undefined) { if (!base) { throw new Error( @@ -46,21 +24,15 @@ function sanitizeBase(base: string | undefined) { return base.replace(/^\/|\/$/g, '') } -async function handleServerRequest({ - request, - event, -}: { - request: Request - event: H3Event -}) { +export const handleServerAction = async ({ request }: { request: Request }) => { const controller = new AbortController() const signal = controller.signal const abort = () => controller.abort() - event.node.req.on('close', abort) + request.signal.addEventListener('abort', abort) const method = request.method const url = new URL(request.url, 'http://localhost:3000') - // extract the serverFnId from the url as host/_server/:serverFnId + // extract the serverFnId from the url as host/_serverFn/:serverFnId // Define a regex to match the path and extract the :thing part const regex = new RegExp( `${sanitizeBase(process.env.TSS_SERVER_FN_BASE)}/([^/?#]+)`, @@ -84,33 +56,23 @@ async function handleServerRequest({ const serverFnInfo = serverFnManifest[serverFnId] if (!serverFnInfo) { - console.log('serverFnManifest', serverFnManifest) + console.info('serverFnManifest', serverFnManifest) throw new Error('Server function info not found for ' + serverFnId) } - if (process.env.NODE_ENV === 'development') - console.info(`\nServerFn Request: ${serverFnId}`) - - let fnModule: undefined | { [key: string]: any } - - if (process.env.NODE_ENV === 'development') { - fnModule = await (globalThis as any).app - .getRouter('server') - .internals.devServer.ssrLoadModule(serverFnInfo.extractedFilename) - } else { - fnModule = await serverFnInfo.importer() - } + const fnModule: undefined | { [key: string]: any } = + await serverFnInfo.importer() if (!fnModule) { - console.log('serverFnManifest', serverFnManifest) + console.info('serverFnInfo', serverFnInfo) throw new Error('Server function module not resolved for ' + serverFnId) } const action = fnModule[serverFnInfo.functionName] if (!action) { - console.log('serverFnManifest', serverFnManifest) - console.log('fnModule', fnModule) + console.info('serverFnInfo', serverFnInfo) + console.info('fnModule', fnModule) throw new Error( `Server function module export not resolved for serverFn ID: ${serverFnId}`, ) @@ -208,11 +170,11 @@ async function handleServerRequest({ // return result.result // } - // TODO: RSCs + // TODO: RSCs Where are we getting this package? // if (isValidElement(result)) { // const { renderToPipeableStream } = await import( // // @ts-expect-error - // '@vinxi/react-server-dom/server' + // 'react-server-dom/server' // ) // const pipeableStream = renderToPipeableStream(result) @@ -227,8 +189,8 @@ async function handleServerRequest({ // return new Response(null, { status: 200 }) // } - if (isRedirect(result) || isNotFound(result)) { - return redirectOrNotFoundResponse(result) + if (isNotFound(result)) { + return isNotFoundResponse(result) } return new Response( @@ -257,8 +219,8 @@ async function handleServerRequest({ // The client will check for __redirect and __notFound keys, // and if they exist, it will handle them appropriately. - if (isRedirect(error) || isNotFound(error)) { - return redirectOrNotFoundResponse(error) + if (isNotFound(error)) { + return isNotFoundResponse(error) } console.info() @@ -275,30 +237,17 @@ async function handleServerRequest({ }) } })() - event.node.req.removeListener('close', abort) + + request.signal.removeEventListener('abort', abort) if (isRaw) { return response } - if (process.env.NODE_ENV === 'development') - console.info(`ServerFn Response: ${response.status}`) - - if (response.headers.get('Content-Type') === 'application/json') { - const cloned = response.clone() - const text = await cloned.text() - const payload = text ? JSON.stringify(JSON.parse(text)) : 'undefined' - - if (process.env.NODE_ENV === 'development') - console.info( - ` - Payload: ${payload.length > 100 ? payload.substring(0, 100) + '...' : payload}`, - ) - } - if (process.env.NODE_ENV === 'development') console.info() return response } -function redirectOrNotFoundResponse(error: any) { +function isNotFoundResponse(error: any) { const { headers, ...rest } = error return new Response(JSON.stringify(rest), { diff --git a/packages/start-server-core/src/serverRoute.ts b/packages/start-server-core/src/serverRoute.ts new file mode 100644 index 0000000000..18011d6656 --- /dev/null +++ b/packages/start-server-core/src/serverRoute.ts @@ -0,0 +1,661 @@ +import { joinPaths, rootRouteId, trimPathLeft } from '@tanstack/router-core' +import type { + Assign, + Constrain, + Expand, + ResolveParams, + RouteConstraints, + TrimPathRight, +} from '@tanstack/router-core' +import type { + AnyRequestMiddleware, + AssignAllServerContext, +} from '@tanstack/start-client-core' + +type TODO = any + +export function createServerFileRoute< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TChildren, +>(__?: never): ServerRoute { + return createServerRoute( + undefined, + ) +} + +export interface ServerRouteOptions< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TMiddlewares, +> { + id: TId + path: TPath + pathname: TFullPath + originalIndex: number + getParentRoute?: () => TParentRoute + middleware: Constrain> + methods: Record< + string, + ServerRouteMethodHandlerFn + > + caseSensitive?: boolean +} + +export type ServerRouteManifest = { + middleware: boolean + methods: Record +} + +export function createServerRoute< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TChildren, +>( + __?: never, + __opts?: Partial< + ServerRouteOptions + >, +): ServerRoute { + const options = __opts || {} + + const route: ServerRoute = { + path: '' as TPath, + id: '' as TId, + fullPath: '' as TFullPath, + to: '' as TrimPathRight, + options: options as TODO, + parentRoute: undefined as unknown as TParentRoute, + _types: {} as TODO, + // children: undefined as TChildren, + middleware: (middlewares: TODO) => + createServerRoute(undefined, { + ...options, + middleware: middlewares, + }) as TODO, + methods: (methodsOrGetMethods: TODO) => { + const methods = (() => { + if (typeof methodsOrGetMethods === 'function') { + return methodsOrGetMethods(createMethodBuilder()) + } + + return methodsOrGetMethods + })() + + return createServerRoute(undefined, { + ...__opts, + methods, + }) as TODO + }, + update: (opts) => + createServerRoute(undefined, { + ...options, + ...opts, + }) as TODO, + init: (opts: { originalIndex: number }): void => { + options.originalIndex = opts.originalIndex + + const isRoot = !options.path && !options.id + + route.parentRoute = options.getParentRoute?.() as TParentRoute + + if (isRoot) { + route.path = rootRouteId as TPath + } else if (!(route.parentRoute as any)) { + throw new Error( + `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a ServerRoute instance.`, + ) + } + + let path: undefined | string = isRoot ? rootRouteId : options.path + + // If the path is anything other than an index path, trim it up + if (path && path !== '/') { + path = trimPathLeft(path) + } + + const customId = options.id || path + + // Strip the parentId prefix from the first level of children + let id = isRoot + ? rootRouteId + : joinPaths([ + route.parentRoute.id === rootRouteId ? '' : route.parentRoute.id, + customId, + ]) + + if (path === rootRouteId) { + path = '/' + } + + if (id !== rootRouteId) { + id = joinPaths(['/', id]) + } + + const fullPath = + id === rootRouteId ? '/' : joinPaths([route.parentRoute.fullPath, path]) + + route.path = path as TPath + route.id = id as TId + route.fullPath = fullPath as TFullPath + route.to = fullPath as TrimPathRight + }, + + _addFileChildren: (children) => { + if (Array.isArray(children)) { + route.children = children as TChildren as TODO + } + + if (typeof children === 'object' && children !== null) { + route.children = Object.values(children) as TChildren as TODO + } + + return route as any + }, + + _addFileTypes: () => route, + } + + return route +} + +export type ServerRouteAddFileChildrenFn< + in out TParentRoute extends AnyServerRouteWithTypes, + in out TId extends RouteConstraints['TId'], + in out TPath extends RouteConstraints['TPath'], + in out TFullPath extends RouteConstraints['TFullPath'], + in out TMiddlewares, + in out TMethods, + in out TChildren, +> = ( + children: TChildren, +) => ServerRouteWithTypes< + TParentRoute, + TId, + TPath, + TFullPath, + TMiddlewares, + TMethods, + TChildren +> + +const createMethodBuilder = < + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, +>( + __opts?: TODO, +): ServerRouteMethodBuilder => { + return { + _options: __opts || {}, + _types: {} as TODO, + middleware: (middlewares) => + createMethodBuilder({ + ...__opts, + middlewares, + }) as TODO, + handler: (handler) => + createMethodBuilder({ + ...__opts, + handler, + }) as TODO, + } +} + +export type CreateServerFileRoute< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TChildren, +> = ( + options?: undefined, +) => ServerRoute + +export type AnyServerRouteWithTypes = ServerRouteWithTypes< + any, + any, + any, + any, + any, + any, + any +> + +export interface ServerRouteWithTypes< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TMiddlewares, + TMethods, + TChildren, +> { + _types: ServerRouteTypes< + TParentRoute, + TId, + TPath, + TFullPath, + TMiddlewares, + TMethods + > + path: TPath + id: TId + fullPath: TFullPath + to: TrimPathRight + parentRoute: TParentRoute + children?: TChildren + options: ServerRouteOptions + update: ( + opts: ServerRouteOptions, + ) => ServerRoute + init: (opts: { originalIndex: number }) => void + _addFileChildren: ServerRouteAddFileChildrenFn< + TParentRoute, + TId, + TPath, + TFullPath, + TMiddlewares, + TMethods, + TChildren + > + _addFileTypes: () => ServerRouteWithTypes< + TParentRoute, + TId, + TPath, + TFullPath, + TMiddlewares, + TMethods, + TChildren + > +} + +export interface ServerRouteTypes< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TMiddlewares, + TMethods, +> { + id: TId + path: TPath + fullPath: TFullPath + middlewares: TMiddlewares + methods: TMethods + parentRoute: TParentRoute + allContext: ResolveAllServerContext +} + +export type ResolveAllServerContext< + TParentRoute extends AnyServerRouteWithTypes, + TMiddlewares, +> = unknown extends TParentRoute + ? AssignAllServerContext + : Assign< + TParentRoute['_types']['allContext'], + AssignAllServerContext + > + +export type AnyServerRoute = AnyServerRouteWithTypes + +export interface ServerRoute< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TChildren, +> extends ServerRouteWithTypes< + TParentRoute, + TId, + TPath, + TFullPath, + undefined, + undefined, + TChildren + >, + ServerRouteMiddleware, + ServerRouteMethods< + TParentRoute, + TId, + TPath, + TFullPath, + undefined, + TChildren + > {} + +export interface ServerRouteMiddleware< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TChildren, +> { + middleware: ( + middleware: Constrain>, + ) => ServerRouteAfterMiddleware< + TParentRoute, + TId, + TPath, + TFullPath, + TNewMiddleware, + TChildren + > +} + +export interface ServerRouteAfterMiddleware< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TMiddlewares, + TChildren, +> extends ServerRouteWithTypes< + TParentRoute, + TId, + TPath, + TFullPath, + TMiddlewares, + undefined, + TChildren + >, + ServerRouteMethods< + TParentRoute, + TId, + TPath, + TFullPath, + TMiddlewares, + TChildren + > {} + +export interface ServerRouteMethods< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TMiddlewares, + TChildren, +> { + methods: ( + methodsOrGetMethods: Constrain< + TMethods, + ServerRouteMethodsOptions + >, + ) => ServerRouteAfterMethods< + TParentRoute, + TId, + TPath, + TFullPath, + TMiddlewares, + TMethods, + TChildren + > +} + +export type ServerRouteMethodsOptions< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, +> = + | ServerRouteMethodsRecord + | (( + api: ServerRouteMethodBuilder, + ) => ServerRouteMethodsRecord) + +export interface ServerRouteMethodsRecord< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, +> { + GET?: ServerRouteMethodRecordValue + POST?: ServerRouteMethodRecordValue + PUT?: ServerRouteMethodRecordValue + PATCH?: ServerRouteMethodRecordValue + DELETE?: ServerRouteMethodRecordValue + OPTIONS?: ServerRouteMethodRecordValue + HEAD?: ServerRouteMethodRecordValue +} + +export type ServerRouteMethodRecordValue< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, +> = + | ServerRouteMethodHandlerFn< + TParentRoute, + TFullPath, + TMiddlewares, + undefined, + any + > + | AnyRouteMethodsBuilder + +export type ServerRouteVerb = (typeof ServerRouteVerbs)[number] + +export const ServerRouteVerbs = [ + 'GET', + 'POST', + 'PUT', + 'PATCH', + 'DELETE', + 'OPTIONS', + 'HEAD', +] as const + +export type ServerRouteMethodHandlerFn< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, + TMethodMiddlewares, + TResponse, +> = ( + ctx: ServerRouteMethodHandlerCtx< + TParentRoute, + TFullPath, + TMiddlewares, + TMethodMiddlewares + >, +) => TResponse | Promise + +export interface ServerRouteMethodHandlerCtx< + in out TParentRoute extends AnyServerRouteWithTypes, + in out TFullPath extends string, + in out TMiddlewares, + in out TMethodMiddlewares, +> { + context: Expand< + AssignAllMethodContext + > + request: Request + params: Expand> + pathname: TFullPath +} + +export type MergeMethodMiddlewares = + TMiddlewares extends ReadonlyArray + ? TMethodMiddlewares extends ReadonlyArray + ? readonly [...TMiddlewares, ...TMethodMiddlewares] + : TMiddlewares + : TMethodMiddlewares + +export type AssignAllMethodContext< + TParentRoute extends AnyServerRouteWithTypes, + TMiddlewares, + TMethodMiddlewares, +> = ResolveAllServerContext< + TParentRoute, + MergeMethodMiddlewares +> + +export type AnyRouteMethodsBuilder = ServerRouteMethodBuilderWithTypes< + any, + any, + any, + any +> + +export interface ServerRouteMethodBuilder< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, +> extends ServerRouteMethodBuilderWithTypes< + TFullPath, + TMiddlewares, + undefined, + undefined + >, + ServerRouteMethodBuilderMiddleware, + ServerRouteMethodBuilderHandler< + TParentRoute, + TFullPath, + TMiddlewares, + undefined + > {} + +export interface ServerRouteMethodBuilderWithTypes< + TFullPath extends string, + TMiddlewares, + TMethodMiddlewares, + TResponse, +> { + _options: TODO + _types: ServerRouteMethodBuilderTypes< + TFullPath, + TMiddlewares, + TMethodMiddlewares, + TResponse + > +} + +export interface ServerRouteMethodBuilderTypes< + in out TFullPath extends string, + in out TMiddlewares, + in out TMethodMiddlewares, + in out TResponse, +> { + middlewares: TMiddlewares + methodMiddleware: TMethodMiddlewares + fullPath: TFullPath + response: TResponse +} + +export interface ServerRouteMethodBuilderMiddleware< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, +> { + middleware: ( + middleware: Constrain< + TNewMethodMiddlewares, + ReadonlyArray + >, + ) => ServerRouteMethodBuilderAfterMiddleware< + TParentRoute, + TFullPath, + TMiddlewares, + TNewMethodMiddlewares + > +} + +export interface ServerRouteMethodBuilderAfterMiddleware< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, + TMethodMiddlewares, +> extends ServerRouteMethodBuilderWithTypes< + TFullPath, + TMiddlewares, + TMethodMiddlewares, + undefined + >, + ServerRouteMethodBuilderHandler< + TParentRoute, + TFullPath, + TMiddlewares, + TMethodMiddlewares + > {} + +export interface ServerRouteMethodBuilderHandler< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, + TMethodMiddlewares, +> { + handler: ( + handler: ServerRouteMethodHandlerFn< + TParentRoute, + TFullPath, + TMiddlewares, + TMethodMiddlewares, + TResponse + >, + ) => ServerRouteMethodBuilderAfterHandler< + TParentRoute, + TFullPath, + TMiddlewares, + TMethodMiddlewares, + TResponse + > +} + +export interface ServerRouteMethodBuilderAfterHandler< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, + TMethodMiddlewares, + TResponse, +> extends ServerRouteMethodBuilderWithTypes< + TFullPath, + TMiddlewares, + TMethodMiddlewares, + TResponse + > { + opts: ServerRouteMethod< + TParentRoute, + TFullPath, + TMiddlewares, + TMethodMiddlewares + > +} + +export interface ServerRouteMethod< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, + TMethodMiddlewares, +> { + middleware?: Constrain> + handler?: ServerRouteMethodHandlerFn< + TParentRoute, + TFullPath, + TMiddlewares, + TMethodMiddlewares, + undefined + > +} + +export interface ServerRouteAfterMethods< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TMiddlewares, + TMethods, + TChildren, +> extends ServerRouteWithTypes< + TParentRoute, + TId, + TPath, + TFullPath, + TMiddlewares, + TMethods, + TChildren + > { + options: ServerRouteOptions +} diff --git a/packages/start-server-core/src/ssr-server.ts b/packages/start-server-core/src/ssr-server.ts index a7f8378310..2c3e897fdf 100644 --- a/packages/start-server-core/src/ssr-server.ts +++ b/packages/start-server-core/src/ssr-server.ts @@ -105,6 +105,8 @@ export function dehydrateRouter(router: AnyRouter) { const dehydratedRouter: DehydratedRouter = { manifest: router.ssr!.manifest, dehydratedData: router.options.dehydrate?.(), + lastMatchId: + router.state.matches[router.state.matches.length - 1]?.id || '', } router.serverSsr!.injectScript( diff --git a/packages/start-server-core/src/tanstack-start.d.ts b/packages/start-server-core/src/tanstack-start.d.ts new file mode 100644 index 0000000000..62f36aeb9b --- /dev/null +++ b/packages/start-server-core/src/tanstack-start.d.ts @@ -0,0 +1,5 @@ +declare module 'tanstack-start-router-manifest:v' { + import type { Manifest } from '@tanstack/router-core' + + export const tsrStartManifest: () => Manifest +} diff --git a/packages/start-server-core/tests/serverRoute.test-d.ts b/packages/start-server-core/tests/serverRoute.test-d.ts new file mode 100644 index 0000000000..1934238b06 --- /dev/null +++ b/packages/start-server-core/tests/serverRoute.test-d.ts @@ -0,0 +1,286 @@ +import { expectTypeOf, test } from 'vitest' +import { json } from '../../start-client-core/src/json' +import { createMiddleware } from '../../start-client-core/src/createMiddleware' +import { createServerFileRoute as defaultCreateServerFileRoute } from '../src/serverRoute' +import type { CreateServerFileRoute } from '../src/serverRoute' + +test('createServerFileRoute with methods with no middleware', () => { + type Path = '$detailId' + const createServerFileRoute: CreateServerFileRoute< + any, + Path, + Path, + Path, + unknown + > = defaultCreateServerFileRoute + + const serverFileRoute = createServerFileRoute() + + expectTypeOf(serverFileRoute).toHaveProperty('methods') + expectTypeOf(serverFileRoute).toHaveProperty('middleware') + + serverFileRoute.methods({ + GET: (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + context: undefined + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ + test: 'test', + }) + }, + }) + + serverFileRoute.methods((r) => ({ + GET: r.handler((ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + context: undefined + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ + test: 'test', + }) + }), + })) +}) + +test('createServerFileRoute with methods and route middleware context', () => { + type Path = '$detailId' + const createServerFileRoute: CreateServerFileRoute< + any, + Path, + Path, + Path, + unknown + > = defaultCreateServerFileRoute + + const routeMiddleware = createMiddleware({ type: 'request' }).server( + ({ next }) => next({ context: { a: 'a' } }), + ) + + const serverFileRoute = createServerFileRoute().middleware([routeMiddleware]) + + serverFileRoute.methods({ + GET: (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + context: { a: string } + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ + test: 'test', + }) + }, + }) + + serverFileRoute.methods((r) => ({ + GET: r.handler((ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + context: { a: string } + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ + test: 'test', + }) + }), + })) +}) + +test('createServerFileRoute with methods middleware and route middleware', () => { + type Path = '$detailId' + const createServerFileRoute: CreateServerFileRoute< + any, + Path, + Path, + Path, + unknown + > = defaultCreateServerFileRoute + + const routeMiddleware = createMiddleware({ type: 'request' }).server( + ({ next }) => next({ context: { a: 'a' } }), + ) + + const serverFileRoute = createServerFileRoute().middleware([routeMiddleware]) + + const methodMiddleware = createMiddleware({ type: 'request' }).server( + ({ next }) => next({ context: { b: 'b' } }), + ) + + serverFileRoute.methods((r) => ({ + GET: r.middleware([methodMiddleware]).handler((ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + context: { a: string; b: string } + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ + test: 'test', + }) + }), + })) +}) + +test('createServerFileRoute with a parent middleware context', () => { + const createDetailsServerFileRoute: CreateServerFileRoute< + any, + 'details', + 'details', + 'details', + unknown + > = defaultCreateServerFileRoute + + const routeMiddleware1 = createMiddleware({ type: 'request' }).server( + ({ next }) => { + return next({ context: { a: 'a' } }) + }, + ) + + const _detailsServerRoute = createDetailsServerFileRoute().middleware([ + routeMiddleware1, + ]) + + const createDetailServerFileRoute: CreateServerFileRoute< + typeof _detailsServerRoute, + 'details/$detailId', + '$detailId', + 'details/$detailId', + unknown + > = defaultCreateServerFileRoute + + const routeMiddleware2 = createMiddleware({ type: 'request' }).server( + ({ next }) => { + return next({ context: { b: 'b' } }) + }, + ) + + createDetailServerFileRoute() + .middleware([routeMiddleware2]) + .methods({ + GET: (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + context: { a: string; b: string } + params: { detailId: string } + pathname: 'details/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }, + }) + + const methodMiddleware = createMiddleware({ type: 'request' }).server( + ({ next }) => { + return next({ context: { c: 'c' } }) + }, + ) + + createDetailServerFileRoute() + .middleware([routeMiddleware2]) + .methods((r) => ({ + GET: r.middleware([methodMiddleware]).handler((ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + context: { a: string; b: string; c: string } + params: { detailId: string } + pathname: 'details/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) +}) + +test('createServerFileRoute with parent middleware params', () => { + const createDetailsServerFileRoute: CreateServerFileRoute< + any, + '$userId', + '$userId', + '$userId', + unknown + > = defaultCreateServerFileRoute + + const _detailsServerRoute = createDetailsServerFileRoute() + + const createDetailServerFileRoute: CreateServerFileRoute< + typeof _detailsServerRoute, + '$userId/$detailId', + '$detailId', + '$userId/$detailId', + unknown + > = defaultCreateServerFileRoute + + createDetailServerFileRoute().methods({ + GET: (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + context: undefined + params: { userId: string; detailId: string } + pathname: '$userId/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }, + }) + + createDetailServerFileRoute().methods((r) => ({ + GET: r.handler((ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + context: undefined + params: { userId: string; detailId: string } + pathname: '$userId/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) +}) + +test('createServerFileRoute with no params', () => { + const createDetailsServerFileRoute: CreateServerFileRoute< + any, + 'details', + 'details', + 'details', + unknown + > = defaultCreateServerFileRoute + + createDetailsServerFileRoute().methods({ + GET: (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + context: undefined + params: {} + pathname: 'details' + request: Request + }>() + + return json({ test: 'test' }) + }, + }) + + createDetailsServerFileRoute().methods((r) => ({ + GET: r.handler((ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + context: undefined + params: {} + pathname: 'details' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) +}) diff --git a/packages/start-server-core/vite.config.ts b/packages/start-server-core/vite.config.ts index 2f1ffffb80..acf5a7e3ee 100644 --- a/packages/start-server-core/vite.config.ts +++ b/packages/start-server-core/vite.config.ts @@ -19,5 +19,10 @@ export default mergeConfig( tanstackViteConfig({ srcDir: './src', entry: './src/index.tsx', + externalDeps: [ + 'tanstack-start-server-fn-manifest:v', + 'tanstack-start-router-manifest:v', + 'tanstack-start-server-routes-manifest:v', + ], }), ) diff --git a/packages/start-server-functions-client/README.md b/packages/start-server-functions-client/README.md index bb009b0c87..68beb4f16b 100644 --- a/packages/start-server-functions-client/README.md +++ b/packages/start-server-functions-client/README.md @@ -1,33 +1,12 @@ -> 🤫 we're cooking up something special! - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) +# TanStack Start - Server Functions Client -🤖 Type-safe router w/ built-in caching & URL state management for React! +This package is not meant to be used directly. It is a dependency of the TanStack Start framework-specific packages: - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - +- [`@tanstack/react-start`](https://www.npmjs.com/package/@tanstack/react-start) +- [`@tanstack/solid-start`](https://www.npmjs.com/package/@tanstack/solid-start). -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) +It provides the core functionality for TanStack Start, which is a fullstack-framework made for SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router). -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! +Head over to [tanstack.com/start](https://tanstack.com/start) for more information about getting started. diff --git a/packages/start-server-functions-client/package.json b/packages/start-server-functions-client/package.json index 8878f1ea62..d5967dbb63 100644 --- a/packages/start-server-functions-client/package.json +++ b/packages/start-server-functions-client/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/start-server-functions-client", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/start-server-functions-fetcher/README.md b/packages/start-server-functions-fetcher/README.md index bb009b0c87..9039fddc7c 100644 --- a/packages/start-server-functions-fetcher/README.md +++ b/packages/start-server-functions-fetcher/README.md @@ -1,33 +1,12 @@ -> 🤫 we're cooking up something special! - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) +# TanStack Start - Server Functions Fetcher -🤖 Type-safe router w/ built-in caching & URL state management for React! +This package is not meant to be used directly. It is a dependency of the TanStack Start framework-specific packages: - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - +- [`@tanstack/react-start`](https://www.npmjs.com/package/@tanstack/react-start) +- [`@tanstack/solid-start`](https://www.npmjs.com/package/@tanstack/solid-start). -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) +It provides the core functionality for TanStack Start, which is a fullstack-framework made for SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router). -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! +Head over to [tanstack.com/start](https://tanstack.com/start) for more information about getting started. diff --git a/packages/start-server-functions-fetcher/package.json b/packages/start-server-functions-fetcher/package.json index e8e5ec5828..95036205f3 100644 --- a/packages/start-server-functions-fetcher/package.json +++ b/packages/start-server-functions-fetcher/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/start-server-functions-fetcher", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/start-server-functions-fetcher/src/index.ts b/packages/start-server-functions-fetcher/src/index.ts index f12e725a2f..8908d0652c 100644 --- a/packages/start-server-functions-fetcher/src/index.ts +++ b/packages/start-server-functions-fetcher/src/index.ts @@ -3,9 +3,10 @@ import { isNotFound, isPlainObject, isRedirect, + parseRedirect, } from '@tanstack/router-core' import { startSerializer } from '@tanstack/start-client-core' -import type { MiddlewareClientFnOptions } from '@tanstack/start-client-core' +import type { FunctionMiddlewareClientFnOptions } from '@tanstack/start-client-core' export async function serverFnFetcher( url: string, @@ -17,7 +18,7 @@ export async function serverFnFetcher( // If createServerFn was used to wrap the fetcher, // We need to handle the arguments differently if (isPlainObject(_first) && _first.method) { - const first = _first as MiddlewareClientFnOptions & { + const first = _first as FunctionMiddlewareClientFnOptions & { headers: HeadersInit } const type = first.data instanceof FormData ? 'formData' : 'payload' @@ -28,6 +29,7 @@ export async function serverFnFetcher( ? { 'content-type': 'application/json', accept: 'application/json', + 'x-tsr-redirect': 'manual', } : {}), ...(first.headers instanceof Headers @@ -63,62 +65,34 @@ export async function serverFnFetcher( url += `&raw` } - const handlerResponse = await handler(url, { - method: first.method, - headers, - signal: first.signal, - ...getFetcherRequestOptions(first), - }) - - const response = await handleResponseErrors(handlerResponse) - - // Check if the response is JSON - if (response.headers.get('content-type')?.includes('application/json')) { - // Even though the response is JSON, we need to decode it - // because the server may have transformed it - const json = startSerializer.decode(await response.json()) - - // If the response is a redirect or not found, throw it - // for the router to handle - if (isRedirect(json) || isNotFound(json) || json instanceof Error) { - throw json - } - - return json - } - - // Must be a raw response - return response + return await getResponse(() => + handler(url, { + method: first.method, + headers, + signal: first.signal, + ...getFetcherRequestOptions(first), + }), + ) } // If not a custom fetcher, it was probably // a `use server` function, so just proxy the arguments // through as a POST request - const response = await handleResponseErrors( - await handler(url, { + return await getResponse(() => + handler(url, { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify(args), + redirect: 'manual', }), ) - - // If the response is JSON, return it parsed - const contentType = response.headers.get('content-type') - if (contentType && contentType.includes('application/json')) { - return startSerializer.decode(await response.json()) - } else { - // Otherwise, return the text as a fallback - // If the user wants more than this, they can pass a - // request instead - return response.text() - } } function getFetcherRequestOptions( - opts: MiddlewareClientFnOptions, + opts: FunctionMiddlewareClientFnOptions, ) { if (opts.method === 'POST') { if (opts.data instanceof FormData) { @@ -139,17 +113,58 @@ function getFetcherRequestOptions( return {} } -async function handleResponseErrors(response: Response) { +/** + * Retrieves a response from a given function and manages potential errors + * and special response types including redirects and not found errors. + * + * @param fn - The function to execute for obtaining the response. + * @returns The processed response from the function. + * @throws If the response is invalid or an error occurs during processing. + */ +async function getResponse(fn: () => Promise) { + const response = await (async () => { + try { + return await fn() + } catch (error) { + if (error instanceof Response) { + return error + } + + throw error + } + })() + + // If the response is not ok, throw an error if (!response.ok) { const contentType = response.headers.get('content-type') const isJson = contentType && contentType.includes('application/json') if (isJson) { + // If it's JSON, decode it and throw it throw startSerializer.decode(await response.json()) } throw new Error(await response.text()) } + // Check if the response is JSON + if (response.headers.get('content-type')?.includes('application/json')) { + // Even though the response is JSON, we need to decode it + // because the server may have transformed it + let json = startSerializer.decode(await response.json()) + + const redirect = parseRedirect(json) + + if (redirect) json = redirect + + // If the response is a redirect or not found, throw it + // for the router to handle + if (isRedirect(json) || isNotFound(json) || json instanceof Error) { + throw json + } + + return json + } + return response } diff --git a/packages/start-server-functions-handler/README.md b/packages/start-server-functions-handler/README.md deleted file mode 100644 index bb009b0c87..0000000000 --- a/packages/start-server-functions-handler/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/start-server-functions-handler/eslint.config.js b/packages/start-server-functions-handler/eslint.config.js deleted file mode 100644 index bd7118fa1a..0000000000 --- a/packages/start-server-functions-handler/eslint.config.js +++ /dev/null @@ -1,20 +0,0 @@ -// @ts-check - -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - files: ['**/*.{ts,tsx}'], - }, - { - plugins: {}, - rules: {}, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/start-server-functions-handler/package.json b/packages/start-server-functions-handler/package.json deleted file mode 100644 index cec8c3d19a..0000000000 --- a/packages/start-server-functions-handler/package.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "@tanstack/start-server-functions-handler", - "version": "1.120.3", - "description": "Modern and scalable routing for applications", - "author": "Tanner Linsley", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/TanStack/router.git", - "directory": "packages/start-server-functions-handler" - }, - "homepage": "https://tanstack.com/start", - "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": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, - "type": "module", - "types": "dist/esm/index.d.ts", - "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" - }, - "dependencies": { - "@tanstack/router-core": "workspace:^", - "@tanstack/start-client-core": "workspace:^", - "@tanstack/start-server-core": "workspace:^", - "tiny-invariant": "^1.3.3" - }, - "devDependencies": { - "typescript": "^5.7.2" - } -} diff --git a/packages/start-server-functions-handler/tsconfig.json b/packages/start-server-functions-handler/tsconfig.json deleted file mode 100644 index 0484835e6b..0000000000 --- a/packages/start-server-functions-handler/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "module": "esnext" - }, - "include": ["src", "vite.config.ts"] -} diff --git a/packages/start-server-functions-handler/vite.config.ts b/packages/start-server-functions-handler/vite.config.ts deleted file mode 100644 index cc9124d7d8..0000000000 --- a/packages/start-server-functions-handler/vite.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { defineConfig, mergeConfig } from 'vitest/config' -import { tanstackViteConfig } from '@tanstack/config/vite' -import packageJson from './package.json' -import type { ViteUserConfig } from 'vitest/config' - -const config = defineConfig({ - plugins: [] as ViteUserConfig['plugins'], - test: { - name: packageJson.name, - watch: false, - environment: 'jsdom', - }, -}) - -export default mergeConfig( - config, - tanstackViteConfig({ - entry: './src/index.ts', - srcDir: './src', - externalDeps: ['tsr:server-fn-manifest'], - }), -) diff --git a/packages/start-server-functions-server/README.md b/packages/start-server-functions-server/README.md index 2e1cf02055..5037151f69 100644 --- a/packages/start-server-functions-server/README.md +++ b/packages/start-server-functions-server/README.md @@ -1,33 +1,12 @@ -> 🤫 we're cooking up something special! - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) +# TanStack Start - Server Functions Server -🤖 Type-safe router w/ built-in caching & URL state management! +This package is not meant to be used directly. It is a dependency of the TanStack Start framework-specific packages: - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - +- [`@tanstack/react-start`](https://www.npmjs.com/package/@tanstack/react-start) +- [`@tanstack/solid-start`](https://www.npmjs.com/package/@tanstack/solid-start). -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) +It provides the core functionality for TanStack Start, which is a fullstack-framework made for SSR, Streaming, Server Functions, API Routes, bundling and more powered by [TanStack Router](https://tanstack.com/router). -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! +Head over to [tanstack.com/start](https://tanstack.com/start) for more information about getting started. diff --git a/packages/start-server-functions-server/package.json b/packages/start-server-functions-server/package.json index d7011d4a02..0463b26718 100644 --- a/packages/start-server-functions-server/package.json +++ b/packages/start-server-functions-server/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/start-server-functions-server", - "version": "1.119.2", + "version": "1.121.0-alpha.8", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/start-server-functions-ssr/README.md b/packages/start-server-functions-ssr/README.md deleted file mode 100644 index bb009b0c87..0000000000 --- a/packages/start-server-functions-ssr/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/start-server-functions-ssr/eslint.config.js b/packages/start-server-functions-ssr/eslint.config.js deleted file mode 100644 index bd7118fa1a..0000000000 --- a/packages/start-server-functions-ssr/eslint.config.js +++ /dev/null @@ -1,20 +0,0 @@ -// @ts-check - -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - files: ['**/*.{ts,tsx}'], - }, - { - plugins: {}, - rules: {}, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/start-server-functions-ssr/package.json b/packages/start-server-functions-ssr/package.json deleted file mode 100644 index b9feda56bc..0000000000 --- a/packages/start-server-functions-ssr/package.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "@tanstack/start-server-functions-ssr", - "version": "1.120.3", - "description": "Modern and scalable routing for applications", - "author": "Tanner Linsley", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/TanStack/router.git", - "directory": "packages/start-server-functions-ssr" - }, - "homepage": "https://tanstack.com/start", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "keywords": [ - "location", - "router", - "routing", - "async", - "async router", - "typescript" - ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, - "type": "module", - "types": "dist/esm/index.d.ts", - "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" - }, - "dependencies": { - "@tanstack/server-functions-plugin": "workspace:^", - "@tanstack/start-server-functions-fetcher": "workspace:^", - "@tanstack/start-client-core": "workspace:^", - "@tanstack/start-server-core": "workspace:^", - "tiny-invariant": "^1.3.3" - }, - "devDependencies": { - "typescript": "^5.7.2" - } -} diff --git a/packages/start-server-functions-ssr/src/index.ts b/packages/start-server-functions-ssr/src/index.ts deleted file mode 100644 index 0d3430fe71..0000000000 --- a/packages/start-server-functions-ssr/src/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -/// -import { serverFnFetcher } from '@tanstack/start-server-functions-fetcher' -import { mergeHeaders } from '@tanstack/start-client-core' -import { getEvent, getHeaders } from '@tanstack/start-server-core' -import type { CreateRpcFn } from '@tanstack/server-functions-plugin' - -function sanitizeBase(base: string) { - return base.replace(/^\/|\/$/g, '') -} - -export const createSsrRpc: CreateRpcFn = (functionId, serverBase) => { - const url = `/${sanitizeBase(serverBase)}/${functionId}` - - const ssrFn = (...args: Array) => { - return serverFnFetcher(url, args, async (url, requestInit) => { - // pass on the headers from the document request to the server function fetch - requestInit.headers = mergeHeaders(getHeaders(), requestInit.headers) - // @ts-expect-error The $fetch.native method is not typed yet - const res: Response = await $fetch.native(url, requestInit) - const event = getEvent() - const mergedHeaders = mergeHeaders( - res.headers, - (event as any).___ssrRpcResponseHeaders, - ) - - // any response headers set in the server function need to be set on the document response - // we attach the headers to the event so we can later set them - ;(event as any).___ssrRpcResponseHeaders = mergedHeaders - return res - }) - } - - return Object.assign(ssrFn, { - url, - functionId, - }) -} diff --git a/packages/start-server-functions-ssr/tsconfig.json b/packages/start-server-functions-ssr/tsconfig.json deleted file mode 100644 index 51dda9abf2..0000000000 --- a/packages/start-server-functions-ssr/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "jsx": "react-jsx", - "module": "esnext" - }, - "include": ["src", "vite.config.ts"] -} diff --git a/packages/start-server-functions-ssr/tsconfigs/config.tsconfig.json b/packages/start-server-functions-ssr/tsconfigs/config.tsconfig.json deleted file mode 100644 index 58fc33fb0a..0000000000 --- a/packages/start-server-functions-ssr/tsconfigs/config.tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - "include": ["../src/config/index.ts"], - "compilerOptions": { - "rootDir": "../src/config", - "outDir": "../dist/esm/config", - "target": "esnext", - "noEmit": false - } -} diff --git a/packages/start-server-functions-ssr/tsconfigs/router-manifest.tsconfig.json b/packages/start-server-functions-ssr/tsconfigs/router-manifest.tsconfig.json deleted file mode 100644 index cc108d2494..0000000000 --- a/packages/start-server-functions-ssr/tsconfigs/router-manifest.tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - "include": ["../src/router-manifest/index.ts"], - "compilerOptions": { - "rootDir": "../src/router-manifest", - "outDir": "../dist/esm/router-manifest", - "target": "esnext", - "noEmit": false - } -} diff --git a/packages/start/README.md b/packages/start/README.md deleted file mode 100644 index bb009b0c87..0000000000 --- a/packages/start/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/start/eslint.config.js b/packages/start/eslint.config.js deleted file mode 100644 index 931f0ec774..0000000000 --- a/packages/start/eslint.config.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check - -import pluginReact from '@eslint-react/eslint-plugin' -import pluginReactHooks from 'eslint-plugin-react-hooks' -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - ...pluginReact.configs.recommended, - files: ['**/*.{ts,tsx}'], - }, - { - plugins: { - 'react-hooks': pluginReactHooks, - }, - rules: { - '@eslint-react/no-unstable-context-value': 'off', - '@eslint-react/no-unstable-default-props': 'off', - '@eslint-react/dom/no-missing-button-type': 'off', - 'react-hooks/exhaustive-deps': 'error', - 'react-hooks/rules-of-hooks': 'error', - }, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/start/package.json b/packages/start/package.json deleted file mode 100644 index 2a4f92a117..0000000000 --- a/packages/start/package.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "name": "@tanstack/start", - "version": "1.120.3", - "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/start" - }, - "homepage": "https://tanstack.com/start", - "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": "pnpm test:build", - "test:build": "exit 0; vitest", - "build": "vite build" - }, - "type": "module", - "types": "dist/esm/client.d.ts", - "exports": { - ".": { - "import": { - "types": "./dist/esm/client.d.ts", - "default": "./dist/esm/client.js" - }, - "require": { - "types": "./dist/cjs/client.d.cts", - "default": "./dist/cjs/client.cjs" - } - }, - "./client": { - "import": { - "types": "./dist/esm/client.d.ts", - "default": "./dist/esm/client.js" - }, - "require": { - "types": "./dist/cjs/client.d.cts", - "default": "./dist/cjs/client.cjs" - } - }, - "./server": { - "import": { - "types": "./dist/esm/server.d.ts", - "default": "./dist/esm/server.js" - }, - "require": { - "types": "./dist/cjs/server.d.cts", - "default": "./dist/cjs/server.cjs" - } - }, - "./config": { - "import": { - "types": "./dist/esm/config.d.ts", - "default": "./dist/esm/config.js" - }, - "require": { - "types": "./dist/cjs/config.d.cts", - "default": "./dist/cjs/config.cjs" - } - }, - "./api": { - "import": { - "types": "./dist/esm/api.d.ts", - "default": "./dist/esm/api.js" - }, - "require": { - "types": "./dist/cjs/api.d.cts", - "default": "./dist/cjs/api.cjs" - } - }, - "./router-manifest": { - "import": { - "types": "./dist/esm/router-manifest.d.ts", - "default": "./dist/esm/router-manifest.js" - }, - "require": { - "types": "./dist/cjs/router-manifest.d.cts", - "default": "./dist/cjs/router-manifest.cjs" - } - }, - "./server-functions-client": { - "import": { - "types": "./dist/esm/server-functions-client.d.ts", - "default": "./dist/esm/server-functions-client.js" - }, - "require": { - "types": "./dist/cjs/server-functions-client.d.cts", - "default": "./dist/cjs/server-functions-client.cjs" - } - }, - "./server-functions-server": { - "import": { - "types": "./dist/esm/server-functions-server.d.ts", - "default": "./dist/esm/server-functions-server.js" - }, - "require": { - "types": "./dist/cjs/server-functions-server.d.cts", - "default": "./dist/cjs/server-functions-server.cjs" - } - }, - "./server-functions-handler": { - "import": { - "types": "./dist/esm/server-functions-handler.d.ts", - "default": "./dist/esm/server-functions-handler.js" - }, - "require": { - "types": "./dist/cjs/server-functions-handler.d.cts", - "default": "./dist/cjs/server-functions-handler.cjs" - } - }, - "./server-functions-ssr": { - "import": { - "types": "./dist/esm/server-functions-ssr.d.ts", - "default": "./dist/esm/server-functions-ssr.js" - }, - "require": { - "types": "./dist/cjs/server-functions-ssr.d.cts", - "default": "./dist/cjs/server-functions-ssr.cjs" - } - }, - "./package.json": "./package.json" - }, - "sideEffects": false, - "files": [ - "dist", - "src" - ], - "engines": { - "node": ">=12" - }, - "dependencies": { - "@tanstack/react-start-client": "workspace:^", - "@tanstack/react-start-server": "workspace:^", - "@tanstack/start-config": "workspace:^", - "@tanstack/react-start-router-manifest": "workspace:^", - "@tanstack/start-server-functions-client": "workspace:^", - "@tanstack/start-server-functions-server": "workspace:^", - "@tanstack/start-server-functions-handler": "workspace:^", - "@tanstack/start-server-functions-ssr": "workspace:^", - "@tanstack/start-api-routes": "workspace:^" - } -} diff --git a/packages/start/src/api.tsx b/packages/start/src/api.tsx deleted file mode 100644 index a28d259a44..0000000000 --- a/packages/start/src/api.tsx +++ /dev/null @@ -1,4 +0,0 @@ -console.warn( - '[@tanstack/start] Warning: This package has moved to @tanstack/react-start. Please switch to the new package, as this package will be dropped soon.', -) -export * from '@tanstack/start-api-routes' diff --git a/packages/start/src/client.tsx b/packages/start/src/client.tsx deleted file mode 100644 index e2a9aa5466..0000000000 --- a/packages/start/src/client.tsx +++ /dev/null @@ -1,4 +0,0 @@ -console.warn( - '[@tanstack/start] Warning: This package has moved to @tanstack/react-start. Please switch to the new package, as this package will be dropped soon.', -) -export * from '@tanstack/react-start-client' diff --git a/packages/start/src/config.tsx b/packages/start/src/config.tsx deleted file mode 100644 index 262bac966c..0000000000 --- a/packages/start/src/config.tsx +++ /dev/null @@ -1,4 +0,0 @@ -console.warn( - '[@tanstack/start] Warning: This package has moved to @tanstack/react-start. Please switch to the new package, as this package will be dropped soon.', -) -export * from '@tanstack/start-config' diff --git a/packages/start/src/router-manifest.tsx b/packages/start/src/router-manifest.tsx deleted file mode 100644 index 10e98ba06d..0000000000 --- a/packages/start/src/router-manifest.tsx +++ /dev/null @@ -1,4 +0,0 @@ -console.warn( - '[@tanstack/start] Warning: This package has moved to @tanstack/react-start. Please switch to the new package, as this package will be dropped soon.', -) -export * from '@tanstack/react-start-router-manifest' diff --git a/packages/start/src/server-functions-client.tsx b/packages/start/src/server-functions-client.tsx deleted file mode 100644 index d7baf052e5..0000000000 --- a/packages/start/src/server-functions-client.tsx +++ /dev/null @@ -1,4 +0,0 @@ -console.warn( - '[@tanstack/start] Warning: This package has moved to @tanstack/react-start. Please switch to the new package, as this package will be dropped soon.', -) -export * from '@tanstack/start-server-functions-client' diff --git a/packages/start/src/server-functions-handler.tsx b/packages/start/src/server-functions-handler.tsx deleted file mode 100644 index 9e7afcffff..0000000000 --- a/packages/start/src/server-functions-handler.tsx +++ /dev/null @@ -1,4 +0,0 @@ -console.warn( - '[@tanstack/start] Warning: This package has moved to @tanstack/react-start. Please switch to the new package, as this package will be dropped soon.', -) -export * from '@tanstack/start-server-functions-handler' diff --git a/packages/start/src/server-functions-server.tsx b/packages/start/src/server-functions-server.tsx deleted file mode 100644 index b78ff17125..0000000000 --- a/packages/start/src/server-functions-server.tsx +++ /dev/null @@ -1,4 +0,0 @@ -console.warn( - '[@tanstack/start] Warning: This package has moved to @tanstack/react-start. Please switch to the new package, as this package will be dropped soon.', -) -export * from '@tanstack/start-server-functions-server' diff --git a/packages/start/src/server-functions-ssr.tsx b/packages/start/src/server-functions-ssr.tsx deleted file mode 100644 index e66ed969c8..0000000000 --- a/packages/start/src/server-functions-ssr.tsx +++ /dev/null @@ -1,4 +0,0 @@ -console.warn( - '[@tanstack/start] Warning: This package has moved to @tanstack/react-start. Please switch to the new package, as this package will be dropped soon.', -) -export * from '@tanstack/start-server-functions-ssr' diff --git a/packages/start/src/server.tsx b/packages/start/src/server.tsx deleted file mode 100644 index 502e50b680..0000000000 --- a/packages/start/src/server.tsx +++ /dev/null @@ -1,4 +0,0 @@ -console.warn( - '[@tanstack/start] Warning: This package has moved to @tanstack/react-start. Please switch to the new package, as this package will be dropped soon.', -) -export * from '@tanstack/react-start-server' diff --git a/packages/start/tsconfig.json b/packages/start/tsconfig.json deleted file mode 100644 index 51dda9abf2..0000000000 --- a/packages/start/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "jsx": "react-jsx", - "module": "esnext" - }, - "include": ["src", "vite.config.ts"] -} diff --git a/packages/start/vite.config.ts b/packages/start/vite.config.ts deleted file mode 100644 index 7c6fa9afe4..0000000000 --- a/packages/start/vite.config.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { defineConfig, mergeConfig } from 'vitest/config' -import { tanstackViteConfig } from '@tanstack/config/vite' -import packageJson from './package.json' - -const config = defineConfig({ - test: { - name: packageJson.name, - watch: false, - environment: 'jsdom', - }, -}) - -export default mergeConfig( - config, - tanstackViteConfig({ - srcDir: './src', - entry: [ - './src/client.tsx', - './src/server.tsx', - './src/config.tsx', - './src/router-manifest.tsx', - './src/server-functions-client.tsx', - './src/server-functions-server.tsx', - './src/server-functions-ssr.tsx', - './src/api.tsx', - ], - externalDeps: [ - '@tanstack/react-start-client', - '@tanstack/react-start-server', - '@tanstack/start-config', - '@tanstack/react-start-router-manifest', - '@tanstack/start-server-functions-client', - '@tanstack/start-server-functions-server', - '@tanstack/start-server-functions-ssr', - '@tanstack/start-api-routes', - ], - }), -) diff --git a/packages/valibot-adapter/package.json b/packages/valibot-adapter/package.json index ce55411e1e..a4a1f39051 100644 --- a/packages/valibot-adapter/package.json +++ b/packages/valibot-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/valibot-adapter", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "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 70df4fa31f..d2fcd9e066 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.115.0", + "version": "1.121.0-alpha.1", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/zod-adapter/package.json b/packages/zod-adapter/package.json index 93af7a8aa8..6cb58750f5 100644 --- a/packages/zod-adapter/package.json +++ b/packages/zod-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/zod-adapter", - "version": "1.120.3", + "version": "1.121.0-alpha.11", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 93f882fd74..01d24505d9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,7 +11,7 @@ overrides: '@types/react': ^19.0.8 '@types/react-dom': ^19.0.3 eslint: ^9.22.0 - vite: 6.1.4 + vite: 6.3.5 '@playwright/test': ^1.52.0 '@tanstack/react-query': 5.66.0 '@tanstack/history': workspace:* @@ -42,12 +42,10 @@ overrides: '@tanstack/solid-start-plugin': workspace:* '@tanstack/solid-start-router-manifest': workspace:* '@tanstack/solid-start-server': workspace:* - '@tanstack/start-api-routes': workspace:* '@tanstack/start-server-functions-fetcher': workspace:* - '@tanstack/start-server-functions-handler': workspace:* '@tanstack/start-server-functions-client': workspace:* - '@tanstack/start-server-functions-ssr': workspace:* '@tanstack/start-server-functions-server': workspace:* + '@tanstack/start-plugin-core': workspace:* '@tanstack/start-client-core': workspace:* '@tanstack/start-server-core': workspace:* '@tanstack/eslint-plugin-router': workspace:* @@ -70,7 +68,7 @@ importers: version: 1.52.0 '@tanstack/config': specifier: ^0.16.1 - version: 0.16.1(@types/node@22.13.4)(esbuild@0.25.0)(eslint@9.22.0(jiti@2.4.2))(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 0.16.1(@types/node@22.13.4)(esbuild@0.25.2)(eslint@9.22.0(jiti@2.4.2))(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) '@tanstack/react-query': specifier: 5.66.0 version: 5.66.0(react@19.0.0) @@ -85,7 +83,7 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitest/browser': specifier: ^3.0.6 - version: 3.0.6(@types/node@22.13.4)(playwright@1.52.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))(vitest@3.0.6) + version: 3.0.6(@types/node@22.13.4)(playwright@1.52.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))(vitest@3.0.6) '@vitest/ui': specifier: ^3.0.6 version: 3.0.6(vitest@3.0.6) @@ -124,7 +122,7 @@ importers: version: 6.0.1 tinyglobby: specifier: ^0.2.12 - version: 0.2.12 + version: 0.2.13 typescript: specifier: ^5.8.2 version: 5.8.2 @@ -144,11 +142,11 @@ importers: specifier: npm:typescript@5.7 version: typescript@5.7.3 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vitest: specifier: ^3.0.6 - version: 3.0.6(@types/node@22.13.4)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@25.0.1)(lightningcss@1.29.1)(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + version: 3.0.6(@types/node@22.13.4)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@25.0.1)(lightningcss@1.29.2)(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) e2e/e2e-utils: {} @@ -193,10 +191,10 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) e2e/react-router/basic-esbuild-file-based: dependencies: @@ -239,7 +237,7 @@ importers: version: 19.0.3(@types/react@19.0.8) esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 e2e/react-router/basic-file-based: dependencies: @@ -291,13 +289,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) combinate: specifier: ^1.1.11 version: 1.1.11 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) e2e/react-router/basic-file-based-code-splitting: dependencies: @@ -343,10 +341,10 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) e2e/react-router/basic-react-query: dependencies: @@ -395,10 +393,10 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) e2e/react-router/basic-react-query-file-based: dependencies: @@ -453,10 +451,10 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) e2e/react-router/basic-scroll-restoration: dependencies: @@ -502,10 +500,10 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) e2e/react-router/basic-virtual-file-based: dependencies: @@ -557,10 +555,10 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) e2e/react-router/basic-virtual-named-export-config-file-based: dependencies: @@ -612,10 +610,10 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) e2e/react-router/generator-cli-only: dependencies: @@ -661,10 +659,10 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) e2e/react-router/js-only-file-based: dependencies: @@ -710,10 +708,10 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) e2e/react-router/rspack-basic-file-based: dependencies: @@ -872,10 +870,10 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) e2e/react-router/sentry-integration: dependencies: @@ -927,10 +925,10 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) e2e/react-start/basic: dependencies: @@ -940,9 +938,9 @@ importers: '@tanstack/react-router-devtools': specifier: workspace:^ version: link:../../../packages/react-router-devtools - '@tanstack/start': - specifier: workspace:^ - version: link:../../../packages/start + '@tanstack/react-start': + specifier: workspace:* + version: link:../../../packages/react-start react: specifier: ^19.0.0 version: 19.0.0 @@ -955,9 +953,9 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -979,7 +977,7 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.3) @@ -997,7 +995,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/react-start/basic-auth: dependencies: @@ -1028,9 +1026,9 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) devDependencies: '@playwright/test': specifier: ^1.52.0 @@ -1049,7 +1047,7 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.3) @@ -1064,7 +1062,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/react-start/basic-react-query: dependencies: @@ -1098,9 +1096,9 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) devDependencies: '@playwright/test': specifier: ^1.52.0 @@ -1119,7 +1117,7 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.3) @@ -1134,7 +1132,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/react-start/basic-rsc: dependencies: @@ -1162,9 +1160,9 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) devDependencies: '@types/react': specifier: ^19.0.8 @@ -1174,7 +1172,7 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.3) @@ -1189,7 +1187,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/react-start/basic-tsr-config: dependencies: @@ -1205,9 +1203,9 @@ importers: react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) devDependencies: '@tanstack/router-e2e-utils': specifier: workspace:^ @@ -1225,11 +1223,8 @@ importers: specifier: ^5.7.2 version: 5.8.2 - e2e/react-start/clerk-basic: + e2e/react-start/scroll-restoration: dependencies: - '@clerk/tanstack-react-start': - specifier: ^0.12.0 - version: 0.12.0(@tanstack/react-router@packages+react-router)(@tanstack/react-start@packages+react-start)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@tanstack/react-router': specifier: workspace:* version: link:../../../packages/react-router @@ -1239,6 +1234,9 @@ importers: '@tanstack/react-start': specifier: workspace:* version: link:../../../packages/react-start + '@tanstack/zod-adapter': + specifier: workspace:* + version: link:../../../packages/zod-adapter react: specifier: ^19.0.0 version: 19.0.0 @@ -1251,9 +1249,12 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + zod: + specifier: ^3.24.2 + version: 3.24.2 devDependencies: '@playwright/test': specifier: ^1.52.0 @@ -1272,10 +1273,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.3) + combinate: + specifier: ^1.1.11 + version: 1.1.11 postcss: specifier: ^8.5.1 version: 8.5.3 @@ -1287,9 +1291,9 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - e2e/react-start/scroll-restoration: + e2e/react-start/server-functions: dependencies: '@tanstack/react-router': specifier: workspace:* @@ -1300,9 +1304,9 @@ importers: '@tanstack/react-start': specifier: workspace:* version: link:../../../packages/react-start - '@tanstack/zod-adapter': - specifier: workspace:* - version: link:../../../packages/zod-adapter + js-cookie: + specifier: ^3.0.5 + version: 3.0.5 react: specifier: ^19.0.0 version: 19.0.0 @@ -1315,9 +1319,9 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -1328,6 +1332,9 @@ importers: '@tanstack/router-e2e-utils': specifier: workspace:^ version: link:../../e2e-utils + '@types/js-cookie': + specifier: ^3.0.6 + version: 3.0.6 '@types/node': specifier: ^22.10.2 version: 22.13.4 @@ -1339,7 +1346,7 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.3) @@ -1357,9 +1364,9 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - e2e/react-start/server-functions: + e2e/react-start/virtual-routes: dependencies: '@tanstack/react-router': specifier: workspace:* @@ -1370,9 +1377,9 @@ importers: '@tanstack/react-start': specifier: workspace:* version: link:../../../packages/react-start - js-cookie: - specifier: ^3.0.5 - version: 3.0.5 + '@tanstack/virtual-file-routes': + specifier: workspace:* + version: link:../../../packages/virtual-file-routes react: specifier: ^19.0.0 version: 19.0.0 @@ -1385,9 +1392,9 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -1398,9 +1405,6 @@ importers: '@tanstack/router-e2e-utils': specifier: workspace:^ version: link:../../e2e-utils - '@types/js-cookie': - specifier: ^3.0.6 - version: 3.0.6 '@types/node': specifier: ^22.10.2 version: 22.13.4 @@ -1412,7 +1416,7 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.3) @@ -1430,7 +1434,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/react-start/website: dependencies: @@ -1455,9 +1459,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -1479,7 +1480,7 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.3) @@ -1492,9 +1493,12 @@ importers: typescript: specifier: ^5.7.2 version: 5.8.2 + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-router/basic: dependencies: @@ -1527,11 +1531,11 @@ importers: specifier: workspace:^ version: link:../../e2e-utils vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-router/basic-esbuild-file-based: dependencies: @@ -1565,10 +1569,10 @@ importers: version: link:../../e2e-utils esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 esbuild-plugin-solid: specifier: ^0.6.0 - version: 0.6.0(esbuild@0.25.0)(solid-js@1.9.5) + version: 0.6.0(esbuild@0.25.2)(solid-js@1.9.5) e2e/solid-router/basic-file-based: dependencies: @@ -1613,11 +1617,11 @@ importers: specifier: ^1.1.11 version: 1.1.11 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-router/basic-file-based-code-splitting: dependencies: @@ -1653,11 +1657,11 @@ importers: specifier: workspace:^ version: link:../../e2e-utils vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-router/basic-scroll-restoration: dependencies: @@ -1693,20 +1697,20 @@ importers: specifier: workspace:^ version: link:../../e2e-utils vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-router/basic-solid-query: dependencies: '@tanstack/solid-query': specifier: ^5.71.9 - version: 5.71.9(solid-js@1.9.5) + version: 5.72.2(solid-js@1.9.5) '@tanstack/solid-query-devtools': specifier: ^5.71.9 - version: 5.71.9(@tanstack/solid-query@5.71.9(solid-js@1.9.5))(solid-js@1.9.5) + version: 5.72.2(@tanstack/solid-query@5.72.2(solid-js@1.9.5))(solid-js@1.9.5) '@tanstack/solid-router': specifier: workspace:^ version: link:../../../packages/solid-router @@ -1736,11 +1740,11 @@ importers: specifier: workspace:^ version: link:../../e2e-utils vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-router/basic-solid-query-file-based: dependencies: @@ -1749,10 +1753,10 @@ importers: version: link:../../../packages/router-plugin '@tanstack/solid-query': specifier: ^5.71.9 - version: 5.71.9(solid-js@1.9.5) + version: 5.72.2(solid-js@1.9.5) '@tanstack/solid-query-devtools': specifier: ^5.71.9 - version: 5.71.9(@tanstack/solid-query@5.71.9(solid-js@1.9.5))(solid-js@1.9.5) + version: 5.72.2(@tanstack/solid-query@5.72.2(solid-js@1.9.5))(solid-js@1.9.5) '@tanstack/solid-router': specifier: workspace:^ version: link:../../../packages/solid-router @@ -1785,11 +1789,11 @@ importers: specifier: workspace:^ version: link:../../e2e-utils vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-router/basic-virtual-file-based: dependencies: @@ -1831,11 +1835,11 @@ importers: specifier: workspace:^ version: link:../../e2e-utils vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-router/basic-virtual-named-export-config-file-based: dependencies: @@ -1877,11 +1881,11 @@ importers: specifier: workspace:^ version: link:../../e2e-utils vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-router/rspack-basic-file-based: dependencies: @@ -2018,11 +2022,11 @@ importers: specifier: workspace:^ version: link:../../e2e-utils vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-start/basic: dependencies: @@ -2044,9 +2048,9 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -2077,10 +2081,10 @@ importers: version: 5.8.2 vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-start/basic-tsr-config: dependencies: @@ -2096,9 +2100,9 @@ importers: solid-js: specifier: ^1.9.5 version: 1.9.5 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) devDependencies: '@tanstack/router-e2e-utils': specifier: workspace:^ @@ -2109,6 +2113,9 @@ importers: typescript: specifier: ^5.7.2 version: 5.8.2 + vite-tsconfig-paths: + specifier: ^5.1.4 + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-start/scroll-restoration: dependencies: @@ -2133,9 +2140,9 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -2166,10 +2173,10 @@ importers: version: 5.8.2 vite-plugin-solid: specifier: ^2.11.6 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-start/server-functions: dependencies: @@ -2194,9 +2201,9 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -2230,10 +2237,10 @@ importers: version: 5.8.2 vite-plugin-solid: specifier: ^2.11.6 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) e2e/solid-start/website: dependencies: @@ -2255,9 +2262,9 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -2285,10 +2292,10 @@ importers: version: 5.8.2 vite-plugin-solid: specifier: ^2.11.6 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/authenticated-routes: dependencies: @@ -2331,13 +2338,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/authenticated-routes-firebase: dependencies: @@ -2386,13 +2393,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/basic: dependencies: @@ -2429,13 +2436,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/basic-default-search-params: dependencies: @@ -2478,13 +2485,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/basic-devtools-panel: dependencies: @@ -2524,13 +2531,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/basic-file-based: dependencies: @@ -2573,13 +2580,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/basic-non-nested-devtools: dependencies: @@ -2616,13 +2623,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/basic-react-query: dependencies: @@ -2665,13 +2672,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/basic-react-query-file-based: dependencies: @@ -2720,156 +2727,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - typescript: - specifier: ^5.7.2 - version: 5.8.2 - vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - - examples/react/basic-ssr-file-based: - dependencies: - '@tanstack/react-router': - specifier: workspace:* - version: link:../../../packages/react-router - '@tanstack/react-router-devtools': - specifier: workspace:^ - version: link:../../../packages/react-router-devtools - '@tanstack/react-start': - specifier: workspace:* - version: link:../../../packages/react-start - '@tanstack/router-plugin': - specifier: workspace:* - version: link:../../../packages/router-plugin - get-port: - specifier: ^7.1.0 - version: 7.1.0 - react: - specifier: ^19.0.0 - version: 19.0.0 - react-dom: - specifier: ^19.0.0 - version: 19.0.0(react@19.0.0) - redaxios: - specifier: ^0.5.1 - version: 0.5.1 - devDependencies: - '@babel/core': - specifier: ^7.26.8 - version: 7.26.8 - '@babel/generator': - specifier: ^7.26.8 - version: 7.26.8 - '@rollup/plugin-babel': - specifier: ^6.0.4 - version: 6.0.4(@babel/core@7.26.8)(@types/babel__core@7.20.5)(rollup@4.39.0) - '@types/express': - specifier: ^4.17.21 - version: 4.17.21 - '@types/react': - specifier: ^19.0.8 - version: 19.0.8 - '@types/react-dom': - specifier: ^19.0.3 - version: 19.0.3(@types/react@19.0.8) - '@vitejs/plugin-react': - specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - compression: - specifier: ^1.7.5 - version: 1.7.5 - express: - specifier: ^4.21.2 - version: 4.21.2 - isbot: - specifier: ^5.1.22 - version: 5.1.22 - node-fetch: - specifier: ^3.3.2 - version: 3.3.2 - serve-static: - specifier: ^1.16.2 - version: 1.16.2 - typescript: - specifier: ^5.7.2 - version: 5.8.2 - vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - - examples/react/basic-ssr-streaming-file-based: - dependencies: - '@tanstack/react-router': - specifier: workspace:* - version: link:../../../packages/react-router - '@tanstack/react-router-devtools': - specifier: workspace:^ - version: link:../../../packages/react-router-devtools - '@tanstack/react-start': - specifier: workspace:* - version: link:../../../packages/react-start - '@tanstack/router-plugin': - specifier: workspace:* - version: link:../../../packages/router-plugin - get-port: - specifier: ^7.1.0 - version: 7.1.0 - react: - specifier: ^19.0.0 - version: 19.0.0 - react-dom: - specifier: ^19.0.0 - version: 19.0.0(react@19.0.0) - redaxios: - specifier: ^0.5.1 - version: 0.5.1 - superjson: - specifier: ^2.2.2 - version: 2.2.2 - devDependencies: - '@babel/core': - specifier: ^7.26.8 - version: 7.26.8 - '@babel/generator': - specifier: ^7.26.8 - version: 7.26.8 - '@rollup/plugin-babel': - specifier: ^6.0.4 - version: 6.0.4(@babel/core@7.26.8)(@types/babel__core@7.20.5)(rollup@4.39.0) - '@types/express': - specifier: ^4.17.21 - version: 4.17.21 - '@types/react': - specifier: ^19.0.8 - version: 19.0.8 - '@types/react-dom': - specifier: ^19.0.3 - version: 19.0.3(@types/react@19.0.8) - '@vitejs/plugin-react': - specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - compression: - specifier: ^1.7.5 - version: 1.7.5 - express: - specifier: ^4.21.2 - version: 4.21.2 - isbot: - specifier: ^5.1.22 - version: 5.1.22 - node-fetch: - specifier: ^3.3.2 - version: 3.3.2 - serve-static: - specifier: ^1.16.2 - version: 1.16.2 + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/basic-virtual-file-based: dependencies: @@ -2915,13 +2779,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/basic-virtual-inside-file-based: dependencies: @@ -2967,13 +2831,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/deferred-data: dependencies: @@ -3013,13 +2877,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/kitchen-sink: dependencies: @@ -3062,13 +2926,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/kitchen-sink-file-based: dependencies: @@ -3114,13 +2978,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/kitchen-sink-react-query: dependencies: @@ -3169,13 +3033,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/kitchen-sink-react-query-file-based: dependencies: @@ -3227,13 +3091,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/large-file-based: dependencies: @@ -3279,19 +3143,19 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/location-masking: dependencies: '@radix-ui/react-dialog': specifier: ^1.1.6 - version: 1.1.6(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@tanstack/react-query': specifier: 5.66.0 version: 5.66.0(react@19.0.0) @@ -3328,13 +3192,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/navigation-blocking: dependencies: @@ -3374,13 +3238,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/quickstart: dependencies: @@ -3414,13 +3278,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/quickstart-esbuild-file-based: dependencies: @@ -3454,7 +3318,7 @@ importers: version: 19.0.3(@types/react@19.0.8) esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 examples/react/quickstart-file-based: dependencies: @@ -3497,13 +3361,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/quickstart-rspack-file-based: dependencies: @@ -3586,7 +3450,7 @@ importers: version: 5.8.2 webpack: specifier: ^5.97.1 - version: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + version: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-cli: specifier: ^5.1.4 version: 5.1.4(webpack-dev-server@5.2.0)(webpack@5.97.1) @@ -3632,16 +3496,16 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-dts: specifier: ^4.5.0 - version: 4.5.0(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.5.0(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/router-monorepo-react-query/packages/app: dependencies: @@ -3672,7 +3536,7 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.3) @@ -3686,11 +3550,11 @@ importers: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-dts: specifier: ^4.5.0 - version: 4.5.0(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.5.0(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/router-monorepo-react-query/packages/post-feature: dependencies: @@ -3718,16 +3582,16 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-dts: specifier: ^4.5.0 - version: 4.5.0(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.5.0(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/router-monorepo-react-query/packages/post-query: dependencies: @@ -3743,13 +3607,13 @@ importers: devDependencies: '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/router-monorepo-react-query/packages/router: dependencies: @@ -3789,16 +3653,16 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-dts: specifier: ^4.5.0 - version: 4.5.0(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.5.0(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/router-monorepo-simple: dependencies: @@ -3832,16 +3696,16 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-dts: specifier: ^4.5.0 - version: 4.5.0(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.5.0(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/router-monorepo-simple-lazy: dependencies: @@ -3875,16 +3739,16 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-dts: specifier: ^4.5.0 - version: 4.5.0(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.5.0(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/router-monorepo-simple-lazy/packages/app: dependencies: @@ -3912,7 +3776,7 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.3) @@ -3926,11 +3790,11 @@ importers: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-dts: specifier: ^4.5.0 - version: 4.5.0(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.5.0(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/router-monorepo-simple-lazy/packages/post-feature: dependencies: @@ -3955,16 +3819,16 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-dts: specifier: ^4.5.0 - version: 4.5.0(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.5.0(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/router-monorepo-simple-lazy/packages/router: dependencies: @@ -3998,16 +3862,16 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-dts: specifier: ^4.5.0 - version: 4.5.0(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.5.0(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/router-monorepo-simple/packages/app: dependencies: @@ -4035,7 +3899,7 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.3) @@ -4049,11 +3913,11 @@ importers: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-dts: specifier: ^4.5.0 - version: 4.5.0(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.5.0(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/router-monorepo-simple/packages/post-feature: dependencies: @@ -4075,16 +3939,16 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-dts: specifier: ^4.5.0 - version: 4.5.0(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.5.0(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/router-monorepo-simple/packages/router: dependencies: @@ -4118,16 +3982,16 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-dts: specifier: ^4.5.0 - version: 4.5.0(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.5.0(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/scroll-restoration: dependencies: @@ -4164,13 +4028,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/search-validator-adapters: dependencies: @@ -4234,13 +4098,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/start-bare: dependencies: @@ -4259,16 +4123,13 @@ importers: react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 devDependencies: '@tailwindcss/vite': specifier: ^4.0.8 - version: 4.0.8(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.1.6(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) '@types/node': specifier: ^22.5.4 version: 22.13.4 @@ -4280,13 +4141,13 @@ importers: version: 19.0.3(@types/react@19.0.8) tailwindcss: specifier: ^4.0.8 - version: 4.0.8 + version: 4.1.6 typescript: specifier: ^5.7.2 version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/start-basic: dependencies: @@ -4308,9 +4169,12 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + zod: + specifier: ^3.24.2 + version: 3.24.2 devDependencies: '@types/node': specifier: ^22.5.4 @@ -4335,7 +4199,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/start-basic-auth: dependencies: @@ -4366,9 +4230,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -4393,7 +4254,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/start-basic-react-query: dependencies: @@ -4427,9 +4288,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -4454,7 +4312,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/start-basic-rsc: dependencies: @@ -4482,9 +4340,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/react': specifier: ^19.0.8 @@ -4506,7 +4361,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/start-basic-static: dependencies: @@ -4531,9 +4386,6 @@ importers: tailwind-merge: specifier: ^2.5.5 version: 2.6.0 - vinxi: - specifier: 0.5.1 - version: 0.5.1(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -4558,7 +4410,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.3 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/start-clerk-basic: dependencies: @@ -4586,9 +4438,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -4613,7 +4462,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/start-convex-trellaux: dependencies: @@ -4668,9 +4517,6 @@ importers: tiny-invariant: specifier: ^1.3.3 version: 1.3.3 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -4695,7 +4541,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/start-counter: dependencies: @@ -4714,9 +4560,6 @@ importers: react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -4760,9 +4603,6 @@ importers: valibot: specifier: ^1.0.0-beta.15 version: 1.0.0-beta.15(typescript@5.8.2) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -4786,11 +4626,11 @@ importers: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/start-material-ui: dependencies: @@ -4824,9 +4664,6 @@ importers: react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -4845,7 +4682,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/start-supabase-basic: dependencies: @@ -4870,9 +4707,6 @@ importers: react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/react': specifier: ^19.0.8 @@ -4894,7 +4728,56 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + + examples/react/start-tailwind-v4: + dependencies: + '@tanstack/react-router': + specifier: workspace:* + version: link:../../../packages/react-router + '@tanstack/react-router-devtools': + specifier: workspace:^ + version: link:../../../packages/react-router-devtools + '@tanstack/react-start': + specifier: workspace:* + version: link:../../../packages/react-start + react: + specifier: ^19.0.0 + version: 19.0.0 + react-dom: + specifier: ^19.0.0 + version: 19.0.0(react@19.0.0) + tailwind-merge: + specifier: ^2.6.0 + version: 2.6.0 + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + zod: + specifier: ^3.24.2 + version: 3.24.2 + devDependencies: + '@tailwindcss/vite': + specifier: ^4.1.6 + version: 4.1.6(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + '@types/node': + specifier: ^22.5.4 + version: 22.13.4 + '@types/react': + specifier: ^19.0.8 + version: 19.0.8 + '@types/react-dom': + specifier: ^19.0.3 + version: 19.0.3(@types/react@19.0.8) + tailwindcss: + specifier: ^4.1.6 + version: 4.1.6 + typescript: + specifier: ^5.7.2 + version: 5.8.2 + vite-tsconfig-paths: + specifier: ^5.1.4 + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/start-trellaux: dependencies: @@ -4940,9 +4823,6 @@ importers: tiny-invariant: specifier: ^1.3.3 version: 1.3.3 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -4967,7 +4847,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/start-workos: dependencies: @@ -4985,7 +4865,7 @@ importers: version: link:../../../packages/react-start '@workos-inc/node': specifier: ^7.45.0 - version: 7.45.0(express@4.21.2) + version: 7.46.0(express@4.21.2) iron-session: specifier: ^8.0.4 version: 8.0.4 @@ -4998,9 +4878,9 @@ importers: react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) devDependencies: '@types/react': specifier: ^19.0.8 @@ -5022,7 +4902,7 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/view-transitions: dependencies: @@ -5065,13 +4945,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/with-framer-motion: dependencies: @@ -5114,13 +4994,13 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) typescript: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) examples/react/with-trpc: dependencies: @@ -5160,9 +5040,6 @@ importers: tailwindcss: specifier: ^3.4.17 version: 3.4.17 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -5175,7 +5052,7 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/react/with-trpc-react-query: dependencies: @@ -5224,9 +5101,6 @@ importers: tailwindcss: specifier: ^3.4.17 version: 3.4.17 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -5239,12 +5113,12 @@ importers: version: 19.0.3(@types/react@19.0.8) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/solid/basic: dependencies: '@tanstack/solid-router': - specifier: ^1.120.3 + specifier: ^1.121.0-alpha.11 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5275,16 +5149,16 @@ importers: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/solid/basic-devtools-panel: dependencies: '@tanstack/solid-router': - specifier: ^1.120.3 + specifier: ^1.121.0-alpha.11 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5309,16 +5183,16 @@ importers: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.6 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/solid/basic-file-based: dependencies: '@tanstack/solid-router': - specifier: ^1.120.3 + specifier: ^1.121.0-alpha.11 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5349,16 +5223,16 @@ importers: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/solid/basic-non-nested-devtools: dependencies: '@tanstack/solid-router': - specifier: ^1.120.3 + specifier: ^1.121.0-alpha.11 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5389,22 +5263,22 @@ importers: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/solid/basic-solid-query: dependencies: '@tanstack/solid-query': specifier: ^5.71.9 - version: 5.71.9(solid-js@1.9.5) + version: 5.72.2(solid-js@1.9.5) '@tanstack/solid-query-devtools': specifier: ^5.71.9 - version: 5.71.9(@tanstack/solid-query@5.71.9(solid-js@1.9.5))(solid-js@1.9.5) + version: 5.72.2(@tanstack/solid-query@5.72.2(solid-js@1.9.5))(solid-js@1.9.5) '@tanstack/solid-router': - specifier: ^1.120.3 + specifier: ^1.121.0-alpha.11 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5432,22 +5306,22 @@ importers: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/solid/basic-solid-query-file-based: dependencies: '@tanstack/solid-query': specifier: ^5.71.9 - version: 5.71.9(solid-js@1.9.5) + version: 5.72.2(solid-js@1.9.5) '@tanstack/solid-query-devtools': specifier: ^5.71.9 - version: 5.71.9(@tanstack/solid-query@5.71.9(solid-js@1.9.5))(solid-js@1.9.5) + version: 5.72.2(@tanstack/solid-query@5.72.2(solid-js@1.9.5))(solid-js@1.9.5) '@tanstack/solid-router': - specifier: ^1.120.3 + specifier: ^1.121.0-alpha.11 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5478,16 +5352,16 @@ importers: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/solid/kitchen-sink-file-based: dependencies: '@tanstack/solid-router': - specifier: ^1.120.3 + specifier: ^1.121.0-alpha.11 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5521,16 +5395,16 @@ importers: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/solid/quickstart-file-based: dependencies: '@tanstack/solid-router': - specifier: ^1.120.3 + specifier: ^1.121.0-alpha.11 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5561,16 +5435,16 @@ importers: specifier: ^5.7.2 version: 5.8.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/solid/start-bare: dependencies: '@tanstack/solid-router': - specifier: ^1.120.3 + specifier: ^1.121.0-alpha.11 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5587,16 +5461,16 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 devDependencies: '@tailwindcss/vite': specifier: ^4.0.8 - version: 4.0.8(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.1.6(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) '@types/node': specifier: ^22.10.2 version: 22.13.4 @@ -5605,21 +5479,21 @@ importers: version: 1.1.11 tailwindcss: specifier: ^4.0.0 - version: 4.0.8 + version: 4.1.6 typescript: specifier: ^5.7.2 version: 5.8.2 vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) examples/solid/start-basic: dependencies: '@tanstack/solid-router': - specifier: ^1.120.3 + specifier: ^1.121.0-alpha.11 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5636,12 +5510,9 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -5660,7 +5531,47 @@ importers: version: 5.8.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + + examples/solid/start-basic-static: + dependencies: + '@tanstack/solid-router': + specifier: ^1.121.0-alpha.11 + version: link:../../../packages/solid-router + '@tanstack/solid-router-devtools': + specifier: workspace:^ + version: link:../../../packages/solid-router-devtools + '@tanstack/solid-start': + specifier: workspace:* + version: link:../../../packages/solid-start + redaxios: + specifier: ^0.5.1 + version: 0.5.1 + solid-js: + specifier: ^1.9.5 + version: 1.9.5 + tailwind-merge: + specifier: ^2.5.5 + version: 2.6.0 + devDependencies: + '@types/node': + specifier: ^22.5.4 + version: 22.13.4 + autoprefixer: + specifier: ^10.4.20 + version: 10.4.20(postcss@8.5.3) + postcss: + specifier: ^8.4.49 + version: 8.5.3 + tailwindcss: + specifier: ^3.4.15 + version: 3.4.17 + typescript: + specifier: ^5.6.2 + version: 5.8.2 + vite-tsconfig-paths: + specifier: ^5.1.3 + version: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) packages/arktype-adapter: devDependencies: @@ -5712,15 +5623,9 @@ importers: babel-dead-code-elimination: specifier: ^1.0.10 version: 1.0.10 - dedent: - specifier: ^1.5.3 - version: 1.5.3(babel-plugin-macros@3.1.0) tiny-invariant: specifier: ^1.3.3 version: 1.3.3 - vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) devDependencies: '@types/babel__code-frame': specifier: ^7.0.6 @@ -5734,6 +5639,9 @@ importers: '@types/babel__traverse': specifier: ^7.20.6 version: 7.20.6 + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) packages/eslint-plugin-router: dependencies: @@ -5785,7 +5693,7 @@ importers: version: 3.0.3 '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) combinate: specifier: ^1.1.11 version: 1.1.11 @@ -5813,7 +5721,7 @@ importers: devDependencies: '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) react: specifier: ^19.0.0 version: 19.0.0 @@ -5834,7 +5742,7 @@ importers: version: link:../router-core '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) react: specifier: ^19.0.0 version: 19.0.0 @@ -5847,30 +5755,21 @@ importers: '@tanstack/react-start-client': specifier: workspace:* version: link:../react-start-client - '@tanstack/react-start-config': - specifier: workspace:* - version: link:../react-start-config - '@tanstack/react-start-router-manifest': + '@tanstack/react-start-plugin': specifier: workspace:* - version: link:../react-start-router-manifest + version: link:../react-start-plugin '@tanstack/react-start-server': specifier: workspace:* version: link:../react-start-server - '@tanstack/start-api-routes': - specifier: workspace:* - version: link:../start-api-routes '@tanstack/start-server-functions-client': specifier: workspace:* version: link:../start-server-functions-client - '@tanstack/start-server-functions-handler': - specifier: workspace:* - version: link:../start-server-functions-handler '@tanstack/start-server-functions-server': specifier: workspace:* version: link:../start-server-functions-server - '@tanstack/start-server-functions-ssr': - specifier: workspace:* - version: link:../start-server-functions-ssr + '@vitejs/plugin-react': + specifier: '>=4.3.4' + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) react: specifier: ^19.0.0 version: 19.0.0 @@ -5878,12 +5777,12 @@ importers: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) devDependencies: esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 packages/react-start-client: dependencies: @@ -5914,9 +5813,6 @@ importers: tiny-warning: specifier: ^1.0.3 version: 1.0.3 - vinxi: - specifier: ^0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@testing-library/react': specifier: ^16.2.0 @@ -5926,120 +5822,26 @@ importers: version: 3.0.3 '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - packages/react-start-config: + packages/react-start-plugin: dependencies: - '@tanstack/react-start-plugin': - specifier: workspace:* - version: link:../react-start-plugin - '@tanstack/router-core': - specifier: workspace:* - version: link:../router-core - '@tanstack/router-generator': - specifier: workspace:* - version: link:../router-generator - '@tanstack/router-plugin': + '@tanstack/router-utils': specifier: workspace:* - version: link:../router-plugin - '@tanstack/server-functions-plugin': + version: link:../router-utils + '@tanstack/start-plugin-core': specifier: workspace:* - version: link:../server-functions-plugin - '@tanstack/start-server-functions-handler': - specifier: workspace:* - version: link:../start-server-functions-handler - '@vitejs/plugin-react': - specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - import-meta-resolve: - specifier: ^4.1.0 - version: 4.1.0 - nitropack: - specifier: ^2.10.4 - version: 2.10.4(typescript@5.8.2) - ofetch: - specifier: ^1.4.1 - version: 1.4.1 - react: - specifier: ^19.0.0 - version: 19.0.0 - react-dom: - specifier: ^19.0.0 - version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) - vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + version: link:../start-plugin-core zod: specifier: ^3.24.2 version: 3.24.2 - - packages/react-start-plugin: - dependencies: - '@babel/code-frame': - specifier: 7.26.2 - version: 7.26.2 - '@babel/core': - specifier: ^7.26.8 - version: 7.26.8 - '@babel/plugin-syntax-jsx': - specifier: ^7.25.9 - version: 7.25.9(@babel/core@7.26.8) - '@babel/plugin-syntax-typescript': - specifier: ^7.25.9 - version: 7.25.9(@babel/core@7.26.8) - '@babel/template': - specifier: ^7.26.8 - version: 7.26.8 - '@babel/traverse': - specifier: ^7.26.8 - version: 7.26.8 - '@babel/types': - specifier: ^7.26.8 - version: 7.26.8 - '@tanstack/router-utils': - specifier: workspace:* - version: link:../router-utils - babel-dead-code-elimination: - specifier: ^1.0.10 - version: 1.0.10 - tiny-invariant: - specifier: ^1.3.3 - version: 1.3.3 - vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - devDependencies: - '@types/babel__code-frame': - specifier: ^7.0.6 - version: 7.0.6 - '@types/babel__core': - specifier: ^7.20.5 - version: 7.20.5 - '@types/babel__template': - specifier: ^7.4.4 - version: 7.4.4 - '@types/babel__traverse': - specifier: ^7.20.6 - version: 7.20.6 - - packages/react-start-router-manifest: - dependencies: - '@tanstack/router-core': - specifier: workspace:* - version: link:../router-core - tiny-invariant: - specifier: ^1.3.3 - version: 1.3.3 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: - typescript: - specifier: ^5.7.2 - version: 5.8.2 + '@vitejs/plugin-react': + specifier: ^4.3.4 + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) packages/react-start-server: dependencies: @@ -6067,6 +5869,9 @@ importers: jsesc: specifier: ^3.1.0 version: 3.1.0 + tiny-invariant: + specifier: ^1.3.3 + version: 1.3.3 tiny-warning: specifier: ^1.0.3 version: 1.0.3 @@ -6079,10 +5884,10 @@ importers: version: 3.0.3 '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 react: specifier: ^19.0.0 version: 19.0.0 @@ -6141,7 +5946,7 @@ importers: devDependencies: '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) react: specifier: ^19.0.0 version: 19.0.0 @@ -6172,7 +5977,7 @@ importers: version: 1.9.5 vite-plugin-solid: specifier: ^2.11.6 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) packages/router-generator: dependencies: @@ -6247,16 +6052,16 @@ importers: version: 3.6.0 unplugin: specifier: ^2.1.2 - version: 2.1.2 + version: 2.2.2 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) webpack: specifier: '>=5.92.0' - version: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0) + version: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2) zod: specifier: ^3.24.2 version: 3.24.2 @@ -6321,9 +6126,6 @@ importers: babel-dead-code-elimination: specifier: ^1.0.9 version: 1.0.10 - dedent: - specifier: ^1.5.3 - version: 1.5.3(babel-plugin-macros@3.1.0) tiny-invariant: specifier: ^1.3.3 version: 1.3.3 @@ -6391,7 +6193,7 @@ importers: version: 1.9.5 vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) zod: specifier: ^3.23.8 version: 3.24.2 @@ -6410,47 +6212,38 @@ importers: devDependencies: vite-plugin-solid: specifier: ^2.11.6 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) packages/solid-start: dependencies: '@tanstack/solid-start-client': specifier: workspace:* version: link:../solid-start-client - '@tanstack/solid-start-config': - specifier: workspace:* - version: link:../solid-start-config - '@tanstack/solid-start-router-manifest': + '@tanstack/solid-start-plugin': specifier: workspace:* - version: link:../solid-start-router-manifest + version: link:../solid-start-plugin '@tanstack/solid-start-server': specifier: workspace:* version: link:../solid-start-server - '@tanstack/start-api-routes': - specifier: workspace:* - version: link:../start-api-routes '@tanstack/start-server-functions-client': specifier: workspace:* version: link:../start-server-functions-client - '@tanstack/start-server-functions-handler': - specifier: workspace:* - version: link:../start-server-functions-handler '@tanstack/start-server-functions-server': specifier: workspace:* version: link:../start-server-functions-server - '@tanstack/start-server-functions-ssr': - specifier: workspace:* - version: link:../start-server-functions-ssr solid-js: specifier: '>=1.0.0' version: 1.9.5 vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vite-plugin-solid: + specifier: '>=2.11.6' + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) devDependencies: esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 packages/solid-start-client: dependencies: @@ -6478,9 +6271,6 @@ importers: tiny-warning: specifier: ^1.0.3 version: 1.0.3 - vinxi: - specifier: ^0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@solidjs/testing-library': specifier: ^0.8.10 @@ -6493,117 +6283,26 @@ importers: version: 3.0.3 vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - - packages/solid-start-config: - dependencies: - '@tanstack/router-core': - specifier: workspace:* - version: link:../router-core - '@tanstack/router-generator': - specifier: workspace:* - version: link:../router-generator - '@tanstack/router-plugin': - specifier: workspace:* - version: link:../router-plugin - '@tanstack/server-functions-plugin': - specifier: workspace:* - version: link:../server-functions-plugin - '@tanstack/solid-start-plugin': - specifier: workspace:* - version: link:../solid-start-plugin - '@tanstack/start-server-functions-handler': - specifier: workspace:* - version: link:../start-server-functions-handler - import-meta-resolve: - specifier: ^4.1.0 - version: 4.1.0 - nitropack: - specifier: ^2.10.4 - version: 2.10.4(typescript@5.8.2) - ofetch: - specifier: ^1.4.1 - version: 1.4.1 - solid-js: - specifier: '>=1.0.0' - version: 1.9.5 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) - vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - vite-plugin-solid: - specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - zod: - specifier: ^3.24.2 - version: 3.24.2 + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) packages/solid-start-plugin: dependencies: - '@babel/code-frame': - specifier: 7.26.2 - version: 7.26.2 - '@babel/core': - specifier: ^7.26.8 - version: 7.26.8 - '@babel/plugin-syntax-jsx': - specifier: ^7.25.9 - version: 7.25.9(@babel/core@7.26.8) - '@babel/plugin-syntax-typescript': - specifier: ^7.25.9 - version: 7.25.9(@babel/core@7.26.8) - '@babel/template': - specifier: ^7.26.8 - version: 7.26.8 - '@babel/traverse': - specifier: ^7.26.8 - version: 7.26.8 - '@babel/types': - specifier: ^7.26.8 - version: 7.26.8 '@tanstack/router-utils': specifier: workspace:* version: link:../router-utils - babel-dead-code-elimination: - specifier: ^1.0.9 - version: 1.0.10 - tiny-invariant: - specifier: ^1.3.3 - version: 1.3.3 - vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - devDependencies: - '@types/babel__code-frame': - specifier: ^7.0.6 - version: 7.0.6 - '@types/babel__core': - specifier: ^7.20.5 - version: 7.20.5 - '@types/babel__template': - specifier: ^7.4.4 - version: 7.4.4 - '@types/babel__traverse': - specifier: ^7.20.6 - version: 7.20.6 - - packages/solid-start-router-manifest: - dependencies: - '@tanstack/router-core': + '@tanstack/start-plugin-core': specifier: workspace:* - version: link:../router-core - tiny-invariant: - specifier: ^1.3.3 - version: 1.3.3 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + version: link:../start-plugin-core + zod: + specifier: ^3.24.2 + version: 3.24.2 devDependencies: - typescript: - specifier: ^5.7.2 - version: 5.8.2 + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vite-plugin-solid: + specifier: ^2.11.6 + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) packages/solid-start-server: dependencies: @@ -6646,7 +6345,7 @@ importers: version: 3.0.3 esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 solid-js: specifier: ^1.9.5 version: 1.9.5 @@ -6655,53 +6354,7 @@ importers: version: 5.8.2 vite-plugin-solid: specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - - packages/start: - dependencies: - '@tanstack/react-start-client': - specifier: workspace:* - version: link:../react-start-client - '@tanstack/react-start-router-manifest': - specifier: workspace:* - version: link:../react-start-router-manifest - '@tanstack/react-start-server': - specifier: workspace:* - version: link:../react-start-server - '@tanstack/start-api-routes': - specifier: workspace:* - version: link:../start-api-routes - '@tanstack/start-config': - specifier: workspace:^ - version: link:../start-config - '@tanstack/start-server-functions-client': - specifier: workspace:* - version: link:../start-server-functions-client - '@tanstack/start-server-functions-handler': - specifier: workspace:* - version: link:../start-server-functions-handler - '@tanstack/start-server-functions-server': - specifier: workspace:* - version: link:../start-server-functions-server - '@tanstack/start-server-functions-ssr': - specifier: workspace:* - version: link:../start-server-functions-ssr - - packages/start-api-routes: - dependencies: - '@tanstack/router-core': - specifier: workspace:* - version: link:../router-core - '@tanstack/start-server-core': - specifier: workspace:* - version: link:../start-server-core - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) - devDependencies: - typescript: - specifier: ^5.7.2 - version: 5.8.2 + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) packages/start-client-core: dependencies: @@ -6718,53 +6371,66 @@ importers: specifier: ^1.0.3 version: 1.0.3 - packages/start-config: + packages/start-plugin-core: dependencies: - '@tanstack/react-router': - specifier: workspace:* - version: link:../react-router - '@tanstack/react-start-plugin': + '@babel/code-frame': + specifier: 7.26.2 + version: 7.26.2 + '@babel/core': + specifier: ^7.26.8 + version: 7.26.8 + '@babel/types': + specifier: ^7.26.8 + version: 7.26.8 + '@tanstack/router-core': specifier: workspace:* - version: link:../react-start-plugin + version: link:../router-core '@tanstack/router-generator': specifier: workspace:* version: link:../router-generator '@tanstack/router-plugin': specifier: workspace:* version: link:../router-plugin + '@tanstack/router-utils': + specifier: workspace:* + version: link:../router-utils '@tanstack/server-functions-plugin': specifier: workspace:* version: link:../server-functions-plugin - '@tanstack/start-server-functions-handler': - specifier: workspace:* - version: link:../start-server-functions-handler - '@vitejs/plugin-react': - specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - import-meta-resolve: - specifier: ^4.1.0 - version: 4.1.0 + '@types/babel__code-frame': + specifier: ^7.0.6 + version: 7.0.6 + '@types/babel__core': + specifier: ^7.20.5 + version: 7.20.5 + babel-dead-code-elimination: + specifier: ^1.0.9 + version: 1.0.10 + cheerio: + specifier: ^1.0.0 + version: 1.0.0 + h3: + specifier: 1.13.0 + version: 1.13.0 nitropack: - specifier: ^2.10.4 - version: 2.10.4(typescript@5.8.2) - ofetch: - specifier: ^1.4.1 - version: 1.4.1 - react: - specifier: ^19.0.0 - version: 19.0.0 - react-dom: - specifier: ^19.0.0 - version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) - vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + specifier: ^2.11.8 + version: 2.11.8 + pathe: + specifier: ^2.0.3 + version: 2.0.3 + ufo: + specifier: ^1.5.4 + version: 1.5.4 + xmlbuilder2: + specifier: ^3.1.1 + version: 3.1.1 zod: specifier: ^3.24.2 version: 3.24.2 + devDependencies: + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) packages/start-server-core: dependencies: @@ -6786,6 +6452,9 @@ importers: jsesc: specifier: ^3.1.0 version: 3.1.0 + tiny-invariant: + specifier: ^1.3.3 + version: 1.3.3 tiny-warning: specifier: ^1.0.3 version: 1.0.3 @@ -6798,10 +6467,13 @@ importers: version: 3.0.3 esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 typescript: specifier: ^5.7.2 version: 5.8.2 + vite: + specifier: 6.3.5 + version: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) packages/start-server-functions-client: dependencies: @@ -6829,25 +6501,6 @@ importers: specifier: ^5.7.2 version: 5.8.2 - packages/start-server-functions-handler: - dependencies: - '@tanstack/router-core': - specifier: workspace:* - version: link:../router-core - '@tanstack/start-client-core': - specifier: workspace:* - version: link:../start-client-core - '@tanstack/start-server-core': - specifier: workspace:* - version: link:../start-server-core - tiny-invariant: - specifier: ^1.3.3 - version: 1.3.3 - devDependencies: - typescript: - specifier: ^5.7.2 - version: 5.8.2 - packages/start-server-functions-server: dependencies: '@tanstack/server-functions-plugin': @@ -6861,28 +6514,6 @@ importers: specifier: ^5.7.2 version: 5.8.2 - packages/start-server-functions-ssr: - dependencies: - '@tanstack/server-functions-plugin': - specifier: workspace:* - version: link:../server-functions-plugin - '@tanstack/start-client-core': - specifier: workspace:* - version: link:../start-client-core - '@tanstack/start-server-core': - specifier: workspace:* - version: link:../start-server-core - '@tanstack/start-server-functions-fetcher': - specifier: workspace:* - version: link:../start-server-functions-fetcher - tiny-invariant: - specifier: ^1.3.3 - version: 1.3.3 - devDependencies: - typescript: - specifier: ^5.7.2 - version: 5.8.2 - packages/valibot-adapter: devDependencies: '@tanstack/react-router': @@ -7112,10 +6743,6 @@ packages: resolution: {integrity: sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==} engines: {node: '>=6.9.0'} - '@babel/standalone@7.26.7': - resolution: {integrity: sha512-Fvdo9Dd20GDUAREzYMIR2EFMKAJ+ccxstgQdb39XV/yvygHL4UPcqgTkiChPyltAe/b+zgq+vUPXeukEZ6aUeA==} - engines: {node: '>=6.9.0'} - '@babel/template@7.26.8': resolution: {integrity: sha512-iNKaX3ZebKIsCvJ+0jd6embf+Aulaa3vNBqZ41kM7iTWjx5qzWKXGHiJUW3+nTpQ18SG11hdF8OAzKrpXkb96Q==} engines: {node: '>=6.9.0'} @@ -7173,9 +6800,9 @@ packages: resolution: {integrity: sha512-b4LR3Xsegqe0S6ZkaSJ1skO5a36EIiYRCFBzrJIbJX58vh25FFbOs4VHcK71uCLGJ1Jm1bViPi8QPGYoqYAUuw==} engines: {node: '>=18.17.0'} - '@cloudflare/kv-asset-handler@0.3.4': - resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} - engines: {node: '>=16.13'} + '@cloudflare/kv-asset-handler@0.4.0': + resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==} + engines: {node: '>=18.0.0'} '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} @@ -7223,12 +6850,6 @@ packages: resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==} engines: {node: '>=18'} - '@deno/shim-deno-test@0.5.0': - resolution: {integrity: sha512-4nMhecpGlPi0cSzT67L+Tm+GOJqvuk8gqHBziqcUQOarnuIax1z96/gJHCSIz2Z0zhxE6Rzwb3IZXPtFh51j+w==} - - '@deno/shim-deno@0.19.2': - resolution: {integrity: sha512-q3VTHl44ad8T2Tw2SpeAvghdGOjlnLPDNO2cpOxwMrBE/PVas6geWpbpIgrM+czOCH0yejp0yi8OaTuB+NU40Q==} - '@discoveryjs/json-ext@0.5.7': resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} engines: {node: '>=10.0.0'} @@ -7296,12 +6917,6 @@ packages: '@emotion/weak-memoize@0.4.0': resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} - '@esbuild/aix-ppc64@0.20.2': - resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.23.0': resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==} engines: {node: '>=18'} @@ -7314,24 +6929,12 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.24.2': - resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/aix-ppc64@0.25.0': - resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==} + '@esbuild/aix-ppc64@0.25.2': + resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.20.2': - resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.23.0': resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==} engines: {node: '>=18'} @@ -7344,24 +6947,12 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.24.2': - resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} + '@esbuild/android-arm64@0.25.2': + resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.25.0': - resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.20.2': - resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.23.0': resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==} engines: {node: '>=18'} @@ -7374,24 +6965,12 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.24.2': - resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} + '@esbuild/android-arm@0.25.2': + resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.25.0': - resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.20.2': - resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.23.0': resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==} engines: {node: '>=18'} @@ -7404,24 +6983,12 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.24.2': - resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/android-x64@0.25.0': - resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==} + '@esbuild/android-x64@0.25.2': + resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.20.2': - resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.23.0': resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==} engines: {node: '>=18'} @@ -7434,24 +7001,12 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.24.2': - resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-arm64@0.25.0': - resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==} + '@esbuild/darwin-arm64@0.25.2': + resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.20.2': - resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.23.0': resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==} engines: {node: '>=18'} @@ -7464,24 +7019,12 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.24.2': - resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} + '@esbuild/darwin-x64@0.25.2': + resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.25.0': - resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.20.2': - resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.23.0': resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==} engines: {node: '>=18'} @@ -7494,24 +7037,12 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.24.2': - resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-arm64@0.25.0': - resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==} + '@esbuild/freebsd-arm64@0.25.2': + resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.20.2': - resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.23.0': resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==} engines: {node: '>=18'} @@ -7524,24 +7055,12 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.24.2': - resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.0': - resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==} + '@esbuild/freebsd-x64@0.25.2': + resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.20.2': - resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.23.0': resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==} engines: {node: '>=18'} @@ -7554,24 +7073,12 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.24.2': - resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} + '@esbuild/linux-arm64@0.25.2': + resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.25.0': - resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.20.2': - resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.23.0': resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==} engines: {node: '>=18'} @@ -7584,24 +7091,12 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.24.2': - resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-arm@0.25.0': - resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==} + '@esbuild/linux-arm@0.25.2': + resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.20.2': - resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.23.0': resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==} engines: {node: '>=18'} @@ -7614,54 +7109,30 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.24.2': - resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-ia32@0.25.0': - resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==} + '@esbuild/linux-ia32@0.25.2': + resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.20.2': - resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.23.0': resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==} engines: {node: '>=18'} 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-loong64@0.24.2': - resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} + '@esbuild/linux-loong64@0.23.1': + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.25.0': - resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==} + '@esbuild/linux-loong64@0.25.2': + resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.20.2': - resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.23.0': resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==} engines: {node: '>=18'} @@ -7674,24 +7145,12 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.24.2': - resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-mips64el@0.25.0': - resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==} + '@esbuild/linux-mips64el@0.25.2': + resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.20.2': - resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.23.0': resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==} engines: {node: '>=18'} @@ -7704,24 +7163,12 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.24.2': - resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-ppc64@0.25.0': - resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==} + '@esbuild/linux-ppc64@0.25.2': + resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.20.2': - resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.23.0': resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==} engines: {node: '>=18'} @@ -7734,24 +7181,12 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.24.2': - resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.0': - resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==} + '@esbuild/linux-riscv64@0.25.2': + resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.20.2': - resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.23.0': resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==} engines: {node: '>=18'} @@ -7764,24 +7199,12 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.24.2': - resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-s390x@0.25.0': - resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==} + '@esbuild/linux-s390x@0.25.2': + resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.20.2': - resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.23.0': resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==} engines: {node: '>=18'} @@ -7794,36 +7217,18 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.24.2': - resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/linux-x64@0.25.0': - resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==} + '@esbuild/linux-x64@0.25.2': + resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.24.2': - resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-arm64@0.25.0': - resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==} + '@esbuild/netbsd-arm64@0.25.2': + resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.20.2': - resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.23.0': resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==} engines: {node: '>=18'} @@ -7836,14 +7241,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.24.2': - resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.0': - resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==} + '@esbuild/netbsd-x64@0.25.2': + resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -7860,24 +7259,12 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.24.2': - resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-arm64@0.25.0': - resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==} + '@esbuild/openbsd-arm64@0.25.2': + resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.20.2': - resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.23.0': resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==} engines: {node: '>=18'} @@ -7890,24 +7277,12 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.24.2': - resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.0': - resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==} + '@esbuild/openbsd-x64@0.25.2': + resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.20.2': - resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.23.0': resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==} engines: {node: '>=18'} @@ -7920,24 +7295,12 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.24.2': - resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/sunos-x64@0.25.0': - resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==} + '@esbuild/sunos-x64@0.25.2': + resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.20.2': - resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.23.0': resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==} engines: {node: '>=18'} @@ -7950,24 +7313,12 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.24.2': - resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-arm64@0.25.0': - resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==} + '@esbuild/win32-arm64@0.25.2': + resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.20.2': - resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.23.0': resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==} engines: {node: '>=18'} @@ -7980,24 +7331,12 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.24.2': - resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-ia32@0.25.0': - resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==} + '@esbuild/win32-ia32@0.25.2': + resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.20.2': - resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.23.0': resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==} engines: {node: '>=18'} @@ -8010,14 +7349,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.24.2': - resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@esbuild/win32-x64@0.25.0': - resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==} + '@esbuild/win32-x64@0.25.2': + resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -8567,16 +7900,12 @@ packages: '@napi-rs/wasm-runtime@0.2.4': resolution: {integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==} - '@netlify/functions@2.8.2': - resolution: {integrity: sha512-DeoAQh8LuNPvBE4qsKlezjKj0PyXDryOFJfJKo3Z1qZLKzQ21sT314KQKPVjfvw6knqijj+IO+0kHXy/TJiqNA==} - engines: {node: '>=14.0.0'} - - '@netlify/node-cookies@0.1.0': - resolution: {integrity: sha512-OAs1xG+FfLX0LoRASpqzVntVV/RpYkgpI0VrUnw2u0Q1qiZUzcPffxRK8HF3gc4GjuhG5ahOEMJ9bswBiZPq0g==} - engines: {node: ^14.16.0 || >=16.0.0} + '@netlify/functions@3.0.4': + resolution: {integrity: sha512-Ox8+ABI+nsLK+c4/oC5dpquXuEIjzfTlJrdQKgQijCsDQoje7inXFAtKDLvvaGvuvE+PVpMLwQcIUL6P9Ob1hQ==} + engines: {node: '>=18.0.0'} - '@netlify/serverless-functions-api@1.26.1': - resolution: {integrity: sha512-q3L9i3HoNfz0SGpTIS4zTcKBbRkxzCRpd169eyiTuk3IwcPC3/85mzLHranlKo2b+HYT0gu37YxGB45aD8A3Tw==} + '@netlify/serverless-functions-api@1.36.0': + resolution: {integrity: sha512-z6okREyK8in0486a22Oro0k+YsuyEjDXJt46FpgeOgXqKJ9ElM8QPll0iuLBkpbH33ENiNbIPLd1cuClRQnhiw==} engines: {node: '>=18.0.0'} '@nodelib/fs.scandir@2.1.5': @@ -8654,6 +7983,22 @@ packages: cpu: [x64] os: [win32] + '@oozcitak/dom@1.15.10': + resolution: {integrity: sha512-0JT29/LaxVgRcGKvHmSrUTEvZ8BXvZhGl2LASRUgHqDTC1M5g1pLmVv56IYNyt3bG2CUjDkc67wnyZC14pbQrQ==} + engines: {node: '>=8.0'} + + '@oozcitak/infra@1.0.8': + resolution: {integrity: sha512-JRAUc9VR6IGHOL7OGF+yrvs0LO8SlqGnPAMqyzOuFZPSZSXI7Xf2O9+awQPSMXgIWGtgUf/dA6Hs6X6ySEaWTg==} + engines: {node: '>=6.0'} + + '@oozcitak/url@1.0.4': + resolution: {integrity: sha512-kDcD8y+y3FCSOvnBI6HJgl00viO/nGbQoCINmQ0h98OhnGITrWR3bOGfwYCthgcrV8AnTJz8MzslTQbC3SOAmw==} + engines: {node: '>=8.0'} + + '@oozcitak/util@8.3.8': + resolution: {integrity: sha512-T8TbSnGsxo6TDBJx/Sgv/BlVJL3tshxZP7Aq5R1mSnM5OcHY2dQaxLMu2+E8u3gN0MLOzdjurqN4ZRVuzQycOQ==} + engines: {node: '>=8.0'} + '@open-draft/deferred-promise@2.2.0': resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} @@ -8723,12 +8068,6 @@ packages: cpu: [x64] os: [linux] - '@parcel/watcher-wasm@2.3.0': - resolution: {integrity: sha512-ejBAX8H0ZGsD8lSICDNyMbSEtPMWgDL0WFCt/0z7hyf5v8Imz4rAM8xY379mBsECkq/Wdqa5WEDLqtjZ+6NxfA==} - engines: {node: '>= 10.0.0'} - bundledDependencies: - - napi-wasm - '@parcel/watcher-wasm@2.5.1': resolution: {integrity: sha512-RJxlQQLkaMMIuWRozy+z2vEqbaQlCuaCgVZIUCzQLYggY22LZbP5Y1+ia+FD724Ids9e+XIyOLXLrLgQSHIthw==} engines: {node: '>= 10.0.0'} @@ -8783,6 +8122,17 @@ packages: '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + '@poppinss/colors@4.1.4': + resolution: {integrity: sha512-FA+nTU8p6OcSH4tLDY5JilGYr1bVWHpNmcLr7xmMEdbWmKHa+3QZ+DqefrXKmdjO/brHTnQZo20lLSjaO7ydog==} + engines: {node: '>=18.16.0'} + + '@poppinss/dumper@0.6.3': + resolution: {integrity: sha512-iombbn8ckOixMtuV1p3f8jN6vqhXefNjJttoPaJDMeIk/yIGhkkL3OrHkEjE9SRsgoAx1vBUU2GtgggjvA5hCA==} + + '@poppinss/exception@1.2.1': + resolution: {integrity: sha512-aQypoot0HPSJa6gDPEPTntc1GT6QINrSbgRlRhadGW2WaYqUK3tK4Bw9SBMZXhmxd3GeAlZjVcODHgiu+THY7A==} + engines: {node: '>=18'} + '@prisma/client@5.22.0': resolution: {integrity: sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==} engines: {node: '>=16.13'} @@ -8847,9 +8197,6 @@ packages: '@radix-ui/number@1.1.1': resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} - '@radix-ui/primitive@1.1.1': - resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==} - '@radix-ui/primitive@1.1.2': resolution: {integrity: sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==} @@ -8970,15 +8317,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-compose-refs@1.1.1': - resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-compose-refs@1.1.2': resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} peerDependencies: @@ -9001,15 +8339,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-context@1.1.1': - resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-context@1.1.2': resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} peerDependencies: @@ -9019,19 +8348,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-dialog@1.1.6': - resolution: {integrity: sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==} - peerDependencies: - '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 - react: ^19.0.0 - react-dom: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-dialog@1.1.7': resolution: {integrity: sha512-EIdma8C0C/I6kL6sO02avaCRqi3fmWJpxH6mqbVScorW6nNktzKJT/le7VPho3o/7wCsyRg3z0+Q+Obr0Gy/VQ==} peerDependencies: @@ -9054,19 +8370,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-dismissable-layer@1.1.5': - resolution: {integrity: sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==} - peerDependencies: - '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 - react: ^19.0.0 - react-dom: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-dismissable-layer@1.1.6': resolution: {integrity: sha512-7gpgMT2gyKym9Jz2ZhlRXSg2y6cNQIK8d/cqBZ0RBCaps8pFryCWXiUKI+uHGFrhMrbGUP7U6PWgiXzIxoyF3Q==} peerDependencies: @@ -9093,15 +8396,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-focus-guards@1.1.1': - resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-focus-guards@1.1.2': resolution: {integrity: sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==} peerDependencies: @@ -9111,19 +8405,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-focus-scope@1.1.2': - resolution: {integrity: sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==} - peerDependencies: - '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 - react: ^19.0.0 - react-dom: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-focus-scope@1.1.3': resolution: {integrity: sha512-4XaDlq0bPt7oJwR+0k0clCiCO/7lO7NKZTAaJBYxDNQT/vj4ig0/UvctrRscZaFREpRvUTkpKR96ov1e6jptQg==} peerDependencies: @@ -9163,15 +8444,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-id@1.1.0': - resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-id@1.1.1': resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} peerDependencies: @@ -9259,19 +8531,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-portal@1.1.4': - resolution: {integrity: sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==} - peerDependencies: - '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 - react: ^19.0.0 - react-dom: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-portal@1.1.5': resolution: {integrity: sha512-ps/67ZqsFm+Mb6lSPJpfhRLrVL2i2fntgCmGMqqth4eaGUf+knAuuRtWVJrNjUhExgmdRqftSgzpf0DF0n6yXA==} peerDependencies: @@ -9285,19 +8544,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-presence@1.1.2': - resolution: {integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==} - peerDependencies: - '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 - react: ^19.0.0 - react-dom: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-presence@1.1.3': resolution: {integrity: sha512-IrVLIhskYhH3nLvtcBLQFZr61tBG7wx7O3kEmdzcYwRGAEBmBicGGL7ATzNgruYJ3xBTbuzEEq9OXJM3PAX3tA==} peerDependencies: @@ -9311,19 +8557,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-primitive@2.0.2': - resolution: {integrity: sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==} - peerDependencies: - '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 - react: ^19.0.0 - react-dom: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-primitive@2.0.3': resolution: {integrity: sha512-Pf/t/GkndH7CQ8wE2hbkXA+WyZ83fhQQn5DDmwDiDo6AwN/fhaH8oqZ0jRjMrO2iaMhDi6P1HRx6AZwyMinY1g==} peerDependencies: @@ -9428,15 +8661,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-slot@1.1.2': - resolution: {integrity: sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-slot@1.2.0': resolution: {integrity: sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==} peerDependencies: @@ -9525,56 +8749,20 @@ packages: optional: true '@radix-ui/react-tooltip@1.2.0': - resolution: {integrity: sha512-b1Sdc75s7zN9B8ONQTGBSHL3XS8+IcjcOIY51fhM4R1Hx8s0YbgqgyNZiri4qcYMVZK8hfCZVBiyCm7N9rs0rw==} - peerDependencies: - '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 - react: ^19.0.0 - react-dom: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-use-callback-ref@1.1.0': - resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-callback-ref@1.1.1': - resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-controllable-state@1.1.0': - resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-controllable-state@1.1.1': - resolution: {integrity: sha512-YnEXIy8/ga01Y1PN0VfaNH//MhA91JlEGVBDxDzROqwrAtG5Yr2QGEPz8A/rJA3C7ZAHryOYGaUv8fLSW2H/mg==} + resolution: {integrity: sha512-b1Sdc75s7zN9B8ONQTGBSHL3XS8+IcjcOIY51fhM4R1Hx8s0YbgqgyNZiri4qcYMVZK8hfCZVBiyCm7N9rs0rw==} peerDependencies: '@types/react': ^19.0.8 + '@types/react-dom': ^19.0.3 react: ^19.0.0 + react-dom: ^19.0.0 peerDependenciesMeta: '@types/react': optional: true + '@types/react-dom': + optional: true - '@radix-ui/react-use-escape-keydown@1.1.0': - resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} peerDependencies: '@types/react': ^19.0.8 react: ^19.0.0 @@ -9582,8 +8770,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-escape-keydown@1.1.1': - resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + '@radix-ui/react-use-controllable-state@1.1.1': + resolution: {integrity: sha512-YnEXIy8/ga01Y1PN0VfaNH//MhA91JlEGVBDxDzROqwrAtG5Yr2QGEPz8A/rJA3C7ZAHryOYGaUv8fLSW2H/mg==} peerDependencies: '@types/react': ^19.0.8 react: ^19.0.0 @@ -9591,8 +8779,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-layout-effect@1.1.0': - resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} peerDependencies: '@types/react': ^19.0.8 react: ^19.0.0 @@ -9665,16 +8853,6 @@ packages: '@types/react-dom': optional: true - '@redocly/ajv@8.11.2': - resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==} - - '@redocly/config@0.20.3': - resolution: {integrity: sha512-Nyyv1Bj7GgYwj/l46O0nkH1GTKWbO3Ixe7KFcn021aZipkZd+z8Vlu1BwkhqtVgivcKaClaExtWU/lDHkjBzag==} - - '@redocly/openapi-core@1.28.0': - resolution: {integrity: sha512-jnUsOFnz8w71l14Ww34Iswlj0AI4e/R0C5+K2W4v4GaY/sUkpH/145gHLJYlG4XV0neET4lNIptd4I8+yLyEHQ==} - engines: {node: '>=18.17.0', npm: '>=10.8.2'} - '@rollup/plugin-alias@5.1.1': resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==} engines: {node: '>=14.0.0'} @@ -9684,21 +8862,8 @@ packages: rollup: optional: true - '@rollup/plugin-babel@6.0.4': - resolution: {integrity: sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw==} - engines: {node: '>=14.0.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@types/babel__core': ^7.1.9 - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - '@types/babel__core': - optional: true - rollup: - optional: true - - '@rollup/plugin-commonjs@28.0.2': - resolution: {integrity: sha512-BEFI2EDqzl+vA1rl97IDRZ61AIwGH093d9nz8+dThxJNH8oSoB7MjWvPCX3dkaK1/RCJ/1v/R1XB15FuSs0fQw==} + '@rollup/plugin-commonjs@28.0.3': + resolution: {integrity: sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==} engines: {node: '>=16.0.0 || 14 >= 14.17'} peerDependencies: rollup: ^2.68.0||^3.0.0||^4.0.0 @@ -9724,8 +8889,8 @@ packages: rollup: optional: true - '@rollup/plugin-node-resolve@15.3.1': - resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==} + '@rollup/plugin-node-resolve@16.0.1': + resolution: {integrity: sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.78.0||^3.0.0||^4.0.0 @@ -9760,103 +8925,103 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.39.0': - resolution: {integrity: sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==} + '@rollup/rollup-android-arm-eabi@4.38.0': + resolution: {integrity: sha512-ldomqc4/jDZu/xpYU+aRxo3V4mGCV9HeTgUBANI3oIQMOL+SsxB+S2lxMpkFp5UamSS3XuTMQVbsS24R4J4Qjg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.39.0': - resolution: {integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==} + '@rollup/rollup-android-arm64@4.38.0': + resolution: {integrity: sha512-VUsgcy4GhhT7rokwzYQP+aV9XnSLkkhlEJ0St8pbasuWO/vwphhZQxYEKUP3ayeCYLhk6gEtacRpYP/cj3GjyQ==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.39.0': - resolution: {integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==} + '@rollup/rollup-darwin-arm64@4.38.0': + resolution: {integrity: sha512-buA17AYXlW9Rn091sWMq1xGUvWQFOH4N1rqUxGJtEQzhChxWjldGCCup7r/wUnaI6Au8sKXpoh0xg58a7cgcpg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.39.0': - resolution: {integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==} + '@rollup/rollup-darwin-x64@4.38.0': + resolution: {integrity: sha512-Mgcmc78AjunP1SKXl624vVBOF2bzwNWFPMP4fpOu05vS0amnLcX8gHIge7q/lDAHy3T2HeR0TqrriZDQS2Woeg==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.39.0': - resolution: {integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==} + '@rollup/rollup-freebsd-arm64@4.38.0': + resolution: {integrity: sha512-zzJACgjLbQTsscxWqvrEQAEh28hqhebpRz5q/uUd1T7VTwUNZ4VIXQt5hE7ncs0GrF+s7d3S4on4TiXUY8KoQA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.39.0': - resolution: {integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==} + '@rollup/rollup-freebsd-x64@4.38.0': + resolution: {integrity: sha512-hCY/KAeYMCyDpEE4pTETam0XZS4/5GXzlLgpi5f0IaPExw9kuB+PDTOTLuPtM10TlRG0U9OSmXJ+Wq9J39LvAg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.39.0': - resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==} + '@rollup/rollup-linux-arm-gnueabihf@4.38.0': + resolution: {integrity: sha512-mimPH43mHl4JdOTD7bUMFhBdrg6f9HzMTOEnzRmXbOZqjijCw8LA5z8uL6LCjxSa67H2xiLFvvO67PT05PRKGg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.39.0': - resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==} + '@rollup/rollup-linux-arm-musleabihf@4.38.0': + resolution: {integrity: sha512-tPiJtiOoNuIH8XGG8sWoMMkAMm98PUwlriOFCCbZGc9WCax+GLeVRhmaxjJtz6WxrPKACgrwoZ5ia/uapq3ZVg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.39.0': - resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==} + '@rollup/rollup-linux-arm64-gnu@4.38.0': + resolution: {integrity: sha512-wZco59rIVuB0tjQS0CSHTTUcEde+pXQWugZVxWaQFdQQ1VYub/sTrNdY76D1MKdN2NB48JDuGABP6o6fqos8mA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.39.0': - resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==} + '@rollup/rollup-linux-arm64-musl@4.38.0': + resolution: {integrity: sha512-fQgqwKmW0REM4LomQ+87PP8w8xvU9LZfeLBKybeli+0yHT7VKILINzFEuggvnV9M3x1Ed4gUBmGUzCo/ikmFbQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.39.0': - resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==} + '@rollup/rollup-linux-loongarch64-gnu@4.38.0': + resolution: {integrity: sha512-hz5oqQLXTB3SbXpfkKHKXLdIp02/w3M+ajp8p4yWOWwQRtHWiEOCKtc9U+YXahrwdk+3qHdFMDWR5k+4dIlddg==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': - resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==} + '@rollup/rollup-linux-powerpc64le-gnu@4.38.0': + resolution: {integrity: sha512-NXqygK/dTSibQ+0pzxsL3r4Xl8oPqVoWbZV9niqOnIHV/J92fe65pOir0xjkUZDRSPyFRvu+4YOpJF9BZHQImw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.39.0': - resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==} + '@rollup/rollup-linux-riscv64-gnu@4.38.0': + resolution: {integrity: sha512-GEAIabR1uFyvf/jW/5jfu8gjM06/4kZ1W+j1nWTSSB3w6moZEBm7iBtzwQ3a1Pxos2F7Gz+58aVEnZHU295QTg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.39.0': - resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==} + '@rollup/rollup-linux-riscv64-musl@4.38.0': + resolution: {integrity: sha512-9EYTX+Gus2EGPbfs+fh7l95wVADtSQyYw4DfSBcYdUEAmP2lqSZY0Y17yX/3m5VKGGJ4UmIH5LHLkMJft3bYoA==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.39.0': - resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==} + '@rollup/rollup-linux-s390x-gnu@4.38.0': + resolution: {integrity: sha512-Mpp6+Z5VhB9VDk7RwZXoG2qMdERm3Jw07RNlXHE0bOnEeX+l7Fy4bg+NxfyN15ruuY3/7Vrbpm75J9QHFqj5+Q==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.39.0': - resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==} + '@rollup/rollup-linux-x64-gnu@4.38.0': + resolution: {integrity: sha512-vPvNgFlZRAgO7rwncMeE0+8c4Hmc+qixnp00/Uv3ht2x7KYrJ6ERVd3/R0nUtlE6/hu7/HiiNHJ/rP6knRFt1w==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.39.0': - resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==} + '@rollup/rollup-linux-x64-musl@4.38.0': + resolution: {integrity: sha512-q5Zv+goWvQUGCaL7fU8NuTw8aydIL/C9abAVGCzRReuj5h30TPx4LumBtAidrVOtXnlB+RZkBtExMsfqkMfb8g==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.39.0': - resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==} + '@rollup/rollup-win32-arm64-msvc@4.38.0': + resolution: {integrity: sha512-u/Jbm1BU89Vftqyqbmxdq14nBaQjQX1HhmsdBWqSdGClNaKwhjsg5TpW+5Ibs1mb8Es9wJiMdl86BcmtUVXNZg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.39.0': - resolution: {integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==} + '@rollup/rollup-win32-ia32-msvc@4.38.0': + resolution: {integrity: sha512-mqu4PzTrlpNHHbu5qleGvXJoGgHpChBlrBx/mEhTPpnAL1ZAYFlvHD7rLK839LLKQzqEQMFJfGrrOHItN4ZQqA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.39.0': - resolution: {integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==} + '@rollup/rollup-win32-x64-msvc@4.38.0': + resolution: {integrity: sha512-jjqy3uWlecfB98Psxb5cD6Fny9Fupv9LrDSPTQZUROqjvZmcCqNu4UMl7qqhlUUGpwiAkotj6GYu4SZdcr/nLw==} cpu: [x64] os: [win32] @@ -10117,6 +9282,10 @@ packages: resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} + '@sindresorhus/is@7.0.1': + resolution: {integrity: sha512-QWLl2P+rsCJeofkDNIT3WFmb6NrRud1SUYW8dIhXK/46XFV8Q/g7Bsvib0Askb0reRLe+WYPeeE+l5cH7SlkuQ==} + engines: {node: '>=18'} + '@sindresorhus/merge-streams@2.3.0': resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} engines: {node: '>=18'} @@ -10221,6 +9390,9 @@ packages: '@solidjs/router': optional: true + '@speed-highlight/core@1.2.7': + resolution: {integrity: sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==} + '@stylistic/eslint-plugin-js@2.13.0': resolution: {integrity: sha512-GPPDK4+fcbsQD58a3abbng2Dx+jBoxM5cnYjBM4T24WFZRZdlNSKvR19TxP8CPevzMOodQ9QVzNeqWvMXzfJRA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -10332,83 +9504,95 @@ packages: '@swc/types@0.1.17': resolution: {integrity: sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==} - '@tailwindcss/node@4.0.8': - resolution: {integrity: sha512-FKArQpbrbwv08TNT0k7ejYXpF+R8knZFAatNc0acOxbgeqLzwb86r+P3LGOjIeI3Idqe9CVkZrh4GlsJLJKkkw==} + '@tailwindcss/node@4.1.6': + resolution: {integrity: sha512-ed6zQbgmKsjsVvodAS1q1Ld2BolEuxJOSyyNc+vhkjdmfNUDCmQnlXBfQkHrlzNmslxHsQU/bFmzcEbv4xXsLg==} - '@tailwindcss/oxide-android-arm64@4.0.8': - resolution: {integrity: sha512-We7K79+Sm4mwJHk26Yzu/GAj7C7myemm7PeXvpgMxyxO70SSFSL3uCcqFbz9JA5M5UPkrl7N9fkBe/Y0iazqpA==} + '@tailwindcss/oxide-android-arm64@4.1.6': + resolution: {integrity: sha512-VHwwPiwXtdIvOvqT/0/FLH/pizTVu78FOnI9jQo64kSAikFSZT7K4pjyzoDpSMaveJTGyAKvDjuhxJxKfmvjiQ==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.0.8': - resolution: {integrity: sha512-Lv9Isi2EwkCTG1sRHNDi0uRNN1UGFdEThUAGFrydRmQZnraGLMjN8gahzg2FFnOizDl7LB2TykLUuiw833DSNg==} + '@tailwindcss/oxide-darwin-arm64@4.1.6': + resolution: {integrity: sha512-weINOCcqv1HVBIGptNrk7c6lWgSFFiQMcCpKM4tnVi5x8OY2v1FrV76jwLukfT6pL1hyajc06tyVmZFYXoxvhQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.0.8': - resolution: {integrity: sha512-fWfywfYIlSWtKoqWTjukTHLWV3ARaBRjXCC2Eo0l6KVpaqGY4c2y8snUjp1xpxUtpqwMvCvFWFaleMoz1Vhzlw==} + '@tailwindcss/oxide-darwin-x64@4.1.6': + resolution: {integrity: sha512-3FzekhHG0ww1zQjQ1lPoq0wPrAIVXAbUkWdWM8u5BnYFZgb9ja5ejBqyTgjpo5mfy0hFOoMnMuVDI+7CXhXZaQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.0.8': - resolution: {integrity: sha512-SO+dyvjJV9G94bnmq2288Ke0BIdvrbSbvtPLaQdqjqHR83v5L2fWADyFO+1oecHo9Owsk8MxcXh1agGVPIKIqw==} + '@tailwindcss/oxide-freebsd-x64@4.1.6': + resolution: {integrity: sha512-4m5F5lpkBZhVQJq53oe5XgJ+aFYWdrgkMwViHjRsES3KEu2m1udR21B1I77RUqie0ZYNscFzY1v9aDssMBZ/1w==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.0.8': - resolution: {integrity: sha512-ZSHggWiEblQNV69V0qUK5vuAtHP+I+S2eGrKGJ5lPgwgJeAd6GjLsVBN+Mqn2SPVfYM3BOpS9jX/zVg9RWQVDQ==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.6': + resolution: {integrity: sha512-qU0rHnA9P/ZoaDKouU1oGPxPWzDKtIfX7eOGi5jOWJKdxieUJdVV+CxWZOpDWlYTd4N3sFQvcnVLJWJ1cLP5TA==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.0.8': - resolution: {integrity: sha512-xWpr6M0OZLDNsr7+bQz+3X7zcnDJZJ1N9gtBWCtfhkEtDjjxYEp+Lr5L5nc/yXlL4MyCHnn0uonGVXy3fhxaVA==} + '@tailwindcss/oxide-linux-arm64-gnu@4.1.6': + resolution: {integrity: sha512-jXy3TSTrbfgyd3UxPQeXC3wm8DAgmigzar99Km9Sf6L2OFfn/k+u3VqmpgHQw5QNfCpPe43em6Q7V76Wx7ogIQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-arm64-musl@4.0.8': - resolution: {integrity: sha512-5tz2IL7LN58ssGEq7h/staD7pu/izF/KeMWdlJ86WDe2Ah46LF3ET6ZGKTr5eZMrnEA0M9cVFuSPprKRHNgjeg==} + '@tailwindcss/oxide-linux-arm64-musl@4.1.6': + resolution: {integrity: sha512-8kjivE5xW0qAQ9HX9reVFmZj3t+VmljDLVRJpVBEoTR+3bKMnvC7iLcoSGNIUJGOZy1mLVq7x/gerVg0T+IsYw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-x64-gnu@4.0.8': - resolution: {integrity: sha512-KSzMkhyrxAQyY2o194NKVKU9j/c+NFSoMvnHWFaNHKi3P1lb+Vq1UC19tLHrmxSkKapcMMu69D7+G1+FVGNDXQ==} + '@tailwindcss/oxide-linux-x64-gnu@4.1.6': + resolution: {integrity: sha512-A4spQhwnWVpjWDLXnOW9PSinO2PTKJQNRmL/aIl2U/O+RARls8doDfs6R41+DAXK0ccacvRyDpR46aVQJJCoCg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-linux-x64-musl@4.0.8': - resolution: {integrity: sha512-yFYKG5UtHTRimjtqxUWXBgI4Tc6NJe3USjRIVdlTczpLRxq/SFwgzGl5JbatCxgSRDPBFwRrNPxq+ukfQFGdrw==} + '@tailwindcss/oxide-linux-x64-musl@4.1.6': + resolution: {integrity: sha512-YRee+6ZqdzgiQAHVSLfl3RYmqeeaWVCk796MhXhLQu2kJu2COHBkqlqsqKYx3p8Hmk5pGCQd2jTAoMWWFeyG2A==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-win32-arm64-msvc@4.0.8': - resolution: {integrity: sha512-tndGujmCSba85cRCnQzXgpA2jx5gXimyspsUYae5jlPyLRG0RjXbDshFKOheVXU4TLflo7FSG8EHCBJ0EHTKdQ==} + '@tailwindcss/oxide-wasm32-wasi@4.1.6': + resolution: {integrity: sha512-qAp4ooTYrBQ5pk5jgg54/U1rCJ/9FLYOkkQ/nTE+bVMseMfB6O7J8zb19YTpWuu4UdfRf5zzOrNKfl6T64MNrQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.6': + resolution: {integrity: sha512-nqpDWk0Xr8ELO/nfRUDjk1pc9wDJ3ObeDdNMHLaymc4PJBWj11gdPCWZFKSK2AVKjJQC7J2EfmSmf47GN7OuLg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.0.8': - resolution: {integrity: sha512-T77jroAc0p4EHVVgTUiNeFn6Nj3jtD3IeNId2X+0k+N1XxfNipy81BEkYErpKLiOkNhpNFjPee8/ZVas29b2OQ==} + '@tailwindcss/oxide-win32-x64-msvc@4.1.6': + resolution: {integrity: sha512-5k9xF33xkfKpo9wCvYcegQ21VwIBU1/qEbYlVukfEIyQbEA47uK8AAwS7NVjNE3vHzcmxMYwd0l6L4pPjjm1rQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.0.8': - resolution: {integrity: sha512-KfMcuAu/Iw+DcV1e8twrFyr2yN8/ZDC/odIGta4wuuJOGkrkHZbvJvRNIbQNhGh7erZTYV6Ie0IeD6WC9Y8Hcw==} + '@tailwindcss/oxide@4.1.6': + resolution: {integrity: sha512-0bpEBQiGx+227fW4G0fLQ8vuvyy5rsB1YIYNapTq3aRsJ9taF3f5cCaovDjN5pUGKKzcpMrZst/mhNaKAPOHOA==} engines: {node: '>= 10'} - '@tailwindcss/vite@4.0.8': - resolution: {integrity: sha512-+SAq44yLzYlzyrb7QTcFCdU8Xa7FOA0jp+Xby7fPMUie+MY9HhJysM7Vp+vL8qIp8ceQJfLD+FjgJuJ4lL6nyg==} + '@tailwindcss/vite@4.1.6': + resolution: {integrity: sha512-zjtqjDeY1w3g2beYQtrMAf51n5G7o+UwmyOjtsDMP7t6XyoRMOidcoKP32ps7AkNOHIXEOK0bhIC05dj8oJp4w==} peerDependencies: - vite: 6.1.4 + vite: 6.3.5 '@tanstack/config@0.16.1': resolution: {integrity: sha512-GLt1xyQCGRty58N2jv0ONouv8OU46FjkbcSSTiAKwydcX+JycZ7FCLWt05lefrvuV8Eay0eNuN0sYUemObZLEA==} @@ -10418,14 +9602,14 @@ packages: '@tanstack/query-core@5.66.0': resolution: {integrity: sha512-J+JeBtthiKxrpzUu7rfIPDzhscXF2p5zE/hVdrqkACBP8Yu0M96mwJ5m/8cPPYQE9aRNvXztXHlNwIh4FEeMZw==} - '@tanstack/query-core@5.71.5': - resolution: {integrity: sha512-XOQ5SyjCdwhxyLksGKWSL5poqyEXYPDnsrZAzJm2LgrMm4Yh6VOrfC+IFosXreDw9HNqC11YAMY3HlfHjNzuaA==} + '@tanstack/query-core@5.72.2': + resolution: {integrity: sha512-fxl9/0yk3mD/FwTmVEf1/H6N5B975H0luT+icKyX566w6uJG0x6o+Yl+I38wJRCaogiMkstByt+seXfDbWDAcA==} '@tanstack/query-devtools@5.67.2': resolution: {integrity: sha512-O4QXFFd7xqp6EX7sdvc9tsVO8nm4lpWBqwpgjpVLW5g7IeOY6VnS/xvs/YzbRhBVkKTMaJMOUGU7NhSX+YGoNg==} - '@tanstack/query-devtools@5.71.5': - resolution: {integrity: sha512-Fq1JeAp+I52Md/KnyeFxzG7G0RpdHgeOfDNhSPkZQs/JqqXuAfpUf+wFHDz+vP0GZbSnla2JmcLSQebOkIb1yA==} + '@tanstack/query-devtools@5.72.2': + resolution: {integrity: sha512-mMKnGb+iOhVBcj6jaerCFRpg8pACStdG8hmUBHPtToeZzs4ctjBUL1FajqpVn2WaMxnq8Wya+P3Q5tPFNM9jQw==} '@tanstack/react-query-devtools@5.67.2': resolution: {integrity: sha512-cmj2DxBc+/9btQ66n5xI8wTtAma2BLVa403K7zIYiguzJ/kV201jnGensYqJeu1Rd8uRMLLRM74jLVMLDWNRJA==} @@ -10450,14 +9634,14 @@ packages: react: ^19.0.0 react-dom: ^19.0.0 - '@tanstack/solid-query-devtools@5.71.9': - resolution: {integrity: sha512-i2U8UcJM7TnciR7QBWFynAaEub+uhzYcS9L80pAu0J3nETTojjZl3Hl1UUMUYiA7jCFPU9bWQWHjJouUvzGU1w==} + '@tanstack/solid-query-devtools@5.72.2': + resolution: {integrity: sha512-duYFN6EMsV0iwz1vV60GvxsQy3PXycgHhrucaik2yvJlRKrEYuHTYGqpRTy+P3JrFZkEzVLjevMnbzR4IIt5vw==} peerDependencies: - '@tanstack/solid-query': ^5.71.9 + '@tanstack/solid-query': ^5.72.2 solid-js: ^1.6.0 - '@tanstack/solid-query@5.71.9': - resolution: {integrity: sha512-ue9xAX2okLGdXxSWcnYfOedL/QgOx9eNKEJdoM9D3RF5xxxn3p+dXp7+Buzqu2OmfwRnAjHkWRASgS/9NlDMLg==} + '@tanstack/solid-query@5.72.2': + resolution: {integrity: sha512-ty4J5q+DIPEs7xB01TqkTfx0wYkcccJaofb378Nq/HfWoQ/0300A8TM7CU7YotJUmVWA3qwBHnJLChXlNzX4ow==} peerDependencies: solid-js: ^1.6.0 @@ -10560,9 +9744,6 @@ packages: '@types/bonjour@3.5.13': resolution: {integrity: sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==} - '@types/braces@3.0.5': - resolution: {integrity: sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w==} - '@types/connect-history-api-fallback@1.5.4': resolution: {integrity: sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==} @@ -10644,9 +9825,6 @@ packages: '@types/koa@2.15.0': resolution: {integrity: sha512-7QFsywoE5URbuVnG3loe03QXuGajrnotr3gQkXcEBShORai23MePfFYdhz90FEtBBpkyIYQbVD+evKtloCgX3g==} - '@types/micromatch@4.0.9': - resolution: {integrity: sha512-7V+8ncr22h4UoYRLnLXSpTxjQrNUXtWHGeMPRJt1nULXI57G9bIcpyrHlmrQ7QK24EyyuXvYcSSWAM8GA9nqCg==} - '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} @@ -10808,20 +9986,16 @@ packages: resolution: {integrity: sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vercel/nft@0.27.10': - resolution: {integrity: sha512-zbaF9Wp/NsZtKLE4uVmL3FyfFwlpDyuymQM1kPbeT0mVOHKDQQNjnnfslB3REg3oZprmNFJuh3pkHBk2qAaizg==} - engines: {node: '>=16'} - hasBin: true - - '@vinxi/listhen@1.5.6': - resolution: {integrity: sha512-WSN1z931BtasZJlgPp704zJFnQFRg7yzSjkm3MzAWQYe4uXFXlFr1hc5Ac2zae5/HDOz5x1/zDM5Cb54vTCnWw==} + '@vercel/nft@0.29.2': + resolution: {integrity: sha512-A/Si4mrTkQqJ6EXJKv5EYCDQ3NL6nJXxG8VGXePsaiQigsomHYQC9xSpX8qGk7AEZk4b1ssbYIqJ0ISQQ7bfcA==} + engines: {node: '>=18'} hasBin: true '@vitejs/plugin-react@4.3.4': resolution: {integrity: sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - vite: 6.1.4 + vite: 6.3.5 '@vitest/browser@3.0.6': resolution: {integrity: sha512-FqKwCAkALZfNzGNx4YvRJa6HCWM2USWTjOdNO2egI/s6+3WkIl4xAlYISOARLJLDAI3yCXcpTtuUUF39K8TQgw==} @@ -10845,7 +10019,7 @@ packages: resolution: {integrity: sha512-KPztr4/tn7qDGZfqlSPQoF2VgJcKxnDNhmfR3VgZ6Fy1bO8T9Fc1stUiTXtqz0yG24VpD00pZP5f8EOFknjNuQ==} peerDependencies: msw: ^2.4.9 - vite: 6.1.4 + vite: 6.3.5 peerDependenciesMeta: msw: optional: true @@ -10979,8 +10153,8 @@ packages: webpack-dev-server: optional: true - '@workos-inc/node@7.45.0': - resolution: {integrity: sha512-8wx2YuhkmTc3bKc1Py/Gv8X44QovIDQVLfDL8qNMRybCLD5Cu7R6AnWP/ZI5VHwSgeird0g+Cuukqk3ZG8ycMg==} + '@workos-inc/node@7.46.0': + resolution: {integrity: sha512-r/j+l/nlHkOqgIt0U70shZMKIQwLYFFU9aYmFW53l16+FwG+61SfldaK3ckjb3gscoGxWq+t7RlxcEe7Tz5eRA==} engines: {node: '>=16'} '@xtuc/ieee754@1.2.0': @@ -11026,8 +10200,8 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.14.0: - resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + acorn@8.14.1: + resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} engines: {node: '>=0.4.0'} hasBin: true @@ -11088,9 +10262,6 @@ packages: alien-signals@0.4.14: resolution: {integrity: sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==} - ansi-align@3.0.1: - resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} - ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -11266,10 +10437,6 @@ packages: boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - boxen@7.1.1: - resolution: {integrity: sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==} - engines: {node: '>=14.16'} - brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -11306,8 +10473,8 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - c12@2.0.1: - resolution: {integrity: sha512-Z4JgsKXHG37C6PYUtIxCfLJZvo6FyhHJoClwwb9ftUkLpPSkuYqn6Tr+vnaN8hymm0kIbcg6Ey3kv/Q71k5w/A==} + c12@3.0.2: + resolution: {integrity: sha512-6Tzk1/TNeI3WBPpK0j/Ss4+gPj3PUJYbWl/MWDJBThFvwNGNkXtd7Cz8BJtD4aRwoGHtzQD0SnxamgUiBH0/Nw==} peerDependencies: magicast: ^0.3.5 peerDependenciesMeta: @@ -11337,10 +10504,6 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - camelcase@7.0.1: - resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} - engines: {node: '>=14.16'} - caniuse-lite@1.0.30001696: resolution: {integrity: sha512-pDCPkvzfa39ehJtJ+OwGT/2yvT2SbjfHhiIW2LWOAcMQ7BzwxT/XuyUp4OTOd0XFWA6BKw0JalnBHgSi5DGJBQ==} @@ -11360,9 +10523,6 @@ packages: resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - change-case@5.4.4: - resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} - char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} @@ -11371,6 +10531,13 @@ packages: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.0.0: + resolution: {integrity: sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==} + engines: {node: '>=18.17'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -11379,10 +10546,6 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} - chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -11404,10 +10567,6 @@ packages: resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} engines: {node: '>= 10.0'} - cli-boxes@3.0.0: - resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} - engines: {node: '>=10'} - cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -11463,9 +10622,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - colorette@1.4.0: - resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -11533,12 +10689,15 @@ packages: confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + confbox@0.2.1: + resolution: {integrity: sha512-hkT3yDPFbs95mNCy1+7qNKC6Pro+/ibzYxtM2iqEigpf0sVw+bg4Zh9/snjsBcf990vfIsg5+1U7VyiyBb3etg==} + connect-history-api-fallback@2.0.0: resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} engines: {node: '>=0.8'} - consola@3.4.0: - resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==} + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} content-disposition@0.5.4: @@ -11586,6 +10745,9 @@ packages: cookie-es@1.2.2: resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + cookie-es@2.0.0: + resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} @@ -11605,10 +10767,6 @@ packages: resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} engines: {node: '>=18'} - copy-anything@3.0.5: - resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} - engines: {node: '>=12.13'} - core-js@3.40.0: resolution: {integrity: sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==} @@ -11636,12 +10794,15 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - crossws@0.3.3: - resolution: {integrity: sha512-/71DJT3xJlqSnBr83uGJesmVHSzZEvgxHt/fIKxBAAngqMHmnBWQNxCphVxxJ2XL3xleu5+hJD6IQ3TglBedcw==} + crossws@0.3.4: + resolution: {integrity: sha512-uj0O1ETYX1Bh6uSgktfPvwDiPYGQ3aI4qVsaC/LWpkIzGj1nUYm5FK3K+t11oOlpN01lGbprFCH4wBlKdJjVgw==} css-select@4.3.0: resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + css-what@6.1.0: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} @@ -11661,10 +10822,6 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - data-uri-to-buffer@4.0.1: - resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} - engines: {node: '>= 12'} - data-urls@5.0.0: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} @@ -11673,11 +10830,8 @@ packages: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} - dax-sh@0.39.2: - resolution: {integrity: sha512-gpuGEkBQM+5y6p4cWaw9+ePy5TNon+fdwFVtTI8leU3UhwhsBfPewRxMXGuQNC+M2b/MDGMlfgpqynkcd0C3FQ==} - - db0@0.2.3: - resolution: {integrity: sha512-PunuHESDNefmwVy1LDpY663uWwKt2ogLGoB6NOz2sflGREWqDreMwDgF8gfkXxgNXW+dqviyiJGm924H1BaGiw==} + db0@0.3.1: + resolution: {integrity: sha512-3RogPLE2LLq6t4YiFCREyl572aBjkfMvfwPyN51df00TbPbryL3XqBYuJ/j6mgPssPK8AKfYdLxizaO5UG10sA==} peerDependencies: '@electric-sql/pglite': '*' '@libsql/client': '*' @@ -11730,14 +10884,6 @@ packages: decimal.js@10.5.0: resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==} - dedent@1.5.3: - resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true - deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} @@ -11807,8 +10953,8 @@ packages: engines: {node: '>=0.10'} hasBin: true - detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} + detect-libc@2.0.4: + resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} detect-node-es@1.1.0: @@ -11854,6 +11000,9 @@ packages: dom-serializer@1.4.1: resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} @@ -11861,9 +11010,16 @@ packages: resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} engines: {node: '>= 4'} + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} @@ -11916,6 +11072,9 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + encoding-sniffer@0.2.0: + resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==} + end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} @@ -11934,6 +11093,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@6.0.0: + resolution: {integrity: sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==} + engines: {node: '>=0.12'} + envinfo@7.14.0: resolution: {integrity: sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==} engines: {node: '>=4'} @@ -11946,6 +11109,9 @@ packages: error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + error-stack-parser@2.1.4: resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} @@ -11975,11 +11141,6 @@ packages: peerDependencies: esbuild: '>=0.12 <1' - esbuild@0.20.2: - resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} - engines: {node: '>=12'} - hasBin: true - esbuild@0.23.0: resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==} engines: {node: '>=18'} @@ -11990,13 +11151,8 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.24.2: - resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} - engines: {node: '>=18'} - hasBin: true - - esbuild@0.25.0: - resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} + esbuild@0.25.2: + resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==} engines: {node: '>=18'} hasBin: true @@ -12231,6 +11387,9 @@ packages: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} + exsolve@1.0.4: + resolution: {integrity: sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -12264,18 +11423,14 @@ packages: resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} engines: {node: '>=0.8.0'} - fdir@6.4.3: - resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} + fdir@6.4.4: + resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: picomatch: optional: true - fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} - fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} @@ -12360,10 +11515,6 @@ packages: resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} engines: {node: '>= 6'} - formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} - forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -12403,10 +11554,6 @@ packages: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} - fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -12442,10 +11589,6 @@ packages: get-port-please@3.1.2: resolution: {integrity: sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==} - get-port@7.1.0: - resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==} - engines: {node: '>=16'} - get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -12457,8 +11600,8 @@ packages: get-tsconfig@4.10.0: resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} - giget@1.2.4: - resolution: {integrity: sha512-Wv+daGyispVoA31TrWAVR+aAdP7roubTPEM/8JzRnqXhLbdJH0T9eQyXVFF8fjk3WKTsctII6QcyxILYgNp2DA==} + giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} hasBin: true glob-parent@5.1.2: @@ -12481,10 +11624,6 @@ packages: engines: {node: 20 || >=22} hasBin: true - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - glob@9.3.5: resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} engines: {node: '>=16 || 14 >=14.17'} @@ -12509,8 +11648,8 @@ packages: resolution: {integrity: sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==} engines: {node: '>=18'} - globby@14.0.2: - resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==} + globby@14.1.0: + resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} engines: {node: '>=18'} globrex@0.1.2: @@ -12542,6 +11681,9 @@ packages: h3@1.13.0: resolution: {integrity: sha512-vFEAu/yf8UMUcB4s43OaDaigcqpQd14yanmOsn+NcRX3/guSKncyE2rOYhq8RIchgJrPSs/QiIddnTTR1ddiAg==} + h3@1.15.1: + resolution: {integrity: sha512-+ORaOBttdUm1E2Uu/obAyCguiI7MbBvsLTndc3gyK3zU+SYLoZXlyCP9Xgy0gikkGufFLTZXCXD6+4BsufnmHA==} + handle-thing@2.0.1: resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} @@ -12614,6 +11756,9 @@ packages: htmlparser2@6.1.0: resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} + htmlparser2@9.1.0: + resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} + http-deceiver@1.2.7: resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==} @@ -12686,6 +11831,10 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + ignore@7.0.3: + resolution: {integrity: sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==} + engines: {node: '>= 4'} + immer@10.1.1: resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==} @@ -12702,9 +11851,6 @@ packages: engines: {node: '>=8'} hasBin: true - import-meta-resolve@4.1.0: - resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} - imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -12713,14 +11859,6 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - index-to-position@0.1.2: - resolution: {integrity: sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==} - engines: {node: '>=18'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - inherits@2.0.3: resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} @@ -12737,8 +11875,8 @@ packages: resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} engines: {node: '>=10.13.0'} - ioredis@5.4.2: - resolution: {integrity: sha512-0SZXGNGZ+WzISQ67QDyZ2x0+wVxjjUndtD8oSeik/4ajifeiRufed8fCb8QW8VMyi4MXcS+UO1k/0NGhvq1PAg==} + ioredis@5.6.0: + resolution: {integrity: sha512-tBZlIIWbndeWBWCXWZiqtOF/yxf6yZX3tAlTJ7nfo5jhd6dctNxF7QnYlZLZ1a0o0pDoen7CgZqO+zjNaFbJAg==} engines: {node: '>=12.22.0'} ipaddr.js@1.9.1: @@ -12919,10 +12057,6 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isexe@3.1.1: - resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} - engines: {node: '>=16'} - isobject@3.0.1: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} @@ -12971,10 +12105,6 @@ packages: resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} engines: {node: '>=14'} - js-levenshtein@1.1.6: - resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} - engines: {node: '>=0.10.0'} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -13049,6 +12179,10 @@ packages: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + klona@2.0.6: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} @@ -13084,68 +12218,68 @@ packages: resolution: {integrity: sha512-a5BQjbCHnB+cy+gsro8lXJ4kZluzOijzJ1UVVfyJYZC+IP2pLv1h4+aysQeKuTmyO8NAqfyQAk4HWaP/HjcKTg==} engines: {node: '>=10.13.0'} - lightningcss-darwin-arm64@1.29.1: - resolution: {integrity: sha512-HtR5XJ5A0lvCqYAoSv2QdZZyoHNttBpa5EP9aNuzBQeKGfbyH5+UipLWvVzpP4Uml5ej4BYs5I9Lco9u1fECqw==} + lightningcss-darwin-arm64@1.29.2: + resolution: {integrity: sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.29.1: - resolution: {integrity: sha512-k33G9IzKUpHy/J/3+9MCO4e+PzaFblsgBjSGlpAaFikeBFm8B/CkO3cKU9oI4g+fjS2KlkLM/Bza9K/aw8wsNA==} + lightningcss-darwin-x64@1.29.2: + resolution: {integrity: sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.29.1: - resolution: {integrity: sha512-0SUW22fv/8kln2LnIdOCmSuXnxgxVC276W5KLTwoehiO0hxkacBxjHOL5EtHD8BAXg2BvuhsJPmVMasvby3LiQ==} + lightningcss-freebsd-x64@1.29.2: + resolution: {integrity: sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.29.1: - resolution: {integrity: sha512-sD32pFvlR0kDlqsOZmYqH/68SqUMPNj+0pucGxToXZi4XZgZmqeX/NkxNKCPsswAXU3UeYgDSpGhu05eAufjDg==} + lightningcss-linux-arm-gnueabihf@1.29.2: + resolution: {integrity: sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.29.1: - resolution: {integrity: sha512-0+vClRIZ6mmJl/dxGuRsE197o1HDEeeRk6nzycSy2GofC2JsY4ifCRnvUWf/CUBQmlrvMzt6SMQNMSEu22csWQ==} + lightningcss-linux-arm64-gnu@1.29.2: + resolution: {integrity: sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-arm64-musl@1.29.1: - resolution: {integrity: sha512-UKMFrG4rL/uHNgelBsDwJcBqVpzNJbzsKkbI3Ja5fg00sgQnHw/VrzUTEc4jhZ+AN2BvQYz/tkHu4vt1kLuJyw==} + lightningcss-linux-arm64-musl@1.29.2: + resolution: {integrity: sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-x64-gnu@1.29.1: - resolution: {integrity: sha512-u1S+xdODy/eEtjADqirA774y3jLcm8RPtYztwReEXoZKdzgsHYPl0s5V52Tst+GKzqjebkULT86XMSxejzfISw==} + lightningcss-linux-x64-gnu@1.29.2: + resolution: {integrity: sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-linux-x64-musl@1.29.1: - resolution: {integrity: sha512-L0Tx0DtaNUTzXv0lbGCLB/c/qEADanHbu4QdcNOXLIe1i8i22rZRpbT3gpWYsCh9aSL9zFujY/WmEXIatWvXbw==} + lightningcss-linux-x64-musl@1.29.2: + resolution: {integrity: sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-win32-arm64-msvc@1.29.1: - resolution: {integrity: sha512-QoOVnkIEFfbW4xPi+dpdft/zAKmgLgsRHfJalEPYuJDOWf7cLQzYg0DEh8/sn737FaeMJxHZRc1oBreiwZCjog==} + lightningcss-win32-arm64-msvc@1.29.2: + resolution: {integrity: sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.29.1: - resolution: {integrity: sha512-NygcbThNBe4JElP+olyTI/doBNGJvLs3bFCRPdvuCcxZCcCZ71B858IHpdm7L1btZex0FvCmM17FK98Y9MRy1Q==} + lightningcss-win32-x64-msvc@1.29.2: + resolution: {integrity: sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.29.1: - resolution: {integrity: sha512-FmGoeD4S05ewj+AkhTY+D+myDvXI6eL27FjHIjoyUkO/uw7WZD1fBVs0QxeYWa7E17CUHJaYX/RUGISCtcrG4Q==} + lightningcss@1.29.2: + resolution: {integrity: sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==} engines: {node: '>= 12.0.0'} lilconfig@3.1.3: @@ -13174,8 +12308,8 @@ packages: resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} engines: {node: '>=14'} - local-pkg@1.0.0: - resolution: {integrity: sha512-bbgPw/wmroJsil/GgL4qjDzs5YLTBMQ99weRsok1XCDccQeehbHA/I1oRvk2NPtr7KGZgT/Y5tPRnAtMqeG2Kg==} + local-pkg@1.1.1: + resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} engines: {node: '>=14'} locate-path@5.0.0: @@ -13384,35 +12518,18 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} - minipass@4.2.8: resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} engines: {node: '>=8'} - minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} - minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} - minizlib@3.0.1: resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} engines: {node: '>= 18'} - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - mkdirp@3.0.1: resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} engines: {node: '>=10'} @@ -13484,8 +12601,8 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - nitropack@2.10.4: - resolution: {integrity: sha512-sJiG/MIQlZCVSw2cQrFG1H6mLeSqHlYfFerRjLKz69vUfdu0EL2l0WdOxlQbzJr3mMv/l4cOlCCLzVRzjzzF/g==} + nitropack@2.11.8: + resolution: {integrity: sha512-ummTu4R8Lhd1nO3nWrW7eeiHA2ey3ntbWFKkYakm4rcbvT6meWp+oykyrYBNFQKhobQl9CydmUWlCyztYXFPJw==} engines: {node: ^16.11.0 || >=17.0.0} hasBin: true peerDependencies: @@ -13500,10 +12617,6 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - node-emoji@2.2.0: resolution: {integrity: sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==} engines: {node: '>=18'} @@ -13520,10 +12633,6 @@ packages: encoding: optional: true - node-fetch@3.3.2: - resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - node-forge@1.3.1: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} @@ -13535,6 +12644,9 @@ packages: node-machine-id@1.1.12: resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==} + node-mock-http@1.0.0: + resolution: {integrity: sha512-0uGYQ1WQL1M5kKvGRXWQ3uZCHtLTO8hln3oBjIusM75WoesZ909uQJs/Hb946i2SS+Gsrhkaa6iAO17jRIv6DQ==} + node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} @@ -13577,8 +12689,8 @@ packages: '@swc/core': optional: true - nypm@0.5.2: - resolution: {integrity: sha512-AHzvnyUJYSrrphPhRWWZNcoZfArGNp3Vrc4pm/ZurO74tYNTgAPrEyBQEKy+qioqmWlPXwvMZCG2wOaHlPG0Pw==} + nypm@0.6.0: + resolution: {integrity: sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg==} engines: {node: ^14.16.0 || >=16.10.0} hasBin: true @@ -13611,6 +12723,9 @@ packages: ohash@1.1.4: resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==} + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -13638,12 +12753,6 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} - openapi-typescript@7.6.0: - resolution: {integrity: sha512-p/xxKcWFR7aZDOAdnqYBQ1NdNyWdine+gHKHKvjxGXmlq8JT1G9+SkY8I5csKaktLHMbDDH6ZDeWQpydwBHa+Q==} - hasBin: true - peerDependencies: - typescript: ^5.x - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -13700,10 +12809,6 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} - parse-json@8.1.0: - resolution: {integrity: sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==} - engines: {node: '>=18'} - parse-passwd@1.0.0: resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} engines: {node: '>=0.10.0'} @@ -13711,14 +12816,20 @@ packages: parse5-htmlparser2-tree-adapter@6.0.1: resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + parse5@5.1.1: resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} - parse5@7.2.1: - resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} @@ -13734,10 +12845,6 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -13775,9 +12882,9 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - path-type@5.0.0: - resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} - engines: {node: '>=12'} + path-type@6.0.0: + resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} + engines: {node: '>=18'} pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} @@ -13818,6 +12925,9 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + pkg-types@2.1.0: + resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==} + playwright-core@1.52.0: resolution: {integrity: sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==} engines: {node: '>=18'} @@ -13959,6 +13069,9 @@ packages: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} + quansync@0.2.10: + resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -14202,8 +13315,8 @@ packages: rollup: optional: true - rollup@4.39.0: - resolution: {integrity: sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g==} + rollup@4.38.0: + resolution: {integrity: sha512-5SsIRtJy9bf1ErAOiFMFzl64Ex9X5V7bnJ+WlFMb+zmP459OSWCEG7b0ERZ+PEU7xPt4OG3RHbrp1LJlXxYTrw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -14270,8 +13383,8 @@ packages: engines: {node: '>=10'} hasBin: true - semver@7.7.0: - resolution: {integrity: sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==} + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} engines: {node: '>=10'} hasBin: true @@ -14447,8 +13560,8 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} - std-env@3.8.0: - resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} + std-env@3.8.1: + resolution: {integrity: sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==} streamx@2.22.0: resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} @@ -14501,8 +13614,8 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strip-literal@2.1.1: - resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} + strip-literal@3.0.0: + resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} style-to-object@1.0.8: resolution: {integrity: sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==} @@ -14515,9 +13628,9 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true - superjson@2.2.2: - resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} - engines: {node: '>=16'} + supports-color@10.0.0: + resolution: {integrity: sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ==} + engines: {node: '>=18'} supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -14527,10 +13640,6 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - supports-color@9.4.0: - resolution: {integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==} - engines: {node: '>=12'} - supports-hyperlinks@3.1.0: resolution: {integrity: sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==} engines: {node: '>=14.18'} @@ -14565,8 +13674,8 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - tailwindcss@4.0.8: - resolution: {integrity: sha512-Me7N5CKR+D2A1xdWA5t5+kjjT7bwnxZOE6/yDI/ixJdJokszsn2n++mdU5yJwrsTpqFX2B9ZNMBJDwcqk9C9lw==} + tailwindcss@4.1.6: + resolution: {integrity: sha512-j0cGLTreM6u4OWzBeLBpycK0WIh8w7kSwcUsQZoGLHZ7xDTdM69lN64AgoIEEwFi0tnhs4wSykUa5YWxAzgFYg==} tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} @@ -14579,10 +13688,6 @@ packages: tar-stream@3.1.7: resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} - tar@7.4.3: resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} engines: {node: '>=18'} @@ -14646,8 +13751,8 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyglobby@0.2.12: - resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} + tinyglobby@0.2.13: + resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} engines: {node: '>=12.0.0'} tinypool@1.0.2: @@ -14757,10 +13862,6 @@ packages: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - type-fest@2.19.0: - resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} - engines: {node: '>=12.20'} - type-fest@4.33.0: resolution: {integrity: sha512-s6zVrxuyKbbAsSAD5ZPTB77q4YIdRctkTbJ2/Dqlinwz+8ooH2gd+YA7VA6Pa93KML9GockVvoxjZ2vHP+mu8g==} engines: {node: '>=16'} @@ -14845,6 +13946,9 @@ packages: ufo@1.5.4: resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + ultrahtml@1.5.3: + resolution: {integrity: sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==} + unc-path-regex@0.1.2: resolution: {integrity: sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==} engines: {node: '>=0.10.0'} @@ -14855,25 +13959,30 @@ packages: unctx@2.4.1: resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==} - undici-types@5.28.4: - resolution: {integrity: sha512-3OeMF5Lyowe8VW0skf5qaIE7Or3yS9LS7fvMUI0gg4YxpIBVg0L8BxCmROw2CcYhSkpR68Epz7CGc8MPj94Uww==} - undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + undici@6.21.2: + resolution: {integrity: sha512-uROZWze0R0itiAKVPsYhFov9LxrPMHLMEQFszeI2gCN6bnIIZ8twzBCJcN2LJrBBLfrP0t1FW0g+JmKVl8Vk1g==} + engines: {node: '>=18.17'} + unenv@1.10.0: resolution: {integrity: sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ==} + unenv@2.0.0-rc.15: + resolution: {integrity: sha512-J/rEIZU8w6FOfLNz/hNKsnY+fFHWnu9MH4yRbSZF3xbbGHovcetXPs7sD+9p8L6CeNC//I9bhRYAOsBt2u7/OA==} + unicode-emoji-modifier-base@1.0.0: resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} engines: {node: '>=4'} - unicorn-magic@0.1.0: - resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} - unimport@3.14.6: - resolution: {integrity: sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g==} + unimport@4.1.3: + resolution: {integrity: sha512-H+IVJ7rAkE3b+oC8rSJ2FsPaVsweeMC8eKZc+C6Mz7+hxDF45AnrY/tVCNRBvzMwWNcJEV67WdAVcal27iMjOw==} + engines: {node: '>=18.12.0'} universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} @@ -14891,6 +14000,10 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} + unplugin-utils@0.2.4: + resolution: {integrity: sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==} + engines: {node: '>=18.12.0'} + unplugin@1.0.1: resolution: {integrity: sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==} @@ -14898,31 +14011,31 @@ packages: resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} engines: {node: '>=14.0.0'} - unplugin@2.1.2: - resolution: {integrity: sha512-Q3LU0e4zxKfRko1wMV2HmP8lB9KWislY7hxXpxd+lGx0PRInE4vhMBVEZwpdVYHvtqzhSrzuIfErsob6bQfCzw==} + unplugin@2.2.2: + resolution: {integrity: sha512-Qp+iiD+qCRnUek+nDoYvtWX7tfnYyXsrOnJ452FRTgOyKmTM7TUJ3l+PLPJOOWPTUyKISKp4isC5JJPSXUjGgw==} engines: {node: '>=18.12.0'} - unstorage@1.14.4: - resolution: {integrity: sha512-1SYeamwuYeQJtJ/USE1x4l17LkmQBzg7deBJ+U9qOBoHo15d1cDxG4jM31zKRgF7pG0kirZy4wVMX6WL6Zoscg==} + unstorage@1.15.0: + resolution: {integrity: sha512-m40eHdGY/gA6xAPqo8eaxqXgBuzQTlAKfmB1iF7oCKXE1HfwHwzDJBywK+qQGn52dta+bPlZluPF7++yR3p/bg==} peerDependencies: '@azure/app-configuration': ^1.8.0 '@azure/cosmos': ^4.2.0 '@azure/data-tables': ^13.3.0 - '@azure/identity': ^4.5.0 + '@azure/identity': ^4.6.0 '@azure/keyvault-secrets': ^4.9.0 '@azure/storage-blob': ^12.26.0 '@capacitor/preferences': ^6.0.3 - '@deno/kv': '>=0.8.4' + '@deno/kv': '>=0.9.0' '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 '@planetscale/database': ^1.19.0 '@upstash/redis': ^1.34.3 - '@vercel/blob': '>=0.27.0' + '@vercel/blob': '>=0.27.1' '@vercel/kv': ^1.0.1 aws4fetch: ^1.0.20 db0: '>=0.2.1' idb-keyval: ^6.2.1 ioredis: ^5.4.2 - uploadthing: ^7.4.1 + uploadthing: ^7.4.4 peerDependenciesMeta: '@azure/app-configuration': optional: true @@ -14965,8 +14078,8 @@ packages: resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==} hasBin: true - untyped@1.5.2: - resolution: {integrity: sha512-eL/8PlhLcMmlMDtNPKhyyz9kEBDS3Uk4yMu/ewlkT2WFbtzScjHWPJLdQLmaGPUKjXzwe9MumOtOgc4Fro96Kg==} + untyped@2.0.0: + resolution: {integrity: sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==} hasBin: true unwasm@0.3.9: @@ -14985,18 +14098,12 @@ packages: uqr@0.1.2: resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} - uri-js-replace@1.0.1: - resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==} - uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - urlpattern-polyfill@8.0.2: - resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==} - use-callback-ref@1.3.3: resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} engines: {node: '>=10'} @@ -15059,14 +14166,6 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - vinxi@0.5.1: - resolution: {integrity: sha512-jvl2hJ0fyWwfDVQdDDHCJiVxqU4k0A6kFAnljS0kIjrGfhdTvKEWIoj0bcJgMyrKhxNMoZZGmHZsstQgjDIL3g==} - hasBin: true - - vinxi@0.5.3: - resolution: {integrity: sha512-4sL2SMrRzdzClapP44oXdGjCE1oq7/DagsbjY5A09EibmoIO4LP8ScRVdh03lfXxKRk7nCWK7n7dqKvm+fp/9w==} - hasBin: true - vite-node@3.0.6: resolution: {integrity: sha512-s51RzrTkXKJrhNbUzQRsarjmAae7VmMPAsRT7lppVpIg6mK3zGthP9Hgz0YQQKuNcF+Ii7DfYk3Fxz40jRmePw==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -15077,7 +14176,7 @@ packages: engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: typescript: '*' - vite: 6.1.4 + vite: 6.3.5 peerDependenciesMeta: vite: optional: true @@ -15086,7 +14185,7 @@ packages: resolution: {integrity: sha512-M1lrPTdi7gilLYRZoLmGYnl4fbPryVYsehPN9JgaxjJKTs8/f7tuAlvCCvOLB5gRDQTTKnptBcB0ACsaw2wNLw==} peerDependencies: typescript: '*' - vite: 6.1.4 + vite: 6.3.5 peerDependenciesMeta: vite: optional: true @@ -15094,14 +14193,14 @@ packages: vite-plugin-externalize-deps@0.9.0: resolution: {integrity: sha512-wg3qb5gCy2d1KpPKyD9wkXMcYJ84yjgziHrStq9/8R7chhUC73mhQz+tVtvhFiICQHsBn1pnkY4IBbPqF9JHNw==} peerDependencies: - vite: 6.1.4 + vite: 6.3.5 vite-plugin-solid@2.11.6: resolution: {integrity: sha512-Sl5CTqJTGyEeOsmdH6BOgalIZlwH3t4/y0RQuFLMGnvWMBvxb4+lq7x3BSiAw6etf0QexfNJW7HSOO/Qf7pigg==} peerDependencies: '@testing-library/jest-dom': ^5.16.6 || ^5.17.0 || ^6.* solid-js: ^1.7.2 - vite: 6.1.4 + vite: 6.3.5 peerDependenciesMeta: '@testing-library/jest-dom': optional: true @@ -15109,13 +14208,13 @@ packages: vite-tsconfig-paths@5.1.4: resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==} peerDependencies: - vite: 6.1.4 + vite: 6.3.5 peerDependenciesMeta: vite: optional: true - vite@6.1.4: - resolution: {integrity: sha512-VzONrF/qqEg/JBwHXBJdVSmBZBhwiPGinyUb0SQLByqQwi6o8UvX5TWLkpvkq3tvN8Cr273ieZDt36CGwWRMvA==} + vite@6.3.5: + resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -15157,7 +14256,7 @@ packages: vitefu@1.0.5: resolution: {integrity: sha512-h4Vflt9gxODPFNGPwp4zAMZRpZR7eslzwH2c5hn5kNZ5rhnKyRJ50U+yGCdc2IRaBs8O4haIgLNGrV5CrpMsCA==} peerDependencies: - vite: 6.1.4 + vite: 6.3.5 peerDependenciesMeta: vite: optional: true @@ -15219,10 +14318,6 @@ packages: wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} - engines: {node: '>= 8'} - web-vitals@4.2.4: resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} @@ -15331,20 +14426,11 @@ packages: engines: {node: '>= 8'} hasBin: true - which@4.0.0: - resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} - engines: {node: ^16.13.0 || >=18.0.0} - hasBin: true - why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} hasBin: true - widest-line@4.0.1: - resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} - engines: {node: '>=12'} - wildcard@2.0.1: resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} @@ -15383,6 +14469,10 @@ packages: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} + xmlbuilder2@3.1.1: + resolution: {integrity: sha512-WCSfbfZnQDdLQLiMdGUQpMxxckeQ4oZNMNhLVkcekTu7xhD4tuUDyAPoY8CwXvBYE6LwBHd6QW2WZXlOWr1vCw==} + engines: {node: '>=12.0'} + xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} @@ -15400,9 +14490,6 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} - yaml-ast-parser@0.0.43: - resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} - yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} @@ -15436,6 +14523,14 @@ packages: resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} engines: {node: '>=18'} + youch-core@0.3.2: + resolution: {integrity: sha512-fusrlIMLeRvTFYLUjJ9KzlGC3N+6MOPJ68HNj/yJv2nz7zq8t4HEviLms2gkdRPUS7F5rZ5n+pYx9r88m6IE1g==} + engines: {node: '>=18'} + + youch@4.1.0-beta.7: + resolution: {integrity: sha512-HUn0M24AUTMvjdkoMtH8fJz2FEd+k1xvtR9EoTrDUoVUi6o7xl5X+pST/vjk4T3GEQo2mJ9FlAvhWBm8dIdD4g==} + engines: {node: '>=18'} + zip-stream@6.0.1: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} @@ -15464,7 +14559,7 @@ snapshots: commander: 10.0.1 marked: 9.1.6 marked-terminal: 7.3.0(marked@9.1.6) - semver: 7.7.0 + semver: 7.7.1 '@arethetypeswrong/core@0.17.3': dependencies: @@ -15472,7 +14567,7 @@ snapshots: cjs-module-lexer: 1.4.3 fflate: 0.8.2 lru-cache: 10.4.3 - semver: 7.7.0 + semver: 7.7.1 typescript: 5.6.1-rc validate-npm-package-name: 5.0.1 @@ -15512,7 +14607,7 @@ snapshots: '@babel/types': 7.26.8 '@types/gensync': 1.0.4 convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -15692,8 +14787,6 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 - '@babel/standalone@7.26.7': {} - '@babel/template@7.26.8': dependencies: '@babel/code-frame': 7.26.2 @@ -15707,7 +14800,7 @@ snapshots: '@babel/parser': 7.26.8 '@babel/template': 7.26.8 '@babel/types': 7.26.8 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -15755,7 +14848,7 @@ snapshots: dequal: 2.0.3 glob-to-regexp: 0.4.1 js-cookie: 3.0.5 - std-env: 3.8.0 + std-env: 3.8.1 swr: 2.3.0(react@19.0.0) optionalDependencies: react: 19.0.0 @@ -15777,7 +14870,7 @@ snapshots: dependencies: csstype: 3.1.3 - '@cloudflare/kv-asset-handler@0.3.4': + '@cloudflare/kv-asset-handler@0.4.0': dependencies: mime: 3.0.0 @@ -15820,13 +14913,6 @@ snapshots: '@csstools/css-tokenizer@3.0.3': {} - '@deno/shim-deno-test@0.5.0': {} - - '@deno/shim-deno@0.19.2': - dependencies: - '@deno/shim-deno-test': 0.5.0 - which: 4.0.0 - '@discoveryjs/json-ext@0.5.7': {} '@emnapi/core@1.3.1': @@ -15925,22 +15011,13 @@ snapshots: '@emotion/weak-memoize@0.4.0': {} - '@esbuild/aix-ppc64@0.20.2': - optional: true - '@esbuild/aix-ppc64@0.23.0': optional: true '@esbuild/aix-ppc64@0.23.1': optional: true - '@esbuild/aix-ppc64@0.24.2': - optional: true - - '@esbuild/aix-ppc64@0.25.0': - optional: true - - '@esbuild/android-arm64@0.20.2': + '@esbuild/aix-ppc64@0.25.2': optional: true '@esbuild/android-arm64@0.23.0': @@ -15949,13 +15026,7 @@ snapshots: '@esbuild/android-arm64@0.23.1': optional: true - '@esbuild/android-arm64@0.24.2': - optional: true - - '@esbuild/android-arm64@0.25.0': - optional: true - - '@esbuild/android-arm@0.20.2': + '@esbuild/android-arm64@0.25.2': optional: true '@esbuild/android-arm@0.23.0': @@ -15964,13 +15035,7 @@ snapshots: '@esbuild/android-arm@0.23.1': optional: true - '@esbuild/android-arm@0.24.2': - optional: true - - '@esbuild/android-arm@0.25.0': - optional: true - - '@esbuild/android-x64@0.20.2': + '@esbuild/android-arm@0.25.2': optional: true '@esbuild/android-x64@0.23.0': @@ -15979,13 +15044,7 @@ snapshots: '@esbuild/android-x64@0.23.1': optional: true - '@esbuild/android-x64@0.24.2': - optional: true - - '@esbuild/android-x64@0.25.0': - optional: true - - '@esbuild/darwin-arm64@0.20.2': + '@esbuild/android-x64@0.25.2': optional: true '@esbuild/darwin-arm64@0.23.0': @@ -15994,13 +15053,7 @@ snapshots: '@esbuild/darwin-arm64@0.23.1': optional: true - '@esbuild/darwin-arm64@0.24.2': - optional: true - - '@esbuild/darwin-arm64@0.25.0': - optional: true - - '@esbuild/darwin-x64@0.20.2': + '@esbuild/darwin-arm64@0.25.2': optional: true '@esbuild/darwin-x64@0.23.0': @@ -16009,13 +15062,7 @@ snapshots: '@esbuild/darwin-x64@0.23.1': optional: true - '@esbuild/darwin-x64@0.24.2': - optional: true - - '@esbuild/darwin-x64@0.25.0': - optional: true - - '@esbuild/freebsd-arm64@0.20.2': + '@esbuild/darwin-x64@0.25.2': optional: true '@esbuild/freebsd-arm64@0.23.0': @@ -16024,13 +15071,7 @@ snapshots: '@esbuild/freebsd-arm64@0.23.1': optional: true - '@esbuild/freebsd-arm64@0.24.2': - optional: true - - '@esbuild/freebsd-arm64@0.25.0': - optional: true - - '@esbuild/freebsd-x64@0.20.2': + '@esbuild/freebsd-arm64@0.25.2': optional: true '@esbuild/freebsd-x64@0.23.0': @@ -16039,13 +15080,7 @@ snapshots: '@esbuild/freebsd-x64@0.23.1': optional: true - '@esbuild/freebsd-x64@0.24.2': - optional: true - - '@esbuild/freebsd-x64@0.25.0': - optional: true - - '@esbuild/linux-arm64@0.20.2': + '@esbuild/freebsd-x64@0.25.2': optional: true '@esbuild/linux-arm64@0.23.0': @@ -16054,13 +15089,7 @@ snapshots: '@esbuild/linux-arm64@0.23.1': optional: true - '@esbuild/linux-arm64@0.24.2': - optional: true - - '@esbuild/linux-arm64@0.25.0': - optional: true - - '@esbuild/linux-arm@0.20.2': + '@esbuild/linux-arm64@0.25.2': optional: true '@esbuild/linux-arm@0.23.0': @@ -16069,13 +15098,7 @@ snapshots: '@esbuild/linux-arm@0.23.1': optional: true - '@esbuild/linux-arm@0.24.2': - optional: true - - '@esbuild/linux-arm@0.25.0': - optional: true - - '@esbuild/linux-ia32@0.20.2': + '@esbuild/linux-arm@0.25.2': optional: true '@esbuild/linux-ia32@0.23.0': @@ -16084,13 +15107,7 @@ snapshots: '@esbuild/linux-ia32@0.23.1': optional: true - '@esbuild/linux-ia32@0.24.2': - optional: true - - '@esbuild/linux-ia32@0.25.0': - optional: true - - '@esbuild/linux-loong64@0.20.2': + '@esbuild/linux-ia32@0.25.2': optional: true '@esbuild/linux-loong64@0.23.0': @@ -16099,13 +15116,7 @@ snapshots: '@esbuild/linux-loong64@0.23.1': optional: true - '@esbuild/linux-loong64@0.24.2': - optional: true - - '@esbuild/linux-loong64@0.25.0': - optional: true - - '@esbuild/linux-mips64el@0.20.2': + '@esbuild/linux-loong64@0.25.2': optional: true '@esbuild/linux-mips64el@0.23.0': @@ -16114,13 +15125,7 @@ snapshots: '@esbuild/linux-mips64el@0.23.1': optional: true - '@esbuild/linux-mips64el@0.24.2': - optional: true - - '@esbuild/linux-mips64el@0.25.0': - optional: true - - '@esbuild/linux-ppc64@0.20.2': + '@esbuild/linux-mips64el@0.25.2': optional: true '@esbuild/linux-ppc64@0.23.0': @@ -16129,13 +15134,7 @@ snapshots: '@esbuild/linux-ppc64@0.23.1': optional: true - '@esbuild/linux-ppc64@0.24.2': - optional: true - - '@esbuild/linux-ppc64@0.25.0': - optional: true - - '@esbuild/linux-riscv64@0.20.2': + '@esbuild/linux-ppc64@0.25.2': optional: true '@esbuild/linux-riscv64@0.23.0': @@ -16144,13 +15143,7 @@ snapshots: '@esbuild/linux-riscv64@0.23.1': optional: true - '@esbuild/linux-riscv64@0.24.2': - optional: true - - '@esbuild/linux-riscv64@0.25.0': - optional: true - - '@esbuild/linux-s390x@0.20.2': + '@esbuild/linux-riscv64@0.25.2': optional: true '@esbuild/linux-s390x@0.23.0': @@ -16159,13 +15152,7 @@ snapshots: '@esbuild/linux-s390x@0.23.1': optional: true - '@esbuild/linux-s390x@0.24.2': - optional: true - - '@esbuild/linux-s390x@0.25.0': - optional: true - - '@esbuild/linux-x64@0.20.2': + '@esbuild/linux-s390x@0.25.2': optional: true '@esbuild/linux-x64@0.23.0': @@ -16174,19 +15161,10 @@ snapshots: '@esbuild/linux-x64@0.23.1': optional: true - '@esbuild/linux-x64@0.24.2': - optional: true - - '@esbuild/linux-x64@0.25.0': - optional: true - - '@esbuild/netbsd-arm64@0.24.2': + '@esbuild/linux-x64@0.25.2': optional: true - '@esbuild/netbsd-arm64@0.25.0': - optional: true - - '@esbuild/netbsd-x64@0.20.2': + '@esbuild/netbsd-arm64@0.25.2': optional: true '@esbuild/netbsd-x64@0.23.0': @@ -16195,70 +15173,43 @@ snapshots: '@esbuild/netbsd-x64@0.23.1': optional: true - '@esbuild/netbsd-x64@0.24.2': - optional: true - - '@esbuild/netbsd-x64@0.25.0': - optional: true - - '@esbuild/openbsd-arm64@0.23.0': - optional: true - - '@esbuild/openbsd-arm64@0.23.1': - optional: true - - '@esbuild/openbsd-arm64@0.24.2': - optional: true - - '@esbuild/openbsd-arm64@0.25.0': - optional: true - - '@esbuild/openbsd-x64@0.20.2': - optional: true - - '@esbuild/openbsd-x64@0.23.0': - optional: true - - '@esbuild/openbsd-x64@0.23.1': - optional: true - - '@esbuild/openbsd-x64@0.24.2': + '@esbuild/netbsd-x64@0.25.2': optional: true - '@esbuild/openbsd-x64@0.25.0': + '@esbuild/openbsd-arm64@0.23.0': optional: true - '@esbuild/sunos-x64@0.20.2': + '@esbuild/openbsd-arm64@0.23.1': optional: true - '@esbuild/sunos-x64@0.23.0': + '@esbuild/openbsd-arm64@0.25.2': optional: true - '@esbuild/sunos-x64@0.23.1': + '@esbuild/openbsd-x64@0.23.0': optional: true - '@esbuild/sunos-x64@0.24.2': + '@esbuild/openbsd-x64@0.23.1': optional: true - '@esbuild/sunos-x64@0.25.0': + '@esbuild/openbsd-x64@0.25.2': optional: true - '@esbuild/win32-arm64@0.20.2': + '@esbuild/sunos-x64@0.23.0': optional: true - '@esbuild/win32-arm64@0.23.0': + '@esbuild/sunos-x64@0.23.1': optional: true - '@esbuild/win32-arm64@0.23.1': + '@esbuild/sunos-x64@0.25.2': optional: true - '@esbuild/win32-arm64@0.24.2': + '@esbuild/win32-arm64@0.23.0': optional: true - '@esbuild/win32-arm64@0.25.0': + '@esbuild/win32-arm64@0.23.1': optional: true - '@esbuild/win32-ia32@0.20.2': + '@esbuild/win32-arm64@0.25.2': optional: true '@esbuild/win32-ia32@0.23.0': @@ -16267,13 +15218,7 @@ snapshots: '@esbuild/win32-ia32@0.23.1': optional: true - '@esbuild/win32-ia32@0.24.2': - optional: true - - '@esbuild/win32-ia32@0.25.0': - optional: true - - '@esbuild/win32-x64@0.20.2': + '@esbuild/win32-ia32@0.25.2': optional: true '@esbuild/win32-x64@0.23.0': @@ -16282,10 +15227,7 @@ snapshots: '@esbuild/win32-x64@0.23.1': optional: true - '@esbuild/win32-x64@0.24.2': - optional: true - - '@esbuild/win32-x64@0.25.0': + '@esbuild/win32-x64@0.25.2': optional: true '@eslint-community/eslint-utils@4.4.1(eslint@9.22.0(jiti@2.4.2))': @@ -16391,7 +15333,7 @@ snapshots: '@eslint/config-array@0.19.2': dependencies: '@eslint/object-schema': 2.1.6 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -16405,7 +15347,7 @@ snapshots: '@eslint/eslintrc@3.3.0': dependencies: ajv: 6.12.6 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -16877,7 +15819,7 @@ snapshots: '@kwsites/file-exists@1.1.1': dependencies: - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -16887,12 +15829,12 @@ snapshots: '@mapbox/node-pre-gyp@2.0.0': dependencies: - consola: 3.4.0 - detect-libc: 2.0.3 - https-proxy-agent: 7.0.6(supports-color@9.4.0) + consola: 3.4.2 + detect-libc: 2.0.4 + https-proxy-agent: 7.0.6 node-fetch: 2.7.0 nopt: 8.1.0 - semver: 7.7.0 + semver: 7.7.1 tar: 7.4.3 transitivePeerDependencies: - encoding @@ -17072,16 +16014,11 @@ snapshots: '@emnapi/runtime': 1.3.1 '@tybys/wasm-util': 0.9.0 - '@netlify/functions@2.8.2': + '@netlify/functions@3.0.4': dependencies: - '@netlify/serverless-functions-api': 1.26.1 + '@netlify/serverless-functions-api': 1.36.0 - '@netlify/node-cookies@0.1.0': {} - - '@netlify/serverless-functions-api@1.26.1': - dependencies: - '@netlify/node-cookies': 0.1.0 - urlpattern-polyfill: 8.0.2 + '@netlify/serverless-functions-api@1.36.0': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -17127,6 +16064,23 @@ snapshots: '@nx/nx-win32-x64-msvc@20.8.1': optional: true + '@oozcitak/dom@1.15.10': + dependencies: + '@oozcitak/infra': 1.0.8 + '@oozcitak/url': 1.0.4 + '@oozcitak/util': 8.3.8 + + '@oozcitak/infra@1.0.8': + dependencies: + '@oozcitak/util': 8.3.8 + + '@oozcitak/url@1.0.4': + dependencies: + '@oozcitak/infra': 1.0.8 + '@oozcitak/util': 8.3.8 + + '@oozcitak/util@8.3.8': {} + '@open-draft/deferred-promise@2.2.0': {} '@open-draft/logger@0.3.0': @@ -17166,11 +16120,6 @@ snapshots: '@parcel/watcher-linux-x64-musl@2.5.1': optional: true - '@parcel/watcher-wasm@2.3.0': - dependencies: - is-glob: 4.0.3 - micromatch: 4.0.8 - '@parcel/watcher-wasm@2.5.1': dependencies: is-glob: 4.0.3 @@ -17235,6 +16184,18 @@ snapshots: '@popperjs/core@2.11.8': {} + '@poppinss/colors@4.1.4': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.6.3': + dependencies: + '@poppinss/colors': 4.1.4 + '@sindresorhus/is': 7.0.1 + supports-color: 10.0.0 + + '@poppinss/exception@1.2.1': {} + '@prisma/client@5.22.0(prisma@5.22.0)': optionalDependencies: prisma: 5.22.0 @@ -17289,8 +16250,6 @@ snapshots: '@radix-ui/number@1.1.1': {} - '@radix-ui/primitive@1.1.1': {} - '@radix-ui/primitive@1.1.2': {} '@radix-ui/react-accessible-icon@1.1.3(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': @@ -17407,12 +16366,6 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-compose-refs@1.1.1(@types/react@19.0.8)(react@19.0.0)': - dependencies: - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.0.8)(react@19.0.0)': dependencies: react: 19.0.0 @@ -17433,40 +16386,12 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-context@1.1.1(@types/react@19.0.8)(react@19.0.0)': - dependencies: - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-context@1.1.2(@types/react@19.0.8)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: '@types/react': 19.0.8 - '@radix-ui/react-dialog@1.1.6(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-id': 1.1.0(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-slot': 1.1.2(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.8)(react@19.0.0) - aria-hidden: 1.2.4 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-remove-scroll: 2.6.3(@types/react@19.0.8)(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.8 - '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-dialog@1.1.7(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/primitive': 1.1.2 @@ -17495,19 +16420,6 @@ snapshots: optionalDependencies: '@types/react': 19.0.8 - '@radix-ui/react-dismissable-layer@1.1.5(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.8 - '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-dismissable-layer@1.1.6(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/primitive': 1.1.2 @@ -17536,29 +16448,12 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-focus-guards@1.1.1(@types/react@19.0.8)(react@19.0.0)': - dependencies: - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-focus-guards@1.1.2(@types/react@19.0.8)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: '@types/react': 19.0.8 - '@radix-ui/react-focus-scope@1.1.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.8 - '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-focus-scope@1.1.3(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.8)(react@19.0.0) @@ -17601,13 +16496,6 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-id@1.1.0(@types/react@19.0.8)(react@19.0.0)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-id@1.1.1(@types/react@19.0.8)(react@19.0.0)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.8)(react@19.0.0) @@ -17731,16 +16619,6 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-portal@1.1.4(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.8 - '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-portal@1.1.5(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -17751,16 +16629,6 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-presence@1.1.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.8 - '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-presence@1.1.3(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.8)(react@19.0.0) @@ -17771,15 +16639,6 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-primitive@2.0.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@radix-ui/react-slot': 1.1.2(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.8 - '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-primitive@2.0.3(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/react-slot': 1.2.0(@types/react@19.0.8)(react@19.0.0) @@ -17908,13 +16767,6 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-slot@1.1.2(@types/react@19.0.8)(react@19.0.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-slot@1.2.0(@types/react@19.0.8)(react@19.0.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.8)(react@19.0.0) @@ -18034,25 +16886,12 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.0.8)(react@19.0.0)': - dependencies: - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.0.8)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: '@types/react': 19.0.8 - '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.0.8)(react@19.0.0)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-use-controllable-state@1.1.1(@types/react@19.0.8)(react@19.0.0)': dependencies: '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.8)(react@19.0.0) @@ -18060,13 +16899,6 @@ snapshots: optionalDependencies: '@types/react': 19.0.8 - '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.0.8)(react@19.0.0)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.0.8)(react@19.0.0)': dependencies: '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.8)(react@19.0.0) @@ -18074,12 +16906,6 @@ snapshots: optionalDependencies: '@types/react': 19.0.8 - '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.0.8)(react@19.0.0)': - dependencies: - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.0.8)(react@19.0.0)': dependencies: react: 19.0.0 @@ -18129,161 +16955,127 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@redocly/ajv@8.11.2': - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js-replace: 1.0.1 - - '@redocly/config@0.20.3': {} - - '@redocly/openapi-core@1.28.0(supports-color@9.4.0)': - dependencies: - '@redocly/ajv': 8.11.2 - '@redocly/config': 0.20.3 - colorette: 1.4.0 - https-proxy-agent: 7.0.6(supports-color@9.4.0) - js-levenshtein: 1.1.6 - js-yaml: 4.1.0 - minimatch: 5.1.6 - pluralize: 8.0.0 - yaml-ast-parser: 0.0.43 - transitivePeerDependencies: - - supports-color - - '@rollup/plugin-alias@5.1.1(rollup@4.39.0)': - optionalDependencies: - rollup: 4.39.0 - - '@rollup/plugin-babel@6.0.4(@babel/core@7.26.8)(@types/babel__core@7.20.5)(rollup@4.39.0)': - dependencies: - '@babel/core': 7.26.8 - '@babel/helper-module-imports': 7.25.9 - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) + '@rollup/plugin-alias@5.1.1(rollup@4.38.0)': optionalDependencies: - '@types/babel__core': 7.20.5 - rollup: 4.39.0 - transitivePeerDependencies: - - supports-color + rollup: 4.38.0 - '@rollup/plugin-commonjs@28.0.2(rollup@4.39.0)': + '@rollup/plugin-commonjs@28.0.3(rollup@4.38.0)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) + '@rollup/pluginutils': 5.1.4(rollup@4.38.0) commondir: 1.0.1 estree-walker: 2.0.2 - fdir: 6.4.3(picomatch@4.0.2) + fdir: 6.4.4(picomatch@4.0.2) is-reference: 1.2.1 magic-string: 0.30.17 picomatch: 4.0.2 optionalDependencies: - rollup: 4.39.0 + rollup: 4.38.0 - '@rollup/plugin-inject@5.0.5(rollup@4.39.0)': + '@rollup/plugin-inject@5.0.5(rollup@4.38.0)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) + '@rollup/pluginutils': 5.1.4(rollup@4.38.0) estree-walker: 2.0.2 magic-string: 0.30.17 optionalDependencies: - rollup: 4.39.0 + rollup: 4.38.0 - '@rollup/plugin-json@6.1.0(rollup@4.39.0)': + '@rollup/plugin-json@6.1.0(rollup@4.38.0)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) + '@rollup/pluginutils': 5.1.4(rollup@4.38.0) optionalDependencies: - rollup: 4.39.0 + rollup: 4.38.0 - '@rollup/plugin-node-resolve@15.3.1(rollup@4.39.0)': + '@rollup/plugin-node-resolve@16.0.1(rollup@4.38.0)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) + '@rollup/pluginutils': 5.1.4(rollup@4.38.0) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.10 optionalDependencies: - rollup: 4.39.0 + rollup: 4.38.0 - '@rollup/plugin-replace@6.0.2(rollup@4.39.0)': + '@rollup/plugin-replace@6.0.2(rollup@4.38.0)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) + '@rollup/pluginutils': 5.1.4(rollup@4.38.0) magic-string: 0.30.17 optionalDependencies: - rollup: 4.39.0 + rollup: 4.38.0 - '@rollup/plugin-terser@0.4.4(rollup@4.39.0)': + '@rollup/plugin-terser@0.4.4(rollup@4.38.0)': dependencies: serialize-javascript: 6.0.2 smob: 1.5.0 terser: 5.37.0 optionalDependencies: - rollup: 4.39.0 + rollup: 4.38.0 - '@rollup/pluginutils@5.1.4(rollup@4.39.0)': + '@rollup/pluginutils@5.1.4(rollup@4.38.0)': dependencies: '@types/estree': 1.0.7 estree-walker: 2.0.2 picomatch: 4.0.2 optionalDependencies: - rollup: 4.39.0 + rollup: 4.38.0 - '@rollup/rollup-android-arm-eabi@4.39.0': + '@rollup/rollup-android-arm-eabi@4.38.0': optional: true - '@rollup/rollup-android-arm64@4.39.0': + '@rollup/rollup-android-arm64@4.38.0': optional: true - '@rollup/rollup-darwin-arm64@4.39.0': + '@rollup/rollup-darwin-arm64@4.38.0': optional: true - '@rollup/rollup-darwin-x64@4.39.0': + '@rollup/rollup-darwin-x64@4.38.0': optional: true - '@rollup/rollup-freebsd-arm64@4.39.0': + '@rollup/rollup-freebsd-arm64@4.38.0': optional: true - '@rollup/rollup-freebsd-x64@4.39.0': + '@rollup/rollup-freebsd-x64@4.38.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.39.0': + '@rollup/rollup-linux-arm-gnueabihf@4.38.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.39.0': + '@rollup/rollup-linux-arm-musleabihf@4.38.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.39.0': + '@rollup/rollup-linux-arm64-gnu@4.38.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.39.0': + '@rollup/rollup-linux-arm64-musl@4.38.0': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.39.0': + '@rollup/rollup-linux-loongarch64-gnu@4.38.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.38.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.39.0': + '@rollup/rollup-linux-riscv64-gnu@4.38.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.39.0': + '@rollup/rollup-linux-riscv64-musl@4.38.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.39.0': + '@rollup/rollup-linux-s390x-gnu@4.38.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.39.0': + '@rollup/rollup-linux-x64-gnu@4.38.0': optional: true - '@rollup/rollup-linux-x64-musl@4.39.0': + '@rollup/rollup-linux-x64-musl@4.38.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.39.0': + '@rollup/rollup-win32-arm64-msvc@4.38.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.39.0': + '@rollup/rollup-win32-ia32-msvc@4.38.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.39.0': + '@rollup/rollup-win32-x64-msvc@4.38.0': optional: true '@rsbuild/core@1.2.4': @@ -18582,6 +17374,8 @@ snapshots: '@sindresorhus/is@4.6.0': {} + '@sindresorhus/is@7.0.1': {} + '@sindresorhus/merge-streams@2.3.0': {} '@solid-devtools/debugger@0.26.0(solid-js@1.9.5)': @@ -18708,6 +17502,8 @@ snapshots: '@testing-library/dom': 10.4.0 solid-js: 1.9.5 + '@speed-highlight/core@1.2.7': {} + '@stylistic/eslint-plugin-js@2.13.0(eslint@9.22.0(jiti@2.4.2))': dependencies: eslint: 9.22.0(jiti@2.4.2) @@ -18819,74 +17615,84 @@ snapshots: dependencies: '@swc/counter': 0.1.3 - '@tailwindcss/node@4.0.8': + '@tailwindcss/node@4.1.6': dependencies: + '@ampproject/remapping': 2.3.0 enhanced-resolve: 5.18.1 jiti: 2.4.2 - tailwindcss: 4.0.8 + lightningcss: 1.29.2 + magic-string: 0.30.17 + source-map-js: 1.2.1 + tailwindcss: 4.1.6 + + '@tailwindcss/oxide-android-arm64@4.1.6': + optional: true - '@tailwindcss/oxide-android-arm64@4.0.8': + '@tailwindcss/oxide-darwin-arm64@4.1.6': optional: true - '@tailwindcss/oxide-darwin-arm64@4.0.8': + '@tailwindcss/oxide-darwin-x64@4.1.6': optional: true - '@tailwindcss/oxide-darwin-x64@4.0.8': + '@tailwindcss/oxide-freebsd-x64@4.1.6': optional: true - '@tailwindcss/oxide-freebsd-x64@4.0.8': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.6': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.0.8': + '@tailwindcss/oxide-linux-arm64-gnu@4.1.6': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.0.8': + '@tailwindcss/oxide-linux-arm64-musl@4.1.6': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.0.8': + '@tailwindcss/oxide-linux-x64-gnu@4.1.6': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.0.8': + '@tailwindcss/oxide-linux-x64-musl@4.1.6': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.0.8': + '@tailwindcss/oxide-wasm32-wasi@4.1.6': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.0.8': + '@tailwindcss/oxide-win32-arm64-msvc@4.1.6': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.0.8': + '@tailwindcss/oxide-win32-x64-msvc@4.1.6': optional: true - '@tailwindcss/oxide@4.0.8': + '@tailwindcss/oxide@4.1.6': + dependencies: + detect-libc: 2.0.4 + tar: 7.4.3 optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.0.8 - '@tailwindcss/oxide-darwin-arm64': 4.0.8 - '@tailwindcss/oxide-darwin-x64': 4.0.8 - '@tailwindcss/oxide-freebsd-x64': 4.0.8 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.0.8 - '@tailwindcss/oxide-linux-arm64-gnu': 4.0.8 - '@tailwindcss/oxide-linux-arm64-musl': 4.0.8 - '@tailwindcss/oxide-linux-x64-gnu': 4.0.8 - '@tailwindcss/oxide-linux-x64-musl': 4.0.8 - '@tailwindcss/oxide-win32-arm64-msvc': 4.0.8 - '@tailwindcss/oxide-win32-x64-msvc': 4.0.8 - - '@tailwindcss/vite@4.0.8(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))': - dependencies: - '@tailwindcss/node': 4.0.8 - '@tailwindcss/oxide': 4.0.8 - lightningcss: 1.29.1 - tailwindcss: 4.0.8 - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - - '@tanstack/config@0.16.1(@types/node@22.13.4)(esbuild@0.25.0)(eslint@9.22.0(jiti@2.4.2))(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))': + '@tailwindcss/oxide-android-arm64': 4.1.6 + '@tailwindcss/oxide-darwin-arm64': 4.1.6 + '@tailwindcss/oxide-darwin-x64': 4.1.6 + '@tailwindcss/oxide-freebsd-x64': 4.1.6 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.6 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.6 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.6 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.6 + '@tailwindcss/oxide-linux-x64-musl': 4.1.6 + '@tailwindcss/oxide-wasm32-wasi': 4.1.6 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.6 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.6 + + '@tailwindcss/vite@4.1.6(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))': + dependencies: + '@tailwindcss/node': 4.1.6 + '@tailwindcss/oxide': 4.1.6 + tailwindcss: 4.1.6 + vite: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + + '@tanstack/config@0.16.1(@types/node@22.13.4)(esbuild@0.25.2)(eslint@9.22.0(jiti@2.4.2))(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))': dependencies: '@commitlint/parse': 19.5.0 '@eslint/js': 9.22.0 '@stylistic/eslint-plugin-js': 2.13.0(eslint@9.22.0(jiti@2.4.2)) commander: 13.1.0 - esbuild-register: 3.6.0(esbuild@0.25.0) + esbuild-register: 3.6.0(esbuild@0.25.2) eslint-plugin-import-x: 4.6.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) eslint-plugin-n: 17.15.1(eslint@9.22.0(jiti@2.4.2)) globals: 15.14.0 @@ -18894,17 +17700,17 @@ snapshots: jsonfile: 6.1.0 liftoff: 5.0.0 minimist: 1.2.8 - rollup-plugin-preserve-directives: 0.4.0(rollup@4.39.0) - semver: 7.7.0 + rollup-plugin-preserve-directives: 0.4.0(rollup@4.38.0) + semver: 7.7.1 simple-git: 3.27.0 typedoc: 0.27.6(typescript@5.8.2) typedoc-plugin-frontmatter: 1.1.2(typedoc-plugin-markdown@4.4.1(typedoc@0.27.6(typescript@5.8.2))) typedoc-plugin-markdown: 4.4.1(typedoc@0.27.6(typescript@5.8.2)) typescript-eslint: 8.22.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) v8flags: 4.0.1 - vite-plugin-dts: 4.0.3(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - vite-plugin-externalize-deps: 0.9.0(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - vite-tsconfig-paths: 5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + vite-plugin-dts: 4.0.3(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + vite-plugin-externalize-deps: 0.9.0(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + vite-tsconfig-paths: 5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) vue-eslint-parser: 9.4.3(eslint@9.22.0(jiti@2.4.2)) transitivePeerDependencies: - '@types/node' @@ -18917,11 +17723,11 @@ snapshots: '@tanstack/query-core@5.66.0': {} - '@tanstack/query-core@5.71.5': {} + '@tanstack/query-core@5.72.2': {} '@tanstack/query-devtools@5.67.2': {} - '@tanstack/query-devtools@5.71.5': {} + '@tanstack/query-devtools@5.72.2': {} '@tanstack/react-query-devtools@5.67.2(@tanstack/react-query@5.66.0(react@19.0.0))(react@19.0.0)': dependencies: @@ -18947,15 +17753,15 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - '@tanstack/solid-query-devtools@5.71.9(@tanstack/solid-query@5.71.9(solid-js@1.9.5))(solid-js@1.9.5)': + '@tanstack/solid-query-devtools@5.72.2(@tanstack/solid-query@5.72.2(solid-js@1.9.5))(solid-js@1.9.5)': dependencies: - '@tanstack/query-devtools': 5.71.5 - '@tanstack/solid-query': 5.71.9(solid-js@1.9.5) + '@tanstack/query-devtools': 5.72.2 + '@tanstack/solid-query': 5.72.2(solid-js@1.9.5) solid-js: 1.9.5 - '@tanstack/solid-query@5.71.9(solid-js@1.9.5)': + '@tanstack/solid-query@5.72.2(solid-js@1.9.5)': dependencies: - '@tanstack/query-core': 5.71.5 + '@tanstack/query-core': 5.72.2 solid-js: 1.9.5 '@tanstack/solid-store@0.7.0(solid-js@1.9.5)': @@ -19069,8 +17875,6 @@ snapshots: dependencies: '@types/node': 22.13.4 - '@types/braces@3.0.5': {} - '@types/connect-history-api-fallback@1.5.4': dependencies: '@types/express-serve-static-core': 5.0.6 @@ -19173,10 +17977,6 @@ snapshots: '@types/koa-compose': 3.2.8 '@types/node': 22.13.4 - '@types/micromatch@4.0.9': - dependencies: - '@types/braces': 3.0.5 - '@types/mime@1.3.5': {} '@types/node-forge@1.3.11': @@ -19273,7 +18073,7 @@ snapshots: '@typescript-eslint/types': 8.22.0 '@typescript-eslint/typescript-estree': 8.22.0(typescript@5.8.2) '@typescript-eslint/visitor-keys': 8.22.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 eslint: 9.22.0(jiti@2.4.2) typescript: 5.8.2 transitivePeerDependencies: @@ -19287,7 +18087,7 @@ snapshots: eslint: 9.22.0(jiti@2.4.2) json-stable-stringify-without-jsonify: 1.0.1 lodash.merge: 4.6.2 - semver: 7.7.0 + semver: 7.7.1 transitivePeerDependencies: - supports-color - typescript @@ -19306,7 +18106,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 8.22.0(typescript@5.8.2) '@typescript-eslint/utils': 8.22.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 eslint: 9.22.0(jiti@2.4.2) ts-api-utils: 2.0.1(typescript@5.8.2) typescript: 5.8.2 @@ -19317,7 +18117,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.8.2) '@typescript-eslint/utils': 8.23.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 eslint: 9.22.0(jiti@2.4.2) ts-api-utils: 2.0.1(typescript@5.8.2) typescript: 5.8.2 @@ -19332,11 +18132,11 @@ snapshots: dependencies: '@typescript-eslint/types': 8.22.0 '@typescript-eslint/visitor-keys': 8.22.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.0 + semver: 7.7.1 ts-api-utils: 2.0.1(typescript@5.8.2) typescript: 5.8.2 transitivePeerDependencies: @@ -19346,11 +18146,11 @@ snapshots: dependencies: '@typescript-eslint/types': 8.23.0 '@typescript-eslint/visitor-keys': 8.23.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.0 + semver: 7.7.1 ts-api-utils: 2.0.1(typescript@5.8.2) typescript: 5.8.2 transitivePeerDependencies: @@ -19388,16 +18188,16 @@ snapshots: '@typescript-eslint/types': 8.23.0 eslint-visitor-keys: 4.2.0 - '@vercel/nft@0.27.10(rollup@4.39.0)': + '@vercel/nft@0.29.2(rollup@4.38.0)': dependencies: '@mapbox/node-pre-gyp': 2.0.0 - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) - acorn: 8.14.0 - acorn-import-attributes: 1.9.5(acorn@8.14.0) + '@rollup/pluginutils': 5.1.4(rollup@4.38.0) + acorn: 8.14.1 + acorn-import-attributes: 1.9.5(acorn@8.14.1) async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 - glob: 7.2.3 + glob: 10.4.5 graceful-fs: 4.2.11 node-gyp-build: 4.8.4 picomatch: 4.0.2 @@ -19407,48 +18207,28 @@ snapshots: - rollup - supports-color - '@vinxi/listhen@1.5.6': - dependencies: - '@parcel/watcher': 2.5.1 - '@parcel/watcher-wasm': 2.3.0 - citty: 0.1.6 - clipboardy: 4.0.0 - consola: 3.4.0 - defu: 6.1.4 - get-port-please: 3.1.2 - h3: 1.13.0 - http-shutdown: 1.2.2 - jiti: 1.21.7 - mlly: 1.7.4 - node-forge: 1.3.1 - pathe: 1.1.2 - std-env: 3.8.0 - ufo: 1.5.4 - untun: 0.1.3 - uqr: 0.1.2 - - '@vitejs/plugin-react@4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))': + '@vitejs/plugin-react@4.3.4(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))': dependencies: '@babel/core': 7.26.8 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.8) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.8) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) transitivePeerDependencies: - supports-color - '@vitest/browser@3.0.6(@types/node@22.13.4)(playwright@1.52.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))(vitest@3.0.6)': + '@vitest/browser@3.0.6(@types/node@22.13.4)(playwright@1.52.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))(vitest@3.0.6)': dependencies: '@testing-library/dom': 10.4.0 '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0) - '@vitest/mocker': 3.0.6(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + '@vitest/mocker': 3.0.6(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) '@vitest/utils': 3.0.6 magic-string: 0.30.17 msw: 2.7.0(@types/node@22.13.4)(typescript@5.8.2) sirv: 3.0.1 tinyrainbow: 2.0.0 - vitest: 3.0.6(@types/node@22.13.4)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@25.0.1)(lightningcss@1.29.1)(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vitest: 3.0.6(@types/node@22.13.4)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@25.0.1)(lightningcss@1.29.2)(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) ws: 8.18.0 optionalDependencies: playwright: 1.52.0 @@ -19466,14 +18246,14 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.6(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))': + '@vitest/mocker@3.0.6(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))': dependencies: '@vitest/spy': 3.0.6 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: msw: 2.7.0(@types/node@22.13.4)(typescript@5.8.2) - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) '@vitest/pretty-format@3.0.6': dependencies: @@ -19501,9 +18281,9 @@ snapshots: flatted: 3.3.2 pathe: 2.0.3 sirv: 3.0.1 - tinyglobby: 0.2.12 + tinyglobby: 0.2.13 tinyrainbow: 2.0.0 - vitest: 3.0.6(@types/node@22.13.4)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@25.0.1)(lightningcss@1.29.1)(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vitest: 3.0.6(@types/node@22.13.4)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@25.0.1)(lightningcss@1.29.2)(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) '@vitest/utils@3.0.6': dependencies: @@ -19647,22 +18427,22 @@ snapshots: '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.97.1)': dependencies: - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.0)(webpack@5.97.1) '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.97.1)': dependencies: - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.0)(webpack@5.97.1) '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.2.0)(webpack@5.97.1)': dependencies: - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.0)(webpack@5.97.1) optionalDependencies: webpack-dev-server: 5.2.0(webpack-cli@5.1.4)(webpack@5.97.1) - '@workos-inc/node@7.45.0(express@4.21.2)': + '@workos-inc/node@7.46.0(express@4.21.2)': dependencies: iron-session: 6.3.1(express@4.21.2) jose: 5.6.3 @@ -19704,19 +18484,19 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-import-attributes@1.9.5(acorn@8.14.0): + acorn-import-attributes@1.9.5(acorn@8.14.1): dependencies: - acorn: 8.14.0 + acorn: 8.14.1 - acorn-jsx@5.3.2(acorn@8.14.0): + acorn-jsx@5.3.2(acorn@8.14.1): dependencies: - acorn: 8.14.0 + acorn: 8.14.1 - acorn@8.14.0: {} + acorn@8.14.1: {} agent-base@6.0.2: dependencies: - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -19773,10 +18553,6 @@ snapshots: alien-signals@0.4.14: {} - ansi-align@3.0.1: - dependencies: - string-width: 4.2.3 - ansi-colors@4.1.3: {} ansi-escapes@4.3.2: @@ -19911,7 +18687,7 @@ snapshots: '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.8) '@babel/types': 7.26.8 html-entities: 2.3.3 - parse5: 7.2.1 + parse5: 7.3.0 validate-html-nesting: 1.2.2 babel-plugin-macros@3.1.0: @@ -19972,17 +18748,6 @@ snapshots: boolbase@1.0.0: {} - boxen@7.1.1: - dependencies: - ansi-align: 3.0.1 - camelcase: 7.0.1 - chalk: 5.4.1 - cli-boxes: 3.0.0 - string-width: 5.1.2 - type-fest: 2.19.0 - widest-line: 4.0.1 - wrap-ansi: 8.1.0 - brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -20023,19 +18788,19 @@ snapshots: bytes@3.1.2: {} - c12@2.0.1(magicast@0.3.5): + c12@3.0.2(magicast@0.3.5): dependencies: chokidar: 4.0.3 confbox: 0.1.8 defu: 6.1.4 dotenv: 16.4.7 - giget: 1.2.4 + exsolve: 1.0.4 + giget: 2.0.0 jiti: 2.4.2 - mlly: 1.7.4 - ohash: 1.1.4 - pathe: 1.1.2 + ohash: 2.0.11 + pathe: 2.0.3 perfect-debounce: 1.0.0 - pkg-types: 1.3.1 + pkg-types: 2.1.0 rc9: 2.1.2 optionalDependencies: magicast: 0.3.5 @@ -20061,8 +18826,6 @@ snapshots: camelcase-css@2.0.1: {} - camelcase@7.0.1: {} - caniuse-lite@1.0.30001696: {} chai@5.2.0: @@ -20085,12 +18848,33 @@ snapshots: chalk@5.4.1: {} - change-case@5.4.4: {} - char-regex@1.0.2: {} check-error@2.1.1: {} + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.1.0 + css-what: 6.1.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + + cheerio@1.0.0: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.0 + htmlparser2: 9.1.0 + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 6.21.2 + whatwg-mimetype: 4.0.0 + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -20107,15 +18891,13 @@ snapshots: dependencies: readdirp: 4.1.1 - chownr@2.0.0: {} - chownr@3.0.0: {} chrome-trace-event@1.0.4: {} citty@0.1.6: dependencies: - consola: 3.4.0 + consola: 3.4.2 cjs-module-lexer@1.4.3: {} @@ -20125,8 +18907,6 @@ snapshots: dependencies: source-map: 0.6.1 - cli-boxes@3.0.0: {} - cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -20186,8 +18966,6 @@ snapshots: color-name@1.1.4: {} - colorette@1.4.0: {} - colorette@2.0.20: {} combinate@1.1.11: {} @@ -20259,9 +19037,11 @@ snapshots: confbox@0.1.8: {} + confbox@0.2.1: {} + connect-history-api-fallback@2.0.0: {} - consola@3.4.0: {} + consola@3.4.2: {} content-disposition@0.5.4: dependencies: @@ -20296,6 +19076,8 @@ snapshots: cookie-es@1.2.2: {} + cookie-es@2.0.0: {} + cookie-signature@1.0.6: {} cookie@0.5.0: {} @@ -20306,10 +19088,6 @@ snapshots: cookie@1.0.2: {} - copy-anything@3.0.5: - dependencies: - is-what: 4.1.16 - core-js@3.40.0: {} core-util-is@1.0.3: {} @@ -20337,7 +19115,7 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - crossws@0.3.3: + crossws@0.3.4: dependencies: uncrypto: 0.1.3 @@ -20349,6 +19127,14 @@ snapshots: domutils: 2.8.0 nth-check: 2.1.1 + css-select@5.1.0: + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + css-what@6.1.0: {} css.escape@1.5.1: {} @@ -20362,8 +19148,6 @@ snapshots: csstype@3.1.3: {} - data-uri-to-buffer@4.0.1: {} - data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 @@ -20373,12 +19157,7 @@ snapshots: dependencies: '@babel/runtime': 7.26.7 - dax-sh@0.39.2: - dependencies: - '@deno/shim-deno': 0.19.2 - undici-types: 5.28.4 - - db0@0.2.3: {} + db0@0.3.1: {} de-indent@1.0.2: {} @@ -20390,18 +19169,12 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.0(supports-color@9.4.0): + debug@4.4.0: dependencies: ms: 2.1.3 - optionalDependencies: - supports-color: 9.4.0 decimal.js@10.5.0: {} - dedent@1.5.3(babel-plugin-macros@3.1.0): - optionalDependencies: - babel-plugin-macros: 3.1.0 - deep-eql@5.0.2: {} deep-is@0.1.4: {} @@ -20443,7 +19216,7 @@ snapshots: detect-libc@1.0.3: {} - detect-libc@2.0.3: {} + detect-libc@2.0.4: {} detect-node-es@1.1.0: {} @@ -20484,18 +19257,34 @@ snapshots: domhandler: 4.3.1 entities: 2.2.0 + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + domelementtype@2.3.0: {} domhandler@4.3.1: dependencies: domelementtype: 2.3.0 + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + domutils@2.8.0: dependencies: dom-serializer: 1.4.1 domelementtype: 2.3.0 domhandler: 4.3.1 + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dot-case@3.0.4: dependencies: no-case: 3.0.4 @@ -20539,6 +19328,11 @@ snapshots: encodeurl@2.0.0: {} + encoding-sniffer@0.2.0: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + end-of-stream@1.4.4: dependencies: once: 1.4.0 @@ -20556,6 +19350,8 @@ snapshots: entities@4.5.0: {} + entities@6.0.0: {} + envinfo@7.14.0: {} environment@1.1.0: {} @@ -20564,6 +19360,8 @@ snapshots: dependencies: is-arrayish: 0.2.1 + error-stack-parser-es@1.0.5: {} + error-stack-parser@2.1.4: dependencies: stackframe: 1.3.4 @@ -20578,49 +19376,23 @@ snapshots: dependencies: es-errors: 1.3.0 - esbuild-plugin-solid@0.6.0(esbuild@0.25.0)(solid-js@1.9.5): + esbuild-plugin-solid@0.6.0(esbuild@0.25.2)(solid-js@1.9.5): dependencies: '@babel/core': 7.26.8 '@babel/preset-typescript': 7.26.0(@babel/core@7.26.8) babel-preset-solid: 1.9.3(@babel/core@7.26.8) - esbuild: 0.25.0 + esbuild: 0.25.2 solid-js: 1.9.5 transitivePeerDependencies: - supports-color - esbuild-register@3.6.0(esbuild@0.25.0): + esbuild-register@3.6.0(esbuild@0.25.2): dependencies: - debug: 4.4.0(supports-color@9.4.0) - esbuild: 0.25.0 + debug: 4.4.0 + esbuild: 0.25.2 transitivePeerDependencies: - supports-color - esbuild@0.20.2: - optionalDependencies: - '@esbuild/aix-ppc64': 0.20.2 - '@esbuild/android-arm': 0.20.2 - '@esbuild/android-arm64': 0.20.2 - '@esbuild/android-x64': 0.20.2 - '@esbuild/darwin-arm64': 0.20.2 - '@esbuild/darwin-x64': 0.20.2 - '@esbuild/freebsd-arm64': 0.20.2 - '@esbuild/freebsd-x64': 0.20.2 - '@esbuild/linux-arm': 0.20.2 - '@esbuild/linux-arm64': 0.20.2 - '@esbuild/linux-ia32': 0.20.2 - '@esbuild/linux-loong64': 0.20.2 - '@esbuild/linux-mips64el': 0.20.2 - '@esbuild/linux-ppc64': 0.20.2 - '@esbuild/linux-riscv64': 0.20.2 - '@esbuild/linux-s390x': 0.20.2 - '@esbuild/linux-x64': 0.20.2 - '@esbuild/netbsd-x64': 0.20.2 - '@esbuild/openbsd-x64': 0.20.2 - '@esbuild/sunos-x64': 0.20.2 - '@esbuild/win32-arm64': 0.20.2 - '@esbuild/win32-ia32': 0.20.2 - '@esbuild/win32-x64': 0.20.2 - esbuild@0.23.0: optionalDependencies: '@esbuild/aix-ppc64': 0.23.0 @@ -20675,61 +19447,33 @@ snapshots: '@esbuild/win32-ia32': 0.23.1 '@esbuild/win32-x64': 0.23.1 - esbuild@0.24.2: - optionalDependencies: - '@esbuild/aix-ppc64': 0.24.2 - '@esbuild/android-arm': 0.24.2 - '@esbuild/android-arm64': 0.24.2 - '@esbuild/android-x64': 0.24.2 - '@esbuild/darwin-arm64': 0.24.2 - '@esbuild/darwin-x64': 0.24.2 - '@esbuild/freebsd-arm64': 0.24.2 - '@esbuild/freebsd-x64': 0.24.2 - '@esbuild/linux-arm': 0.24.2 - '@esbuild/linux-arm64': 0.24.2 - '@esbuild/linux-ia32': 0.24.2 - '@esbuild/linux-loong64': 0.24.2 - '@esbuild/linux-mips64el': 0.24.2 - '@esbuild/linux-ppc64': 0.24.2 - '@esbuild/linux-riscv64': 0.24.2 - '@esbuild/linux-s390x': 0.24.2 - '@esbuild/linux-x64': 0.24.2 - '@esbuild/netbsd-arm64': 0.24.2 - '@esbuild/netbsd-x64': 0.24.2 - '@esbuild/openbsd-arm64': 0.24.2 - '@esbuild/openbsd-x64': 0.24.2 - '@esbuild/sunos-x64': 0.24.2 - '@esbuild/win32-arm64': 0.24.2 - '@esbuild/win32-ia32': 0.24.2 - '@esbuild/win32-x64': 0.24.2 - - esbuild@0.25.0: + esbuild@0.25.2: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.0 - '@esbuild/android-arm': 0.25.0 - '@esbuild/android-arm64': 0.25.0 - '@esbuild/android-x64': 0.25.0 - '@esbuild/darwin-arm64': 0.25.0 - '@esbuild/darwin-x64': 0.25.0 - '@esbuild/freebsd-arm64': 0.25.0 - '@esbuild/freebsd-x64': 0.25.0 - '@esbuild/linux-arm': 0.25.0 - '@esbuild/linux-arm64': 0.25.0 - '@esbuild/linux-ia32': 0.25.0 - '@esbuild/linux-loong64': 0.25.0 - '@esbuild/linux-mips64el': 0.25.0 - '@esbuild/linux-ppc64': 0.25.0 - '@esbuild/linux-riscv64': 0.25.0 - '@esbuild/linux-s390x': 0.25.0 - '@esbuild/linux-x64': 0.25.0 - '@esbuild/netbsd-arm64': 0.25.0 - '@esbuild/netbsd-x64': 0.25.0 - '@esbuild/openbsd-arm64': 0.25.0 - '@esbuild/openbsd-x64': 0.25.0 - '@esbuild/sunos-x64': 0.25.0 - '@esbuild/win32-arm64': 0.25.0 - '@esbuild/win32-ia32': 0.25.0 - '@esbuild/win32-x64': 0.25.0 + '@esbuild/aix-ppc64': 0.25.2 + '@esbuild/android-arm': 0.25.2 + '@esbuild/android-arm64': 0.25.2 + '@esbuild/android-x64': 0.25.2 + '@esbuild/darwin-arm64': 0.25.2 + '@esbuild/darwin-x64': 0.25.2 + '@esbuild/freebsd-arm64': 0.25.2 + '@esbuild/freebsd-x64': 0.25.2 + '@esbuild/linux-arm': 0.25.2 + '@esbuild/linux-arm64': 0.25.2 + '@esbuild/linux-ia32': 0.25.2 + '@esbuild/linux-loong64': 0.25.2 + '@esbuild/linux-mips64el': 0.25.2 + '@esbuild/linux-ppc64': 0.25.2 + '@esbuild/linux-riscv64': 0.25.2 + '@esbuild/linux-s390x': 0.25.2 + '@esbuild/linux-x64': 0.25.2 + '@esbuild/netbsd-arm64': 0.25.2 + '@esbuild/netbsd-x64': 0.25.2 + '@esbuild/openbsd-arm64': 0.25.2 + '@esbuild/openbsd-x64': 0.25.2 + '@esbuild/sunos-x64': 0.25.2 + '@esbuild/win32-arm64': 0.25.2 + '@esbuild/win32-ia32': 0.25.2 + '@esbuild/win32-x64': 0.25.2 escalade@3.2.0: {} @@ -20744,7 +19488,7 @@ snapshots: eslint-compat-utils@0.5.1(eslint@9.22.0(jiti@2.4.2)): dependencies: eslint: 9.22.0(jiti@2.4.2) - semver: 7.7.0 + semver: 7.7.1 eslint-import-resolver-node@0.3.9: dependencies: @@ -20766,7 +19510,7 @@ snapshots: '@types/doctrine': 0.0.9 '@typescript-eslint/scope-manager': 8.23.0 '@typescript-eslint/utils': 8.23.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 doctrine: 3.0.0 enhanced-resolve: 5.18.1 eslint: 9.22.0(jiti@2.4.2) @@ -20774,7 +19518,7 @@ snapshots: get-tsconfig: 4.10.0 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.0 + semver: 7.7.1 stable-hash: 0.0.4 tslib: 2.8.1 transitivePeerDependencies: @@ -20791,7 +19535,7 @@ snapshots: globals: 15.14.0 ignore: 5.3.2 minimatch: 9.0.5 - semver: 7.7.0 + semver: 7.7.1 eslint-plugin-react-debug@1.26.2(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2): dependencies: @@ -20974,7 +19718,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 escape-string-regexp: 4.0.0 eslint-scope: 8.3.0 eslint-visitor-keys: 4.2.0 @@ -21000,14 +19744,14 @@ snapshots: espree@10.3.0: dependencies: - acorn: 8.14.0 - acorn-jsx: 5.3.2(acorn@8.14.0) + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) eslint-visitor-keys: 4.2.0 espree@9.6.1: dependencies: - acorn: 8.14.0 - acorn-jsx: 5.3.2(acorn@8.14.0) + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} @@ -21094,6 +19838,8 @@ snapshots: transitivePeerDependencies: - supports-color + exsolve@1.0.4: {} + extend@3.0.2: {} fast-deep-equal@3.1.3: {} @@ -21124,15 +19870,10 @@ snapshots: dependencies: websocket-driver: 0.7.4 - fdir@6.4.3(picomatch@4.0.2): + fdir@6.4.4(picomatch@4.0.2): optionalDependencies: picomatch: 4.0.2 - fetch-blob@3.2.0: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.3.3 - fflate@0.8.2: {} figures@3.2.0: @@ -21251,10 +19992,6 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 - formdata-polyfill@4.0.10: - dependencies: - fetch-blob: 3.2.0 - forwarded@0.2.0: {} fraction.js@4.3.7: {} @@ -21289,10 +20026,6 @@ snapshots: jsonfile: 4.0.0 universalify: 0.1.2 - fs-minipass@2.1.0: - dependencies: - minipass: 3.3.6 - fs.realpath@1.0.0: {} fsevents@2.3.2: @@ -21324,8 +20057,6 @@ snapshots: get-port-please@3.1.2: {} - get-port@7.1.0: {} - get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -21337,16 +20068,14 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - giget@1.2.4: + giget@2.0.0: dependencies: citty: 0.1.6 - consola: 3.4.0 + consola: 3.4.2 defu: 6.1.4 node-fetch-native: 1.6.6 - nypm: 0.5.2 - ohash: 1.1.4 + nypm: 0.6.0 pathe: 2.0.3 - tar: 6.2.1 glob-parent@5.1.2: dependencies: @@ -21370,20 +20099,11 @@ snapshots: glob@11.0.1: dependencies: foreground-child: 3.3.0 - jackspeak: 4.0.2 - minimatch: 10.0.1 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 2.0.0 - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 + jackspeak: 4.0.2 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 glob@9.3.5: dependencies: @@ -21412,14 +20132,14 @@ snapshots: globals@15.14.0: {} - globby@14.0.2: + globby@14.1.0: dependencies: '@sindresorhus/merge-streams': 2.3.0 fast-glob: 3.3.3 - ignore: 5.3.2 - path-type: 5.0.0 + ignore: 7.0.3 + path-type: 6.0.0 slash: 5.1.0 - unicorn-magic: 0.1.0 + unicorn-magic: 0.3.0 globrex@0.1.2: {} @@ -21442,7 +20162,7 @@ snapshots: h3@1.13.0: dependencies: cookie-es: 1.2.2 - crossws: 0.3.3 + crossws: 0.3.4 defu: 6.1.4 destr: 2.0.3 iron-webcrypto: 1.2.1 @@ -21452,6 +20172,18 @@ snapshots: uncrypto: 0.1.3 unenv: 1.10.0 + h3@1.15.1: + dependencies: + cookie-es: 1.2.2 + crossws: 0.3.4 + defu: 6.1.4 + destr: 2.0.3 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.0 + radix3: 1.1.2 + ufo: 1.5.4 + uncrypto: 0.1.3 + handle-thing@2.0.1: {} has-flag@4.0.0: {} @@ -21514,7 +20246,7 @@ snapshots: tapable: 2.2.1 optionalDependencies: '@rspack/core': 1.2.2(@swc/helpers@0.5.15) - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) htmlparser2@6.1.0: dependencies: @@ -21523,6 +20255,13 @@ snapshots: domutils: 2.8.0 entities: 2.2.0 + htmlparser2@9.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 4.5.0 + http-deceiver@1.2.7: {} http-errors@1.6.3: @@ -21545,7 +20284,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -21574,14 +20313,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color - https-proxy-agent@7.0.6(supports-color@9.4.0): + https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -21605,6 +20344,8 @@ snapshots: ignore@5.3.2: {} + ignore@7.0.3: {} + immer@10.1.1: {} import-fresh@3.3.0: @@ -21619,19 +20360,10 @@ snapshots: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 - import-meta-resolve@4.1.0: {} - imurmurhash@0.1.4: {} indent-string@4.0.0: {} - index-to-position@0.1.2: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - inherits@2.0.3: {} inherits@2.0.4: {} @@ -21642,11 +20374,11 @@ snapshots: interpret@3.1.1: {} - ioredis@5.4.2: + ioredis@5.6.0: dependencies: '@ioredis/commands': 1.2.0 cluster-key-slot: 1.1.2 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -21795,8 +20527,6 @@ snapshots: isexe@2.0.0: {} - isexe@3.1.1: {} - isobject@3.0.1: {} isomorphic-rslog@0.0.6: {} @@ -21838,8 +20568,6 @@ snapshots: js-cookie@3.0.5: {} - js-levenshtein@1.1.6: {} - js-tokens@4.0.0: {} js-tokens@9.0.1: {} @@ -21861,10 +20589,10 @@ snapshots: form-data: 4.0.1 html-encoding-sniffer: 4.0.0 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6(supports-color@9.4.0) + https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 nwsapi: 2.2.16 - parse5: 7.2.1 + parse5: 7.3.0 rrweb-cssom: 0.7.1 saxes: 6.0.0 symbol-tree: 3.2.4 @@ -21919,6 +20647,8 @@ snapshots: kind-of@6.0.3: {} + kleur@4.1.5: {} + klona@2.0.6: {} knitwork@1.2.0: {} @@ -21955,50 +20685,50 @@ snapshots: rechoir: 0.8.0 resolve: 1.22.10 - lightningcss-darwin-arm64@1.29.1: + lightningcss-darwin-arm64@1.29.2: optional: true - lightningcss-darwin-x64@1.29.1: + lightningcss-darwin-x64@1.29.2: optional: true - lightningcss-freebsd-x64@1.29.1: + lightningcss-freebsd-x64@1.29.2: optional: true - lightningcss-linux-arm-gnueabihf@1.29.1: + lightningcss-linux-arm-gnueabihf@1.29.2: optional: true - lightningcss-linux-arm64-gnu@1.29.1: + lightningcss-linux-arm64-gnu@1.29.2: optional: true - lightningcss-linux-arm64-musl@1.29.1: + lightningcss-linux-arm64-musl@1.29.2: optional: true - lightningcss-linux-x64-gnu@1.29.1: + lightningcss-linux-x64-gnu@1.29.2: optional: true - lightningcss-linux-x64-musl@1.29.1: + lightningcss-linux-x64-musl@1.29.2: optional: true - lightningcss-win32-arm64-msvc@1.29.1: + lightningcss-win32-arm64-msvc@1.29.2: optional: true - lightningcss-win32-x64-msvc@1.29.1: + lightningcss-win32-x64-msvc@1.29.2: optional: true - lightningcss@1.29.1: + lightningcss@1.29.2: dependencies: - detect-libc: 1.0.3 + detect-libc: 2.0.4 optionalDependencies: - lightningcss-darwin-arm64: 1.29.1 - lightningcss-darwin-x64: 1.29.1 - lightningcss-freebsd-x64: 1.29.1 - lightningcss-linux-arm-gnueabihf: 1.29.1 - lightningcss-linux-arm64-gnu: 1.29.1 - lightningcss-linux-arm64-musl: 1.29.1 - lightningcss-linux-x64-gnu: 1.29.1 - lightningcss-linux-x64-musl: 1.29.1 - lightningcss-win32-arm64-msvc: 1.29.1 - lightningcss-win32-x64-msvc: 1.29.1 + lightningcss-darwin-arm64: 1.29.2 + lightningcss-darwin-x64: 1.29.2 + lightningcss-freebsd-x64: 1.29.2 + lightningcss-linux-arm-gnueabihf: 1.29.2 + lightningcss-linux-arm64-gnu: 1.29.2 + lightningcss-linux-arm64-musl: 1.29.2 + lightningcss-linux-x64-gnu: 1.29.2 + lightningcss-linux-x64-musl: 1.29.2 + lightningcss-win32-arm64-msvc: 1.29.2 + lightningcss-win32-x64-msvc: 1.29.2 lilconfig@3.1.3: {} @@ -22016,8 +20746,8 @@ snapshots: '@parcel/watcher-wasm': 2.5.1 citty: 0.1.6 clipboardy: 4.0.0 - consola: 3.4.0 - crossws: 0.3.3 + consola: 3.4.2 + crossws: 0.3.4 defu: 6.1.4 get-port-please: 3.1.2 h3: 1.13.0 @@ -22026,7 +20756,7 @@ snapshots: mlly: 1.7.4 node-forge: 1.3.1 pathe: 1.1.2 - std-env: 3.8.0 + std-env: 3.8.1 ufo: 1.5.4 untun: 0.1.3 uqr: 0.1.2 @@ -22038,10 +20768,11 @@ snapshots: mlly: 1.7.4 pkg-types: 1.3.1 - local-pkg@1.0.0: + local-pkg@1.1.1: dependencies: mlly: 1.7.4 - pkg-types: 1.3.1 + pkg-types: 2.1.0 + quansync: 0.2.10 locate-path@5.0.0: dependencies: @@ -22218,33 +20949,20 @@ snapshots: minimist@1.2.8: {} - minipass@3.3.6: - dependencies: - yallist: 4.0.0 - minipass@4.2.8: {} - minipass@5.0.0: {} - minipass@7.1.2: {} - minizlib@2.1.2: - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 - minizlib@3.0.1: dependencies: minipass: 7.1.2 rimraf: 5.0.10 - mkdirp@1.0.4: {} - mkdirp@3.0.1: {} mlly@1.7.4: dependencies: - acorn: 8.14.0 + acorn: 8.14.1 pathe: 2.0.3 pkg-types: 1.3.1 ufo: 1.5.4 @@ -22313,44 +21031,42 @@ snapshots: neo-async@2.6.2: {} - nitropack@2.10.4(typescript@5.8.2): - dependencies: - '@cloudflare/kv-asset-handler': 0.3.4 - '@netlify/functions': 2.8.2 - '@rollup/plugin-alias': 5.1.1(rollup@4.39.0) - '@rollup/plugin-commonjs': 28.0.2(rollup@4.39.0) - '@rollup/plugin-inject': 5.0.5(rollup@4.39.0) - '@rollup/plugin-json': 6.1.0(rollup@4.39.0) - '@rollup/plugin-node-resolve': 15.3.1(rollup@4.39.0) - '@rollup/plugin-replace': 6.0.2(rollup@4.39.0) - '@rollup/plugin-terser': 0.4.4(rollup@4.39.0) - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) - '@types/http-proxy': 1.17.15 - '@vercel/nft': 0.27.10(rollup@4.39.0) + nitropack@2.11.8: + dependencies: + '@cloudflare/kv-asset-handler': 0.4.0 + '@netlify/functions': 3.0.4 + '@rollup/plugin-alias': 5.1.1(rollup@4.38.0) + '@rollup/plugin-commonjs': 28.0.3(rollup@4.38.0) + '@rollup/plugin-inject': 5.0.5(rollup@4.38.0) + '@rollup/plugin-json': 6.1.0(rollup@4.38.0) + '@rollup/plugin-node-resolve': 16.0.1(rollup@4.38.0) + '@rollup/plugin-replace': 6.0.2(rollup@4.38.0) + '@rollup/plugin-terser': 0.4.4(rollup@4.38.0) + '@vercel/nft': 0.29.2(rollup@4.38.0) archiver: 7.0.1 - c12: 2.0.1(magicast@0.3.5) - chokidar: 3.6.0 + c12: 3.0.2(magicast@0.3.5) + chokidar: 4.0.3 citty: 0.1.6 compatx: 0.1.8 - confbox: 0.1.8 - consola: 3.4.0 - cookie-es: 1.2.2 + confbox: 0.2.1 + consola: 3.4.2 + cookie-es: 2.0.0 croner: 9.0.0 - crossws: 0.3.3 - db0: 0.2.3 + crossws: 0.3.4 + db0: 0.3.1 defu: 6.1.4 destr: 2.0.3 dot-prop: 9.0.0 - esbuild: 0.24.2 + esbuild: 0.25.2 escape-string-regexp: 5.0.0 etag: 1.8.1 - fs-extra: 11.3.0 - globby: 14.0.2 + exsolve: 1.0.4 + globby: 14.1.0 gzip-size: 7.0.0 - h3: 1.13.0 + h3: 1.15.1 hookable: 5.5.3 httpxy: 0.1.7 - ioredis: 5.4.2 + ioredis: 5.6.0 jiti: 2.4.2 klona: 2.0.6 knitwork: 1.2.0 @@ -22360,29 +21076,34 @@ snapshots: mime: 4.0.6 mlly: 1.7.4 node-fetch-native: 1.6.6 + node-mock-http: 1.0.0 ofetch: 1.4.1 - ohash: 1.1.4 - openapi-typescript: 7.6.0(typescript@5.8.2) - pathe: 1.1.2 + ohash: 2.0.11 + pathe: 2.0.3 perfect-debounce: 1.0.0 - pkg-types: 1.3.1 + pkg-types: 2.1.0 pretty-bytes: 6.1.1 radix3: 1.1.2 - rollup: 4.39.0 - rollup-plugin-visualizer: 5.14.0(rollup@4.39.0) + rollup: 4.38.0 + rollup-plugin-visualizer: 5.14.0(rollup@4.38.0) scule: 1.3.0 - semver: 7.7.0 + semver: 7.7.1 serve-placeholder: 2.0.2 serve-static: 1.16.2 - std-env: 3.8.0 + source-map: 0.7.4 + std-env: 3.8.1 ufo: 1.5.4 + ultrahtml: 1.5.3 uncrypto: 0.1.3 unctx: 2.4.1 - unenv: 1.10.0 - unimport: 3.14.6(rollup@4.39.0) - unstorage: 1.14.4(db0@0.2.3)(ioredis@5.4.2) - untyped: 1.5.2 + unenv: 2.0.0-rc.15 + unimport: 4.1.3 + unplugin-utils: 0.2.4 + unstorage: 1.15.0(db0@0.3.1)(ioredis@5.6.0) + untyped: 2.0.0 unwasm: 0.3.9 + youch: 4.1.0-beta.7 + youch-core: 0.3.2 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -22408,7 +21129,6 @@ snapshots: - rolldown - sqlite3 - supports-color - - typescript - uploadthing no-case@3.0.4: @@ -22418,8 +21138,6 @@ snapshots: node-addon-api@7.1.1: {} - node-domexception@1.0.0: {} - node-emoji@2.2.0: dependencies: '@sindresorhus/is': 4.6.0 @@ -22433,18 +21151,14 @@ snapshots: dependencies: whatwg-url: 5.0.0 - node-fetch@3.3.2: - dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - node-forge@1.3.1: {} node-gyp-build@4.8.4: {} node-machine-id@1.1.12: {} + node-mock-http@1.0.0: {} + node-releases@2.0.19: {} nopt@8.1.0: @@ -22496,7 +21210,7 @@ snapshots: open: 8.4.2 ora: 5.3.0 resolve.exports: 2.0.3 - semver: 7.7.0 + semver: 7.7.1 string-width: 4.2.3 tar-stream: 2.2.0 tmp: 0.2.3 @@ -22520,14 +21234,13 @@ snapshots: transitivePeerDependencies: - debug - nypm@0.5.2: + nypm@0.6.0: dependencies: citty: 0.1.6 - consola: 3.4.0 + consola: 3.4.2 pathe: 2.0.3 - pkg-types: 1.3.1 + pkg-types: 2.1.0 tinyexec: 0.3.2 - ufo: 1.5.4 object-assign@4.1.1: {} @@ -22556,6 +21269,8 @@ snapshots: ohash@1.1.4: {} + ohash@2.0.11: {} + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -22587,16 +21302,6 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - openapi-typescript@7.6.0(typescript@5.8.2): - dependencies: - '@redocly/openapi-core': 1.28.0(supports-color@9.4.0) - ansi-colors: 4.1.3 - change-case: 5.4.4 - parse-json: 8.1.0 - supports-color: 9.4.0 - typescript: 5.8.2 - yargs-parser: 21.1.1 - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -22669,25 +21374,28 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - parse-json@8.1.0: - dependencies: - '@babel/code-frame': 7.26.2 - index-to-position: 0.1.2 - type-fest: 4.33.0 - parse-passwd@1.0.0: {} parse5-htmlparser2-tree-adapter@6.0.1: dependencies: parse5: 6.0.1 + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.3.0 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.3.0 + parse5@5.1.1: {} parse5@6.0.1: {} - parse5@7.2.1: + parse5@7.3.0: dependencies: - entities: 4.5.0 + entities: 6.0.0 parseurl@1.3.3: {} @@ -22700,8 +21408,6 @@ snapshots: path-exists@4.0.0: {} - path-is-absolute@1.0.1: {} - path-key@3.1.1: {} path-key@4.0.0: {} @@ -22730,7 +21436,7 @@ snapshots: path-type@4.0.0: {} - path-type@5.0.0: {} + path-type@6.0.0: {} pathe@1.1.2: {} @@ -22760,6 +21466,12 @@ snapshots: mlly: 1.7.4 pathe: 2.0.3 + pkg-types@2.1.0: + dependencies: + confbox: 0.2.1 + exsolve: 1.0.4 + pathe: 2.0.3 + playwright-core@1.52.0: {} playwright@1.52.0: @@ -22897,6 +21609,8 @@ snapshots: dependencies: side-channel: 1.1.0 + quansync@0.2.10: {} + querystringify@2.2.0: {} queue-microtask@1.2.3: {} @@ -23157,45 +21871,45 @@ snapshots: glob: 11.0.1 package-json-from-dist: 1.0.1 - rollup-plugin-preserve-directives@0.4.0(rollup@4.39.0): + rollup-plugin-preserve-directives@0.4.0(rollup@4.38.0): dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) + '@rollup/pluginutils': 5.1.4(rollup@4.38.0) magic-string: 0.30.17 - rollup: 4.39.0 + rollup: 4.38.0 - rollup-plugin-visualizer@5.14.0(rollup@4.39.0): + rollup-plugin-visualizer@5.14.0(rollup@4.38.0): dependencies: open: 8.4.2 picomatch: 4.0.2 source-map: 0.7.4 yargs: 17.7.2 optionalDependencies: - rollup: 4.39.0 + rollup: 4.38.0 - rollup@4.39.0: + rollup@4.38.0: dependencies: '@types/estree': 1.0.7 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.39.0 - '@rollup/rollup-android-arm64': 4.39.0 - '@rollup/rollup-darwin-arm64': 4.39.0 - '@rollup/rollup-darwin-x64': 4.39.0 - '@rollup/rollup-freebsd-arm64': 4.39.0 - '@rollup/rollup-freebsd-x64': 4.39.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.39.0 - '@rollup/rollup-linux-arm-musleabihf': 4.39.0 - '@rollup/rollup-linux-arm64-gnu': 4.39.0 - '@rollup/rollup-linux-arm64-musl': 4.39.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.39.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.39.0 - '@rollup/rollup-linux-riscv64-gnu': 4.39.0 - '@rollup/rollup-linux-riscv64-musl': 4.39.0 - '@rollup/rollup-linux-s390x-gnu': 4.39.0 - '@rollup/rollup-linux-x64-gnu': 4.39.0 - '@rollup/rollup-linux-x64-musl': 4.39.0 - '@rollup/rollup-win32-arm64-msvc': 4.39.0 - '@rollup/rollup-win32-ia32-msvc': 4.39.0 - '@rollup/rollup-win32-x64-msvc': 4.39.0 + '@rollup/rollup-android-arm-eabi': 4.38.0 + '@rollup/rollup-android-arm64': 4.38.0 + '@rollup/rollup-darwin-arm64': 4.38.0 + '@rollup/rollup-darwin-x64': 4.38.0 + '@rollup/rollup-freebsd-arm64': 4.38.0 + '@rollup/rollup-freebsd-x64': 4.38.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.38.0 + '@rollup/rollup-linux-arm-musleabihf': 4.38.0 + '@rollup/rollup-linux-arm64-gnu': 4.38.0 + '@rollup/rollup-linux-arm64-musl': 4.38.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.38.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.38.0 + '@rollup/rollup-linux-riscv64-gnu': 4.38.0 + '@rollup/rollup-linux-riscv64-musl': 4.38.0 + '@rollup/rollup-linux-s390x-gnu': 4.38.0 + '@rollup/rollup-linux-x64-gnu': 4.38.0 + '@rollup/rollup-linux-x64-musl': 4.38.0 + '@rollup/rollup-win32-arm64-msvc': 4.38.0 + '@rollup/rollup-win32-ia32-msvc': 4.38.0 + '@rollup/rollup-win32-x64-msvc': 4.38.0 fsevents: 2.3.3 rrweb-cssom@0.7.1: {} @@ -23256,7 +21970,7 @@ snapshots: dependencies: lru-cache: 6.0.0 - semver@7.7.0: {} + semver@7.7.1: {} send@0.19.0: dependencies: @@ -23365,7 +22079,7 @@ snapshots: dependencies: '@kwsites/file-exists': 1.1.1 '@kwsites/promise-deferred': 1.1.1 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -23434,7 +22148,7 @@ snapshots: spdy-transport@3.0.0: dependencies: - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 detect-node: 2.1.0 hpack.js: 2.1.6 obuf: 1.1.2 @@ -23445,7 +22159,7 @@ snapshots: spdy@4.0.2: dependencies: - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 handle-thing: 2.0.1 http-deceiver: 1.2.7 select-hose: 2.0.0 @@ -23469,7 +22183,7 @@ snapshots: statuses@2.0.1: {} - std-env@3.8.0: {} + std-env@3.8.1: {} streamx@2.22.0: dependencies: @@ -23522,7 +22236,7 @@ snapshots: strip-json-comments@3.1.1: {} - strip-literal@2.1.1: + strip-literal@3.0.0: dependencies: js-tokens: 9.0.1 @@ -23542,9 +22256,7 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 - superjson@2.2.2: - dependencies: - copy-anything: 3.0.5 + supports-color@10.0.0: {} supports-color@7.2.0: dependencies: @@ -23554,8 +22266,6 @@ snapshots: dependencies: has-flag: 4.0.0 - supports-color@9.4.0: {} - supports-hyperlinks@3.1.0: dependencies: has-flag: 4.0.0 @@ -23567,7 +22277,7 @@ snapshots: dependencies: '@swc/core': 1.10.15(@swc/helpers@0.5.15) '@swc/counter': 0.1.3 - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) swr@2.3.0(react@19.0.0): dependencies: @@ -23608,7 +22318,7 @@ snapshots: transitivePeerDependencies: - ts-node - tailwindcss@4.0.8: {} + tailwindcss@4.1.6: {} tapable@2.2.1: {} @@ -23626,15 +22336,6 @@ snapshots: fast-fifo: 1.3.2 streamx: 2.22.0 - tar@6.2.1: - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - tar@7.4.3: dependencies: '@isaacs/fs-minipass': 4.0.1 @@ -23644,34 +22345,34 @@ snapshots: mkdirp: 3.0.1 yallist: 5.0.0 - terser-webpack-plugin@5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)): + terser-webpack-plugin@5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 4.3.0 serialize-javascript: 6.0.2 terser: 5.37.0 - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2) optionalDependencies: '@swc/core': 1.10.15(@swc/helpers@0.5.15) - esbuild: 0.25.0 + esbuild: 0.25.2 - terser-webpack-plugin@5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack@5.97.1): + terser-webpack-plugin@5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack@5.97.1): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 4.3.0 serialize-javascript: 6.0.2 terser: 5.37.0 - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.10.15(@swc/helpers@0.5.15) - esbuild: 0.25.0 + esbuild: 0.25.2 terser@5.37.0: dependencies: '@jridgewell/source-map': 0.3.6 - acorn: 8.14.0 + acorn: 8.14.1 commander: 2.20.3 source-map-support: 0.5.21 @@ -23705,9 +22406,9 @@ snapshots: tinyexec@0.3.2: {} - tinyglobby@0.2.12: + tinyglobby@0.2.13: dependencies: - fdir: 6.4.3(picomatch@4.0.2) + fdir: 6.4.4(picomatch@4.0.2) picomatch: 4.0.2 tinypool@1.0.2: {} @@ -23793,8 +22494,6 @@ snapshots: type-fest@0.21.3: {} - type-fest@2.19.0: {} - type-fest@4.33.0: {} type-is@1.6.18: @@ -23852,51 +22551,59 @@ snapshots: ufo@1.5.4: {} + ultrahtml@1.5.3: {} + unc-path-regex@0.1.2: {} uncrypto@0.1.3: {} unctx@2.4.1: dependencies: - acorn: 8.14.0 + acorn: 8.14.1 estree-walker: 3.0.3 magic-string: 0.30.17 - unplugin: 2.1.2 - - undici-types@5.28.4: {} + unplugin: 2.2.2 undici-types@6.20.0: {} + undici@6.21.2: {} + unenv@1.10.0: dependencies: - consola: 3.4.0 + consola: 3.4.2 defu: 6.1.4 mime: 3.0.0 node-fetch-native: 1.6.6 pathe: 1.1.2 + unenv@2.0.0-rc.15: + dependencies: + defu: 6.1.4 + exsolve: 1.0.4 + ohash: 2.0.11 + pathe: 2.0.3 + ufo: 1.5.4 + unicode-emoji-modifier-base@1.0.0: {} - unicorn-magic@0.1.0: {} + unicorn-magic@0.3.0: {} - unimport@3.14.6(rollup@4.39.0): + unimport@4.1.3: dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) - acorn: 8.14.0 + acorn: 8.14.1 escape-string-regexp: 5.0.0 estree-walker: 3.0.3 - fast-glob: 3.3.3 - local-pkg: 1.0.0 + local-pkg: 1.1.1 magic-string: 0.30.17 mlly: 1.7.4 pathe: 2.0.3 picomatch: 4.0.2 - pkg-types: 1.3.1 + pkg-types: 2.1.0 scule: 1.3.0 - strip-literal: 2.1.1 - unplugin: 1.16.1 - transitivePeerDependencies: - - rollup + strip-literal: 3.0.0 + tinyglobby: 0.2.13 + unplugin: 2.2.2 + unplugin-utils: 0.2.4 universalify@0.1.2: {} @@ -23906,55 +22613,55 @@ snapshots: unpipe@1.0.0: {} + unplugin-utils@0.2.4: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.2 + unplugin@1.0.1: dependencies: - acorn: 8.14.0 + acorn: 8.14.1 chokidar: 3.6.0 webpack-sources: 3.2.3 webpack-virtual-modules: 0.5.0 unplugin@1.16.1: dependencies: - acorn: 8.14.0 + acorn: 8.14.1 webpack-virtual-modules: 0.6.2 - unplugin@2.1.2: + unplugin@2.2.2: dependencies: - acorn: 8.14.0 + acorn: 8.14.1 webpack-virtual-modules: 0.6.2 - unstorage@1.14.4(db0@0.2.3)(ioredis@5.4.2): + unstorage@1.15.0(db0@0.3.1)(ioredis@5.6.0): dependencies: anymatch: 3.1.3 - chokidar: 3.6.0 + chokidar: 4.0.3 destr: 2.0.3 - h3: 1.13.0 + h3: 1.15.1 lru-cache: 10.4.3 node-fetch-native: 1.6.6 ofetch: 1.4.1 ufo: 1.5.4 optionalDependencies: - db0: 0.2.3 - ioredis: 5.4.2 + db0: 0.3.1 + ioredis: 5.6.0 untun@0.1.3: dependencies: citty: 0.1.6 - consola: 3.4.0 + consola: 3.4.2 pathe: 1.1.2 - untyped@1.5.2: + untyped@2.0.0: dependencies: - '@babel/core': 7.26.8 - '@babel/standalone': 7.26.7 - '@babel/types': 7.26.8 citty: 0.1.6 defu: 6.1.4 jiti: 2.4.2 knitwork: 1.2.0 scule: 1.3.0 - transitivePeerDependencies: - - supports-color unwasm@0.3.9: dependencies: @@ -23975,8 +22682,6 @@ snapshots: uqr@0.1.2: {} - uri-js-replace@1.0.1: {} - uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -23986,8 +22691,6 @@ snapshots: querystringify: 2.2.0 requires-port: 1.0.0 - urlpattern-polyfill@8.0.2: {} - use-callback-ref@1.3.3(@types/react@19.0.8)(react@19.0.0): dependencies: react: 19.0.0 @@ -24027,171 +22730,13 @@ snapshots: vary@1.1.2: {} - vinxi@0.5.1(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0): - dependencies: - '@babel/core': 7.26.8 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.8) - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.8) - '@types/micromatch': 4.0.9 - '@vinxi/listhen': 1.5.6 - boxen: 7.1.1 - chokidar: 3.6.0 - citty: 0.1.6 - consola: 3.4.0 - crossws: 0.3.3 - dax-sh: 0.39.2 - defu: 6.1.4 - es-module-lexer: 1.6.0 - esbuild: 0.20.2 - fast-glob: 3.3.3 - get-port-please: 3.1.2 - h3: 1.13.0 - hookable: 5.5.3 - http-proxy: 1.18.1 - micromatch: 4.0.8 - nitropack: 2.10.4(typescript@5.8.2) - node-fetch-native: 1.6.6 - path-to-regexp: 6.3.0 - pathe: 1.1.2 - radix3: 1.1.2 - resolve: 1.22.10 - serve-placeholder: 2.0.2 - serve-static: 1.16.2 - ufo: 1.5.4 - unctx: 2.4.1 - unenv: 1.10.0 - unstorage: 1.14.4(db0@0.2.3)(ioredis@5.4.2) - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - zod: 3.24.2 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@electric-sql/pglite' - - '@libsql/client' - - '@netlify/blobs' - - '@planetscale/database' - - '@types/node' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - better-sqlite3 - - db0 - - debug - - drizzle-orm - - encoding - - idb-keyval - - ioredis - - jiti - - less - - lightningcss - - mysql2 - - rolldown - - sass - - sass-embedded - - sqlite3 - - stylus - - sugarss - - supports-color - - terser - - tsx - - typescript - - uploadthing - - xml2js - - yaml - - vinxi@0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0): - dependencies: - '@babel/core': 7.26.8 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.8) - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.8) - '@types/micromatch': 4.0.9 - '@vinxi/listhen': 1.5.6 - boxen: 7.1.1 - chokidar: 3.6.0 - citty: 0.1.6 - consola: 3.4.0 - crossws: 0.3.3 - dax-sh: 0.39.2 - defu: 6.1.4 - es-module-lexer: 1.6.0 - esbuild: 0.20.2 - fast-glob: 3.3.3 - get-port-please: 3.1.2 - h3: 1.13.0 - hookable: 5.5.3 - http-proxy: 1.18.1 - micromatch: 4.0.8 - nitropack: 2.10.4(typescript@5.8.2) - node-fetch-native: 1.6.6 - path-to-regexp: 6.3.0 - pathe: 1.1.2 - radix3: 1.1.2 - resolve: 1.22.10 - serve-placeholder: 2.0.2 - serve-static: 1.16.2 - ufo: 1.5.4 - unctx: 2.4.1 - unenv: 1.10.0 - unstorage: 1.14.4(db0@0.2.3)(ioredis@5.4.2) - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - zod: 3.24.2 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@electric-sql/pglite' - - '@libsql/client' - - '@netlify/blobs' - - '@planetscale/database' - - '@types/node' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - better-sqlite3 - - db0 - - debug - - drizzle-orm - - encoding - - idb-keyval - - ioredis - - jiti - - less - - lightningcss - - mysql2 - - rolldown - - sass - - sass-embedded - - sqlite3 - - stylus - - sugarss - - supports-color - - terser - - tsx - - typescript - - uploadthing - - xml2js - - yaml - - vite-node@3.0.6(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0): + vite-node@3.0.6(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0): dependencies: cac: 6.7.14 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 es-module-lexer: 1.6.0 pathe: 2.0.3 - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' - jiti @@ -24206,50 +22751,50 @@ snapshots: - tsx - yaml - vite-plugin-dts@4.0.3(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)): + vite-plugin-dts@4.0.3(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)): dependencies: '@microsoft/api-extractor': 7.47.4(@types/node@22.13.4) - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) + '@rollup/pluginutils': 5.1.4(rollup@4.38.0) '@volar/typescript': 2.4.11 '@vue/language-core': 2.0.29(typescript@5.8.2) compare-versions: 6.1.1 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 kolorist: 1.8.0 local-pkg: 0.5.1 magic-string: 0.30.17 typescript: 5.8.2 vue-tsc: 2.0.29(typescript@5.8.2) optionalDependencies: - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' - rollup - supports-color - vite-plugin-dts@4.5.0(@types/node@22.13.4)(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)): + vite-plugin-dts@4.5.0(@types/node@22.13.4)(rollup@4.38.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)): dependencies: '@microsoft/api-extractor': 7.49.2(@types/node@22.13.4) - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) + '@rollup/pluginutils': 5.1.4(rollup@4.38.0) '@volar/typescript': 2.4.11 '@vue/language-core': 2.2.0(typescript@5.8.2) compare-versions: 6.1.1 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 kolorist: 1.8.0 local-pkg: 0.5.1 magic-string: 0.30.17 typescript: 5.8.2 optionalDependencies: - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' - rollup - supports-color - vite-plugin-externalize-deps@0.9.0(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)): + vite-plugin-externalize-deps@0.9.0(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)): dependencies: - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)): + vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)): dependencies: '@babel/core': 7.26.8 '@types/babel__core': 7.20.5 @@ -24257,67 +22802,70 @@ snapshots: merge-anything: 5.1.7 solid-js: 1.9.5 solid-refresh: 0.6.3(solid-js@1.9.5) - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - vitefu: 1.0.5(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + vite: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vitefu: 1.0.5(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) optionalDependencies: '@testing-library/jest-dom': 6.6.3 transitivePeerDependencies: - supports-color - vite-tsconfig-paths@5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)): + vite-tsconfig-paths@5.1.4(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)): dependencies: - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 globrex: 0.1.2 tsconfck: 3.1.4(typescript@5.8.2) optionalDependencies: - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) transitivePeerDependencies: - supports-color - typescript - vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0): + vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0): dependencies: - esbuild: 0.24.2 + esbuild: 0.25.2 + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 postcss: 8.5.3 - rollup: 4.39.0 + rollup: 4.38.0 + tinyglobby: 0.2.13 optionalDependencies: '@types/node': 22.13.4 fsevents: 2.3.3 jiti: 2.4.2 - lightningcss: 1.29.1 + lightningcss: 1.29.2 terser: 5.37.0 tsx: 4.19.2 yaml: 2.7.0 - vitefu@1.0.5(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)): + vitefu@1.0.5(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)): optionalDependencies: - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - vitest@3.0.6(@types/node@22.13.4)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@25.0.1)(lightningcss@1.29.1)(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0): + vitest@3.0.6(@types/node@22.13.4)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@25.0.1)(lightningcss@1.29.2)(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0): dependencies: '@vitest/expect': 3.0.6 - '@vitest/mocker': 3.0.6(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + '@vitest/mocker': 3.0.6(msw@2.7.0(@types/node@22.13.4)(typescript@5.8.2))(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) '@vitest/pretty-format': 3.0.6 '@vitest/runner': 3.0.6 '@vitest/snapshot': 3.0.6 '@vitest/spy': 3.0.6 '@vitest/utils': 3.0.6 chai: 5.2.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 expect-type: 1.1.0 magic-string: 0.30.17 pathe: 2.0.3 - std-env: 3.8.0 + std-env: 3.8.1 tinybench: 2.9.0 tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - vite-node: 3.0.6(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vite-node: 3.0.6(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.13.4 - '@vitest/browser': 3.0.6(@types/node@22.13.4)(playwright@1.52.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))(vitest@3.0.6) + '@vitest/browser': 3.0.6(@types/node@22.13.4)(playwright@1.52.0)(typescript@5.8.2)(vite@6.3.5(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))(vitest@3.0.6) '@vitest/ui': 3.0.6(vitest@3.0.6) jsdom: 25.0.1 transitivePeerDependencies: @@ -24338,14 +22886,14 @@ snapshots: vue-eslint-parser@9.4.3(eslint@9.22.0(jiti@2.4.2)): dependencies: - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 eslint: 9.22.0(jiti@2.4.2) eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 esquery: 1.6.0 lodash: 4.17.21 - semver: 7.7.0 + semver: 7.7.1 transitivePeerDependencies: - supports-color @@ -24353,7 +22901,7 @@ snapshots: dependencies: '@volar/typescript': 2.4.11 '@vue/language-core': 2.0.29(typescript@5.8.2) - semver: 7.7.0 + semver: 7.7.1 typescript: 5.8.2 w3c-xmlserializer@5.0.0: @@ -24373,8 +22921,6 @@ snapshots: dependencies: defaults: 1.0.4 - web-streams-polyfill@3.3.3: {} - web-vitals@4.2.4: {} webcrypto-core@1.8.1: @@ -24403,7 +22949,7 @@ snapshots: import-local: 3.2.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-merge: 5.10.0 optionalDependencies: webpack-dev-server: 5.2.0(webpack-cli@5.1.4)(webpack@5.97.1) @@ -24417,7 +22963,7 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.0 optionalDependencies: - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-dev-server@5.2.0(webpack-cli@5.1.4)(webpack@5.97.1): dependencies: @@ -24449,7 +22995,7 @@ snapshots: webpack-dev-middleware: 7.4.2(webpack@5.97.1) ws: 8.18.0 optionalDependencies: - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.0)(webpack@5.97.1) transitivePeerDependencies: - bufferutil @@ -24469,14 +23015,14 @@ snapshots: webpack-virtual-modules@0.6.2: {} - webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0): + webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.7 '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.14.0 + acorn: 8.14.1 browserslist: 4.24.4 chrome-trace-event: 1.0.4 enhanced-resolve: 5.18.1 @@ -24491,7 +23037,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)) + terser-webpack-plugin: 5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -24499,14 +23045,14 @@ snapshots: - esbuild - uglify-js - webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4): + webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.7 '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.14.0 + acorn: 8.14.1 browserslist: 4.24.4 chrome-trace-event: 1.0.4 enhanced-resolve: 5.18.1 @@ -24521,7 +23067,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack@5.97.1) + terser-webpack-plugin: 5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack@5.97.1) watchpack: 2.4.2 webpack-sources: 3.2.3 optionalDependencies: @@ -24563,19 +23109,11 @@ snapshots: dependencies: isexe: 2.0.0 - which@4.0.0: - dependencies: - isexe: 3.1.1 - why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 stackback: 0.0.2 - widest-line@4.0.1: - dependencies: - string-width: 5.1.2 - wildcard@2.0.1: {} word-wrap@1.2.5: {} @@ -24604,6 +23142,13 @@ snapshots: xml-name-validator@5.0.0: {} + xmlbuilder2@3.1.1: + dependencies: + '@oozcitak/dom': 1.15.10 + '@oozcitak/infra': 1.0.8 + '@oozcitak/util': 8.3.8 + js-yaml: 3.14.1 + xmlchars@2.2.0: {} y18n@5.0.8: {} @@ -24614,8 +23159,6 @@ snapshots: yallist@5.0.0: {} - yaml-ast-parser@0.0.43: {} - yaml@1.10.2: {} yaml@2.7.0: {} @@ -24648,6 +23191,18 @@ snapshots: yoctocolors-cjs@2.1.2: {} + youch-core@0.3.2: + dependencies: + '@poppinss/exception': 1.2.1 + error-stack-parser-es: 1.0.5 + + youch@4.1.0-beta.7: + dependencies: + '@poppinss/dumper': 0.6.3 + '@speed-highlight/core': 1.2.7 + cookie: 1.0.2 + youch-core: 0.3.2 + zip-stream@6.0.1: dependencies: archiver-utils: 5.0.2 diff --git a/scripts/generateLabelerConfig.mjs b/scripts/generateLabelerConfig.mjs index 6b02b962fc..e38ef6e323 100644 --- a/scripts/generateLabelerConfig.mjs +++ b/scripts/generateLabelerConfig.mjs @@ -8,7 +8,7 @@ function generateLabelerConfig() { * Pairs of package labels and their corresponding paths * @type {Array<[string, string]>} **/ - const pairs = [] + let pairs = [] // Add subfolders in the packages folder, i.e. packages/** fs.readdirSync(path.resolve('packages')) @@ -28,6 +28,9 @@ function generateLabelerConfig() { } }) + // Sort by package name in alphabetical order + pairs.sort((a, b) => a[0].localeCompare(b[0])) + // Always add the docs folder pairs.push(['documentation', 'docs/**/*']) diff --git a/scripts/publish.js b/scripts/publish.js index 430c3a3c41..0f8c7d0e98 100644 --- a/scripts/publish.js +++ b/scripts/publish.js @@ -92,21 +92,13 @@ await publish({ name: '@tanstack/solid-start', packageDir: 'packages/solid-start', }, - { - name: '@tanstack/solid-start-client', - packageDir: 'packages/solid-start-client', - }, - { - name: '@tanstack/solid-start-config', - packageDir: 'packages/solid-start-config', - }, { name: '@tanstack/solid-start-plugin', packageDir: 'packages/solid-start-plugin', }, { - name: '@tanstack/solid-start-router-manifest', - packageDir: 'packages/solid-start-router-manifest', + name: '@tanstack/solid-start-client', + packageDir: 'packages/solid-start-client', }, { name: '@tanstack/solid-start-server', @@ -136,45 +128,21 @@ await publish({ name: '@tanstack/react-start-server', packageDir: 'packages/react-start-server', }, - { - name: '@tanstack/start-config', - packageDir: 'packages/start-config', - }, - { - name: '@tanstack/react-start-config', - packageDir: 'packages/react-start-config', - }, - { - name: '@tanstack/start-api-routes', - packageDir: 'packages/start-api-routes', - }, { name: '@tanstack/start-server-functions-fetcher', packageDir: 'packages/start-server-functions-fetcher', }, - { - name: '@tanstack/start-server-functions-handler', - packageDir: 'packages/start-server-functions-handler', - }, { name: '@tanstack/start-server-functions-client', packageDir: 'packages/start-server-functions-client', }, - { - name: '@tanstack/start-server-functions-ssr', - packageDir: 'packages/start-server-functions-ssr', - }, { name: '@tanstack/start-server-functions-server', packageDir: 'packages/start-server-functions-server', }, { - name: '@tanstack/react-start-router-manifest', - packageDir: 'packages/react-start-router-manifest', - }, - { - name: '@tanstack/start', - packageDir: 'packages/start', + name: '@tanstack/start-plugin-core', + packageDir: 'packages/start-plugin-core', }, { name: '@tanstack/router-utils',