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 2edc524065d..f67ad6c608d 100644 --- a/e2e/react-start/server-functions/tests/server-functions.spec.ts +++ b/e2e/react-start/server-functions/tests/server-functions.spec.ts @@ -450,6 +450,8 @@ test('primitives', async ({ page }) => { const testCases = await page .locator('[data-testid^="expected-"]') .elementHandles() + expect(testCases.length).not.toBe(0) + for (const testCase of testCases) { const testId = await testCase.getAttribute('data-testid') diff --git a/e2e/react-start/server-routes/package.json b/e2e/react-start/server-routes/package.json index 1f764d6cdf8..fca76e6a1bb 100644 --- a/e2e/react-start/server-routes/package.json +++ b/e2e/react-start/server-routes/package.json @@ -11,8 +11,10 @@ "test:e2e": "playwright test --project=chromium" }, "dependencies": { + "@tanstack/react-query": "5.66.0", "@tanstack/react-router": "workspace:^", "@tanstack/react-router-devtools": "workspace:^", + "@tanstack/react-router-ssr-query": "workspace:^", "@tanstack/react-start": "workspace:^", "js-cookie": "^3.0.5", "react": "^19.0.0", diff --git a/e2e/react-start/server-routes/src/routeTree.gen.ts b/e2e/react-start/server-routes/src/routeTree.gen.ts index b5a408c7ae7..8caf1ab9179 100644 --- a/e2e/react-start/server-routes/src/routeTree.gen.ts +++ b/e2e/react-start/server-routes/src/routeTree.gen.ts @@ -9,23 +9,46 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { Route as rootRouteImport } from './routes/__root' -import { Route as MergeServerFnMiddlewareContextRouteImport } from './routes/merge-server-fn-middleware-context' +import { Route as MergeMiddlewareContextRouteImport } from './routes/merge-middleware-context' +import { Route as MethodsRouteRouteImport } from './routes/methods/route' import { Route as IndexRouteImport } from './routes/index' +import { Route as MethodsIndexRouteImport } from './routes/methods/index' +import { Route as MethodsOnlyAnyRouteImport } from './routes/methods/only-any' +import { Route as ApiOnlyAnyRouteImport } from './routes/api/only-any' import { Route as ApiMiddlewareContextRouteImport } from './routes/api/middleware-context' import { Route as ApiParamsFooRouteRouteImport } from './routes/api/params/$foo/route' import { Route as ApiParamsFooBarRouteImport } from './routes/api/params/$foo/$bar' -const MergeServerFnMiddlewareContextRoute = - MergeServerFnMiddlewareContextRouteImport.update({ - id: '/merge-server-fn-middleware-context', - path: '/merge-server-fn-middleware-context', - getParentRoute: () => rootRouteImport, - } as any) +const MergeMiddlewareContextRoute = MergeMiddlewareContextRouteImport.update({ + id: '/merge-middleware-context', + path: '/merge-middleware-context', + getParentRoute: () => rootRouteImport, +} as any) +const MethodsRouteRoute = MethodsRouteRouteImport.update({ + id: '/methods', + path: '/methods', + getParentRoute: () => rootRouteImport, +} as any) const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRouteImport, } as any) +const MethodsIndexRoute = MethodsIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => MethodsRouteRoute, +} as any) +const MethodsOnlyAnyRoute = MethodsOnlyAnyRouteImport.update({ + id: '/only-any', + path: '/only-any', + getParentRoute: () => MethodsRouteRoute, +} as any) +const ApiOnlyAnyRoute = ApiOnlyAnyRouteImport.update({ + id: '/api/only-any', + path: '/api/only-any', + getParentRoute: () => rootRouteImport, +} as any) const ApiMiddlewareContextRoute = ApiMiddlewareContextRouteImport.update({ id: '/api/middleware-context', path: '/api/middleware-context', @@ -44,23 +67,34 @@ const ApiParamsFooBarRoute = ApiParamsFooBarRouteImport.update({ export interface FileRoutesByFullPath { '/': typeof IndexRoute - '/merge-server-fn-middleware-context': typeof MergeServerFnMiddlewareContextRoute + '/methods': typeof MethodsRouteRouteWithChildren + '/merge-middleware-context': typeof MergeMiddlewareContextRoute '/api/middleware-context': typeof ApiMiddlewareContextRoute + '/api/only-any': typeof ApiOnlyAnyRoute + '/methods/only-any': typeof MethodsOnlyAnyRoute + '/methods/': typeof MethodsIndexRoute '/api/params/$foo': typeof ApiParamsFooRouteRouteWithChildren '/api/params/$foo/$bar': typeof ApiParamsFooBarRoute } export interface FileRoutesByTo { '/': typeof IndexRoute - '/merge-server-fn-middleware-context': typeof MergeServerFnMiddlewareContextRoute + '/merge-middleware-context': typeof MergeMiddlewareContextRoute '/api/middleware-context': typeof ApiMiddlewareContextRoute + '/api/only-any': typeof ApiOnlyAnyRoute + '/methods/only-any': typeof MethodsOnlyAnyRoute + '/methods': typeof MethodsIndexRoute '/api/params/$foo': typeof ApiParamsFooRouteRouteWithChildren '/api/params/$foo/$bar': typeof ApiParamsFooBarRoute } export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute - '/merge-server-fn-middleware-context': typeof MergeServerFnMiddlewareContextRoute + '/methods': typeof MethodsRouteRouteWithChildren + '/merge-middleware-context': typeof MergeMiddlewareContextRoute '/api/middleware-context': typeof ApiMiddlewareContextRoute + '/api/only-any': typeof ApiOnlyAnyRoute + '/methods/only-any': typeof MethodsOnlyAnyRoute + '/methods/': typeof MethodsIndexRoute '/api/params/$foo': typeof ApiParamsFooRouteRouteWithChildren '/api/params/$foo/$bar': typeof ApiParamsFooBarRoute } @@ -68,40 +102,60 @@ export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath fullPaths: | '/' - | '/merge-server-fn-middleware-context' + | '/methods' + | '/merge-middleware-context' | '/api/middleware-context' + | '/api/only-any' + | '/methods/only-any' + | '/methods/' | '/api/params/$foo' | '/api/params/$foo/$bar' fileRoutesByTo: FileRoutesByTo to: | '/' - | '/merge-server-fn-middleware-context' + | '/merge-middleware-context' | '/api/middleware-context' + | '/api/only-any' + | '/methods/only-any' + | '/methods' | '/api/params/$foo' | '/api/params/$foo/$bar' id: | '__root__' | '/' - | '/merge-server-fn-middleware-context' + | '/methods' + | '/merge-middleware-context' | '/api/middleware-context' + | '/api/only-any' + | '/methods/only-any' + | '/methods/' | '/api/params/$foo' | '/api/params/$foo/$bar' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute - MergeServerFnMiddlewareContextRoute: typeof MergeServerFnMiddlewareContextRoute + MethodsRouteRoute: typeof MethodsRouteRouteWithChildren + MergeMiddlewareContextRoute: typeof MergeMiddlewareContextRoute ApiMiddlewareContextRoute: typeof ApiMiddlewareContextRoute + ApiOnlyAnyRoute: typeof ApiOnlyAnyRoute ApiParamsFooRouteRoute: typeof ApiParamsFooRouteRouteWithChildren } declare module '@tanstack/react-router' { interface FileRoutesByPath { - '/merge-server-fn-middleware-context': { - id: '/merge-server-fn-middleware-context' - path: '/merge-server-fn-middleware-context' - fullPath: '/merge-server-fn-middleware-context' - preLoaderRoute: typeof MergeServerFnMiddlewareContextRouteImport + '/merge-middleware-context': { + id: '/merge-middleware-context' + path: '/merge-middleware-context' + fullPath: '/merge-middleware-context' + preLoaderRoute: typeof MergeMiddlewareContextRouteImport + parentRoute: typeof rootRouteImport + } + '/methods': { + id: '/methods' + path: '/methods' + fullPath: '/methods' + preLoaderRoute: typeof MethodsRouteRouteImport parentRoute: typeof rootRouteImport } '/': { @@ -111,6 +165,27 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRouteImport } + '/methods/': { + id: '/methods/' + path: '/' + fullPath: '/methods/' + preLoaderRoute: typeof MethodsIndexRouteImport + parentRoute: typeof MethodsRouteRoute + } + '/methods/only-any': { + id: '/methods/only-any' + path: '/only-any' + fullPath: '/methods/only-any' + preLoaderRoute: typeof MethodsOnlyAnyRouteImport + parentRoute: typeof MethodsRouteRoute + } + '/api/only-any': { + id: '/api/only-any' + path: '/api/only-any' + fullPath: '/api/only-any' + preLoaderRoute: typeof ApiOnlyAnyRouteImport + parentRoute: typeof rootRouteImport + } '/api/middleware-context': { id: '/api/middleware-context' path: '/api/middleware-context' @@ -135,6 +210,20 @@ declare module '@tanstack/react-router' { } } +interface MethodsRouteRouteChildren { + MethodsOnlyAnyRoute: typeof MethodsOnlyAnyRoute + MethodsIndexRoute: typeof MethodsIndexRoute +} + +const MethodsRouteRouteChildren: MethodsRouteRouteChildren = { + MethodsOnlyAnyRoute: MethodsOnlyAnyRoute, + MethodsIndexRoute: MethodsIndexRoute, +} + +const MethodsRouteRouteWithChildren = MethodsRouteRoute._addFileChildren( + MethodsRouteRouteChildren, +) + interface ApiParamsFooRouteRouteChildren { ApiParamsFooBarRoute: typeof ApiParamsFooBarRoute } @@ -148,8 +237,10 @@ const ApiParamsFooRouteRouteWithChildren = const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, - MergeServerFnMiddlewareContextRoute: MergeServerFnMiddlewareContextRoute, + MethodsRouteRoute: MethodsRouteRouteWithChildren, + MergeMiddlewareContextRoute: MergeMiddlewareContextRoute, ApiMiddlewareContextRoute: ApiMiddlewareContextRoute, + ApiOnlyAnyRoute: ApiOnlyAnyRoute, ApiParamsFooRouteRoute: ApiParamsFooRouteRouteWithChildren, } export const routeTree = rootRouteImport diff --git a/e2e/react-start/server-routes/src/router.tsx b/e2e/react-start/server-routes/src/router.tsx index 1a1d8822d20..d19308cc303 100644 --- a/e2e/react-start/server-routes/src/router.tsx +++ b/e2e/react-start/server-routes/src/router.tsx @@ -1,9 +1,12 @@ import { createRouter } from '@tanstack/react-router' +import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query' +import { QueryClient } from '@tanstack/react-query' import { routeTree } from './routeTree.gen' import { DefaultCatchBoundary } from './components/DefaultCatchBoundary' import { NotFound } from './components/NotFound' export function getRouter() { + const queryClient = new QueryClient() const router = createRouter({ routeTree, defaultPreload: 'intent', @@ -11,6 +14,7 @@ export function getRouter() { defaultNotFoundComponent: () => , scrollRestoration: true, }) + setupRouterSsrQueryIntegration({ router, queryClient }) return router } diff --git a/e2e/react-start/server-routes/src/routes/api/only-any.ts b/e2e/react-start/server-routes/src/routes/api/only-any.ts new file mode 100644 index 00000000000..d99a060f7bc --- /dev/null +++ b/e2e/react-start/server-routes/src/routes/api/only-any.ts @@ -0,0 +1,18 @@ +import { createFileRoute } from '@tanstack/react-router' +import { json } from '@tanstack/react-start' + +export const Route = createFileRoute('/api/only-any')({ + server: { + handlers: { + ANY: ({ request }) => { + return json( + { + handler: 'ANY', + method: request.method, + }, + { headers: { 'X-HANDLER': 'ANY', 'X-METHOD': request.method } }, + ) + }, + }, + }, +}) diff --git a/e2e/react-start/server-routes/src/routes/index.tsx b/e2e/react-start/server-routes/src/routes/index.tsx index ef9dc9ab85d..1cbd7ef0be4 100644 --- a/e2e/react-start/server-routes/src/routes/index.tsx +++ b/e2e/react-start/server-routes/src/routes/index.tsx @@ -1,4 +1,4 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/')({ component: Home, @@ -10,9 +10,12 @@ function Home() {

Server Routes E2E tests

diff --git a/e2e/react-start/server-routes/src/routes/merge-server-fn-middleware-context.tsx b/e2e/react-start/server-routes/src/routes/merge-middleware-context.tsx similarity index 89% rename from e2e/react-start/server-routes/src/routes/merge-server-fn-middleware-context.tsx rename to e2e/react-start/server-routes/src/routes/merge-middleware-context.tsx index 65c409cc8d1..1150ba206c9 100644 --- a/e2e/react-start/server-routes/src/routes/merge-server-fn-middleware-context.tsx +++ b/e2e/react-start/server-routes/src/routes/merge-middleware-context.tsx @@ -1,11 +1,11 @@ import { createFileRoute } from '@tanstack/react-router' import * as React from 'react' -export const Route = createFileRoute('/merge-server-fn-middleware-context')({ - component: () => , +export const Route = createFileRoute('/merge-middleware-context')({ + component: MergeMiddlewareContext, }) -function MergeServerFnMiddlewareContext() { +function MergeMiddlewareContext() { const [apiResponse, setApiResponse] = React.useState(null) const fetchMiddlewareContext = async () => { @@ -21,7 +21,7 @@ function MergeServerFnMiddlewareContext() { return (
-

Merge Server Function Middleware Context Test

+

Merge Server Route Middleware Context Test

+ ) +} diff --git a/e2e/react-start/server-routes/src/routes/methods/only-any.tsx b/e2e/react-start/server-routes/src/routes/methods/only-any.tsx new file mode 100644 index 00000000000..215cb390ea7 --- /dev/null +++ b/e2e/react-start/server-routes/src/routes/methods/only-any.tsx @@ -0,0 +1,63 @@ +import { createFileRoute } from '@tanstack/react-router' +import { useQuery } from '@tanstack/react-query' +import * as React from 'react' + +export const Route = createFileRoute('/methods/only-any')({ + ssr: false, + component: RouteComponent, +}) + +const HttpMethods = [ + 'GET', + 'POST', + 'PUT', + 'DELETE', + 'PATCH', + 'OPTIONS', + 'HEAD', +] as const +type HttpMethods = (typeof HttpMethods)[number] +function Test({ method }: { method: HttpMethods }) { + const queryFn = React.useCallback(async () => { + const response = await fetch(`/api/only-any`, { + method, + }) + try { + const json = (await response.json()) as Promise<{ + method: HttpMethods + handler: HttpMethods & 'ANY' + }> + return json + } catch (e) {} + // handle HEAD and OPTIONS that have no body + const result = { + handler: response.headers.get('x-handler') as HttpMethods & 'ANY', + method: response.headers.get('x-method') as HttpMethods, + } + return result + }, [method]) + + const query = useQuery({ queryKey: [method], queryFn }) + return ( +
+

method={method}

+

expected

+
{method}
+

result

+ {query.data ? ( +
{query.data.method}
+ ) : null} +
+ ) +} + +function RouteComponent() { + return ( +
+

Server Route has only ANY handler

+ {HttpMethods.map((method) => ( + + ))} +
+ ) +} diff --git a/e2e/react-start/server-routes/src/routes/methods/route.tsx b/e2e/react-start/server-routes/src/routes/methods/route.tsx new file mode 100644 index 00000000000..27531509ba1 --- /dev/null +++ b/e2e/react-start/server-routes/src/routes/methods/route.tsx @@ -0,0 +1,14 @@ +import { Outlet, createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/methods')({ + component: RouteComponent, +}) + +function RouteComponent() { + return ( +
+

Server Routes Methods E2E tests

+ +
+ ) +} diff --git a/e2e/react-start/server-routes/tests/server-routes.spec.ts b/e2e/react-start/server-routes/tests/server-routes.spec.ts index 33176a23fd2..f3a80a5a469 100644 --- a/e2e/react-start/server-routes/tests/server-routes.spec.ts +++ b/e2e/react-start/server-routes/tests/server-routes.spec.ts @@ -1,8 +1,8 @@ import { expect } from '@playwright/test' import { test } from '@tanstack/router-e2e-utils' -test('merge-server-fn-middleware-context', async ({ page }) => { - await page.goto('/merge-server-fn-middleware-context') +test('merge-middleware-context', async ({ page }) => { + await page.goto('/merge-middleware-context') await page.waitForLoadState('networkidle') @@ -16,3 +16,32 @@ test('merge-server-fn-middleware-context', async ({ page }) => { expect(contextResult).toContain('testParent') expect(contextResult).toContain('test') }) + +test.describe('methods', () => { + test('only ANY', async ({ page }) => { + await page.goto('/methods/only-any') + + // wait for page to be loaded by waiting for the route component to be rendered + await expect(page.getByTestId('route-component')).toBeInViewport() + + const testCases = await page + .locator('[data-testid^="expected-"]') + .elementHandles() + expect(testCases.length).not.toBe(0) + for (const testCase of testCases) { + const testId = await testCase.getAttribute('data-testid') + + if (!testId) { + throw new Error('testcase is missing data-testid') + } + + const suffix = testId.replace('expected-', '') + + const expected = + (await page.getByTestId(`expected-${suffix}`).textContent()) || '' + expect(expected).not.toBe('') + + await expect(page.getByTestId(`result-${suffix}`)).toContainText(expected) + } + }) +}) diff --git a/packages/router-core/src/route.ts b/packages/router-core/src/route.ts index 4524e3b541d..b67651cbb0f 100644 --- a/packages/router-core/src/route.ts +++ b/packages/router-core/src/route.ts @@ -161,7 +161,7 @@ export type ResolveRequiredParams = { } export type ResolveOptionalParams = { - [K in ParsePathParams['optional']]?: T + [K in ParsePathParams['optional']]?: T | undefined } export type ResolveParams< @@ -441,7 +441,7 @@ export type ResolveAllSSR< > = unknown extends TParentRoute ? ResolveSSR : unknown extends TSSR - ? TParentRoute['types']['ssr'] + ? TParentRoute['types']['allSsr'] : ResolveSSR export type ResolveFullPath< diff --git a/packages/server-functions-plugin/src/index.ts b/packages/server-functions-plugin/src/index.ts index e2d29b7822c..fa8bbbf0ca6 100644 --- a/packages/server-functions-plugin/src/index.ts +++ b/packages/server-functions-plugin/src/index.ts @@ -82,12 +82,12 @@ export function TanStackServerFnPlugin( }) => { if (serverDevEnv) { const root = serverDevEnv.config.root - + const rootWithTrailingSlash = withTrailingSlash(root) let file = extractedFilename - if (extractedFilename.startsWith(withTrailingSlash(root))) { - file = extractedFilename.slice(root.length) + if (extractedFilename.startsWith(rootWithTrailingSlash)) { + file = extractedFilename.slice(rootWithTrailingSlash.length) } - file = `/@id${file[0] === '/' ? '' : '/'}${file}` + file = `/@id/${file}` const serverFn: { file: string diff --git a/packages/start-client-core/src/serverRoute.ts b/packages/start-client-core/src/serverRoute.ts index 0c874f48f86..17c129aa3a7 100644 --- a/packages/start-client-core/src/serverRoute.ts +++ b/packages/start-client-core/src/serverRoute.ts @@ -287,7 +287,7 @@ export interface CreateMethodFnOpts< TMethodHeadMiddlewares, TServerContext, > { - ALL?: RouteMethodHandler< + ANY?: RouteMethodHandler< TRegister, TParentRoute, TFullPath, @@ -425,7 +425,7 @@ export type ResolveAllServerContext< > export type RouteMethod = - | 'ALL' + | 'ANY' | 'GET' | 'POST' | 'PUT' diff --git a/packages/start-plugin-core/src/prerender.ts b/packages/start-plugin-core/src/prerender.ts index a11216416c0..79a20e60458 100644 --- a/packages/start-plugin-core/src/prerender.ts +++ b/packages/start-plugin-core/src/prerender.ts @@ -174,7 +174,8 @@ export async function prerender({ : cleanPagePath const htmlPath = - cleanPagePath.endsWith('/') || prerenderOptions.autoSubfolderIndex + cleanPagePath.endsWith('/') || + (prerenderOptions.autoSubfolderIndex ?? true) ? joinURL(cleanPagePath, 'index.html') : cleanPagePath + '.html' @@ -253,10 +254,18 @@ export async function writeBundleToDisk({ bundle: Rollup.OutputBundle outDir: string }) { + const createdDirs = new Set() + for (const [fileName, asset] of Object.entries(bundle)) { const fullPath = path.join(outDir, fileName) + const dir = path.dirname(fullPath) const content = asset.type === 'asset' ? asset.source : asset.code - await fsp.mkdir(path.dirname(fullPath), { recursive: true }) + + if (!createdDirs.has(dir)) { + await fsp.mkdir(dir, { recursive: true }) + createdDirs.add(dir) + } + await fsp.writeFile(fullPath, content) } } diff --git a/packages/start-plugin-core/src/start-manifest-plugin/plugin.ts b/packages/start-plugin-core/src/start-manifest-plugin/plugin.ts index bcf0ed73956..fae50e164ad 100644 --- a/packages/start-plugin-core/src/start-manifest-plugin/plugin.ts +++ b/packages/start-plugin-core/src/start-manifest-plugin/plugin.ts @@ -8,11 +8,21 @@ import type { GetConfigFn } from '../plugin' import type { PluginOption, Rollup } from 'vite' import type { RouterManagedTag } from '@tanstack/router-core' -export const getCSSRecursively = ( +const getCSSRecursively = ( chunk: Rollup.OutputChunk, chunksByFileName: Map, basePath: string, + cache: Map>, + visited = new Set(), ) => { + if (visited.has(chunk)) { + return [] + } + visited.add(chunk) + const cachedResult = cache.get(chunk) + if (cachedResult) { + return cachedResult + } const result: Array = [] // Get all css imports from the file @@ -32,11 +42,18 @@ export const getCSSRecursively = ( const importedChunk = chunksByFileName.get(importedFileName) if (importedChunk) { result.push( - ...getCSSRecursively(importedChunk, chunksByFileName, basePath), + ...getCSSRecursively( + importedChunk, + chunksByFileName, + basePath, + cache, + visited, + ), ) } } + cache.set(chunk, result) return result } @@ -82,6 +99,11 @@ export function startManifestPlugin(opts: { // i.e what's located in `src/routeTree.gen.ts` const routeTreeRoutes = globalThis.TSS_ROUTES_MANIFEST.routes + const cssPerChunkCache = new Map< + Rollup.OutputChunk, + Array + >() + // This is where hydration will start, from when the SSR'd page reaches the browser. let entryFile: Rollup.OutputChunk | undefined @@ -161,6 +183,7 @@ export function startManifestPlugin(opts: { chunk, chunksByFileName, resolvedStartConfig.viteAppBase, + cssPerChunkCache, ) routeTreeRoutes[routeId] = { @@ -188,6 +211,7 @@ export function startManifestPlugin(opts: { entryFile, chunksByFileName, resolvedStartConfig.viteAppBase, + cssPerChunkCache, ) routeTreeRoutes[rootRouteId]!.assets = [ diff --git a/packages/start-server-core/src/createStartHandler.ts b/packages/start-server-core/src/createStartHandler.ts index d0fd84e8f43..3860c6a9667 100644 --- a/packages/start-server-core/src/createStartHandler.ts +++ b/packages/start-server-core/src/createStartHandler.ts @@ -378,39 +378,25 @@ async function handleServerRoutes({ }) : server.handlers - const requestMethod = request.method.toLowerCase() + const requestMethod = request.method.toUpperCase() as RouteMethod // Attempt to find the method in the handlers - let method = Object.keys(handlers).find( - (method) => method.toLowerCase() === requestMethod, - ) - - // If no method is found, attempt to find the 'all' method - if (!method) { - method = Object.keys(handlers).find( - (method) => method.toLowerCase() === 'all', - ) - ? 'all' - : undefined - } + const handler = handlers[requestMethod] ?? handlers['ANY'] // If a method is found, execute the handler - if (method) { - const handler = handlers[method as RouteMethod] - if (handler) { - const mayDefer = !!foundRoute.options.component - if (typeof handler === 'function') { - middlewares.push(handlerToMiddleware(handler, mayDefer)) - } else { - const { middleware } = handler - if (middleware && middleware.length) { - middlewares.push( - ...flattenMiddlewares(middleware).map((d) => d.options.server), - ) - } - if (handler.handler) { - middlewares.push(handlerToMiddleware(handler.handler, mayDefer)) - } + if (handler) { + const mayDefer = !!foundRoute.options.component + if (typeof handler === 'function') { + middlewares.push(handlerToMiddleware(handler, mayDefer)) + } else { + const { middleware } = handler + if (middleware && middleware.length) { + middlewares.push( + ...flattenMiddlewares(middleware).map((d) => d.options.server), + ) + } + if (handler.handler) { + middlewares.push(handlerToMiddleware(handler.handler, mayDefer)) } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c297c258fe6..68d7e42453c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1721,12 +1721,18 @@ importers: e2e/react-start/server-routes: dependencies: + '@tanstack/react-query': + specifier: 5.66.0 + version: 5.66.0(react@19.0.0) '@tanstack/react-router': specifier: workspace:* version: link:../../../packages/react-router '@tanstack/react-router-devtools': specifier: workspace:^ version: link:../../../packages/react-router-devtools + '@tanstack/react-router-ssr-query': + specifier: workspace:* + version: link:../../../packages/react-router-ssr-query '@tanstack/react-start': specifier: workspace:* version: link:../../../packages/react-start