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
-
-
- server function middleware context is merged correctly
-
+
+ server route middleware context is merged correctly
+
+
+ -
+ server route methods
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