From ee6ca1d1d414c6ab78e1b09a6799b45b074e35cf Mon Sep 17 00:00:00 2001 From: TkDodo Date: Thu, 13 Nov 2025 11:22:07 +0100 Subject: [PATCH 1/2] feat: createServerEntry --- .../react/guide/server-entry-point.md | 39 +++++++++---------- .../react-start/src/default-entry/server.ts | 17 ++++---- .../solid-start/src/default-entry/server.ts | 17 ++++---- 3 files changed, 39 insertions(+), 34 deletions(-) diff --git a/docs/start/framework/react/guide/server-entry-point.md b/docs/start/framework/react/guide/server-entry-point.md index e80a3dc292..d90211ed28 100644 --- a/docs/start/framework/react/guide/server-entry-point.md +++ b/docs/start/framework/react/guide/server-entry-point.md @@ -8,20 +8,7 @@ title: Server Entry Point > [!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 `src/server.ts` file. - -```tsx -// src/server.ts -import handler, { type ServerEntry } from '@tanstack/react-start/server-entry' - -export default { - fetch(request) { - return handler.fetch(request) - }, -} satisfies ServerEntry -``` - -The default export must conform to the `ServerEntry` interface: +The Server Entry Point conforms to the [universal fetch handler](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/) format, which means the default export must conform to the `ServerEntry` interface: ```ts export default { @@ -30,6 +17,18 @@ export default { }, } ``` +TanStack Start exposes a wrapper to make creation type-safe. This is done in the `src/server.ts` file. + +```tsx +// src/server.ts +import handler, { createServerEntry } from '@tanstack/react-start/server-entry' + +export default createServerEntry({ + fetch(request) { + return handler.fetch(request) + }, +}) +``` 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 as well as for handling server routes and server function requests. @@ -44,7 +43,7 @@ import { defaultStreamHandler, defineHandlerCallback, } from '@tanstack/react-start/server' -import type { ServerEntry } from '@tanstack/react-start/server-entry' +import { createServerEntry } from '@tanstack/react-start/server-entry' const customHandler = defineHandlerCallback((ctx) => { // add custom logic here @@ -53,9 +52,9 @@ const customHandler = defineHandlerCallback((ctx) => { const fetch = createStartHandler(customHandler) -export default { +export default createServerEntry({ fetch, -} satisfies ServerEntry +}) ``` ## Request context @@ -65,7 +64,7 @@ When your server needs to pass additional, typed data into request handlers (for To add types for your request context, augment the `Register` interface from `@tanstack/react-start` with a `server.requestContext` property. The runtime `context` you pass to `handler.fetch` will then match that type. Example: ```tsx -import handler, { type ServerEntry } from '@tanstack/react-start/server-entry' +import handler, { createServerEntry } from '@tanstack/react-start/server-entry' type MyRequestContext = { hello: string @@ -80,11 +79,11 @@ declare module '@tanstack/react-start' { } } -export default { +export default createServerEntry({ async fetch(request) { return handler.fetch(request, { context: { hello: 'world', foo: 123 } }) }, -} satisfies ServerEntry +}) ``` ## Server Configuration diff --git a/packages/react-start/src/default-entry/server.ts b/packages/react-start/src/default-entry/server.ts index d24e2c4888..e0e0007301 100644 --- a/packages/react-start/src/default-entry/server.ts +++ b/packages/react-start/src/default-entry/server.ts @@ -7,12 +7,15 @@ import type { RequestHandler } from '@tanstack/react-start/server' const fetch = createStartHandler(defaultStreamHandler) -const serverEntry = { - // Providing `RequestHandler` from `@tanstack/react-start/server` is required so that the output types don't import it from `@tanstack/start-server-core` - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - fetch: fetch as RequestHandler, -} as const +// Providing `RequestHandler` from `@tanstack/react-start/server` is required so that the output types don't import it from `@tanstack/start-server-core` +export type ServerEntry = { fetch: RequestHandler } -export type ServerEntry = typeof serverEntry +export function createServerEntry(entry: ServerEntry): ServerEntry { + return { + async fetch(request) { + return await entry.fetch(request) + }, + } +} -export default serverEntry +export default createServerEntry({ fetch }) diff --git a/packages/solid-start/src/default-entry/server.ts b/packages/solid-start/src/default-entry/server.ts index d83d67e1e2..3bcd6706eb 100644 --- a/packages/solid-start/src/default-entry/server.ts +++ b/packages/solid-start/src/default-entry/server.ts @@ -7,12 +7,15 @@ import type { RequestHandler } from '@tanstack/solid-start/server' const fetch = createStartHandler(defaultStreamHandler) -const serverEntry = { - // Providing `RequestHandler` from `@tanstack/solid-start/server` is required so that the output types don't import it from `@tanstack/start-server-core` - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - fetch: fetch as RequestHandler, -} as const +// Providing `RequestHandler` from `@tanstack/solid-start/server` is required so that the output types don't import it from `@tanstack/start-server-core` +export type ServerEntry = { fetch: RequestHandler } -export type ServerEntry = typeof serverEntry +export function createServerEntry(entry: ServerEntry): ServerEntry { + return { + async fetch(request) { + return await entry.fetch(request) + }, + } +} -export default serverEntry +export default createServerEntry({ fetch }) From 6e37b298786580933e16922079e1d8467a4a2724 Mon Sep 17 00:00:00 2001 From: TkDodo Date: Thu, 13 Nov 2025 11:47:10 +0100 Subject: [PATCH 2/2] fix: forward all args from server entry point --- docs/start/framework/react/guide/server-entry-point.md | 7 +++++-- packages/react-start/src/default-entry/server.ts | 4 ++-- packages/solid-start/src/default-entry/server.ts | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/start/framework/react/guide/server-entry-point.md b/docs/start/framework/react/guide/server-entry-point.md index d90211ed28..a07014947e 100644 --- a/docs/start/framework/react/guide/server-entry-point.md +++ b/docs/start/framework/react/guide/server-entry-point.md @@ -8,15 +8,18 @@ title: Server Entry Point > [!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. -The Server Entry Point conforms to the [universal fetch handler](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/) format, which means the default export must conform to the `ServerEntry` interface: +The Server Entry Point supports the universal fetch handler format, commonly used by [Cloudflare Workers](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/) and other WinterCG-compatible runtimes. + +To ensure interoperability, the default export must conform to our `ServerEntry` interface: ```ts export default { - fetch(req: Request, opts?: RequestOptions): Promise { + fetch(req: Request, opts?: RequestOptions): Response | Promise { // ... }, } ``` + TanStack Start exposes a wrapper to make creation type-safe. This is done in the `src/server.ts` file. ```tsx diff --git a/packages/react-start/src/default-entry/server.ts b/packages/react-start/src/default-entry/server.ts index e0e0007301..8e734a7e49 100644 --- a/packages/react-start/src/default-entry/server.ts +++ b/packages/react-start/src/default-entry/server.ts @@ -12,8 +12,8 @@ export type ServerEntry = { fetch: RequestHandler } export function createServerEntry(entry: ServerEntry): ServerEntry { return { - async fetch(request) { - return await entry.fetch(request) + async fetch(...args) { + return await entry.fetch(...args) }, } } diff --git a/packages/solid-start/src/default-entry/server.ts b/packages/solid-start/src/default-entry/server.ts index 3bcd6706eb..b8f3105c6a 100644 --- a/packages/solid-start/src/default-entry/server.ts +++ b/packages/solid-start/src/default-entry/server.ts @@ -12,8 +12,8 @@ export type ServerEntry = { fetch: RequestHandler } export function createServerEntry(entry: ServerEntry): ServerEntry { return { - async fetch(request) { - return await entry.fetch(request) + async fetch(...args) { + return await entry.fetch(...args) }, } }