Skip to content

Commit c05572e

Browse files
fix: streaming (#6175)
1 parent f8d9759 commit c05572e

40 files changed

+3900
-318
lines changed

docs/router/framework/react/api/router/RouterEventsType.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ type RouterEvents = {
4444
}
4545
onInjectedHtml: {
4646
type: 'onInjectedHtml'
47-
promise: Promise<string>
4847
}
4948
onRendered: {
5049
type: 'onRendered'
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
node_modules
2+
package-lock.json
3+
yarn.lock
4+
5+
.DS_Store
6+
.cache
7+
.env
8+
.vercel
9+
.output
10+
/build/
11+
/api/
12+
/server/build
13+
/public/build
14+
.env.sentry-build-plugin
15+
/test-results/
16+
/playwright-report/
17+
/blob-report/
18+
/playwright/.cache/
19+
/dist/
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "tanstack-react-start-e2e-streaming-ssr",
3+
"private": true,
4+
"sideEffects": false,
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite dev --port 3000",
8+
"dev:e2e": "vite dev",
9+
"build": "vite build && tsc --noEmit",
10+
"start": "pnpx srvx --prod -s ../client dist/server/server.js",
11+
"test:e2e": "rm -rf port*.txt; playwright test --project=chromium"
12+
},
13+
"dependencies": {
14+
"@tanstack/react-query": "^5.80.7",
15+
"@tanstack/react-router": "workspace:^",
16+
"@tanstack/react-router-ssr-query": "workspace:^",
17+
"@tanstack/react-start": "workspace:^",
18+
"react": "^19.0.0",
19+
"react-dom": "^19.0.0",
20+
"vite": "^7.1.7"
21+
},
22+
"devDependencies": {
23+
"@playwright/test": "^1.50.1",
24+
"@tanstack/router-e2e-utils": "workspace:^",
25+
"@types/node": "^22.10.2",
26+
"@types/react": "^19.0.8",
27+
"@types/react-dom": "^19.0.3",
28+
"srvx": "^0.9.8",
29+
"typescript": "^5.7.2"
30+
}
31+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { defineConfig, devices } from '@playwright/test'
2+
import { getTestServerPort } from '@tanstack/router-e2e-utils'
3+
import packageJson from './package.json' with { type: 'json' }
4+
5+
const PORT = await getTestServerPort(packageJson.name)
6+
const baseURL = `http://localhost:${PORT}`
7+
8+
/**
9+
* See https://playwright.dev/docs/test-configuration.
10+
*/
11+
export default defineConfig({
12+
testDir: './tests',
13+
workers: 1,
14+
15+
reporter: [['line']],
16+
17+
use: {
18+
/* Base URL to use in actions like `await page.goto('/')`. */
19+
baseURL,
20+
},
21+
22+
webServer: {
23+
command: `VITE_SERVER_PORT=${PORT} pnpm build && PORT=${PORT} VITE_SERVER_PORT=${PORT} pnpm start`,
24+
url: baseURL,
25+
reuseExistingServer: !process.env.CI,
26+
stdout: 'pipe',
27+
},
28+
29+
projects: [
30+
{
31+
name: 'chromium',
32+
use: { ...devices['Desktop Chrome'] },
33+
},
34+
],
35+
})
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
/* eslint-disable */
2+
3+
// @ts-nocheck
4+
5+
// noinspection JSUnusedGlobalSymbols
6+
7+
// This file was automatically generated by TanStack Router.
8+
// You should NOT make any changes in this file as it will be overwritten.
9+
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
10+
11+
import { Route as rootRouteImport } from './routes/__root'
12+
import { Route as SyncOnlyRouteImport } from './routes/sync-only'
13+
import { Route as StreamRouteImport } from './routes/stream'
14+
import { Route as SlowRenderRouteImport } from './routes/slow-render'
15+
import { Route as QueryHeavyRouteImport } from './routes/query-heavy'
16+
import { Route as NestedDeferredRouteImport } from './routes/nested-deferred'
17+
import { Route as ManyPromisesRouteImport } from './routes/many-promises'
18+
import { Route as FastSerialRouteImport } from './routes/fast-serial'
19+
import { Route as DeferredRouteImport } from './routes/deferred'
20+
import { Route as ConcurrentRouteImport } from './routes/concurrent'
21+
import { Route as IndexRouteImport } from './routes/index'
22+
23+
const SyncOnlyRoute = SyncOnlyRouteImport.update({
24+
id: '/sync-only',
25+
path: '/sync-only',
26+
getParentRoute: () => rootRouteImport,
27+
} as any)
28+
const StreamRoute = StreamRouteImport.update({
29+
id: '/stream',
30+
path: '/stream',
31+
getParentRoute: () => rootRouteImport,
32+
} as any)
33+
const SlowRenderRoute = SlowRenderRouteImport.update({
34+
id: '/slow-render',
35+
path: '/slow-render',
36+
getParentRoute: () => rootRouteImport,
37+
} as any)
38+
const QueryHeavyRoute = QueryHeavyRouteImport.update({
39+
id: '/query-heavy',
40+
path: '/query-heavy',
41+
getParentRoute: () => rootRouteImport,
42+
} as any)
43+
const NestedDeferredRoute = NestedDeferredRouteImport.update({
44+
id: '/nested-deferred',
45+
path: '/nested-deferred',
46+
getParentRoute: () => rootRouteImport,
47+
} as any)
48+
const ManyPromisesRoute = ManyPromisesRouteImport.update({
49+
id: '/many-promises',
50+
path: '/many-promises',
51+
getParentRoute: () => rootRouteImport,
52+
} as any)
53+
const FastSerialRoute = FastSerialRouteImport.update({
54+
id: '/fast-serial',
55+
path: '/fast-serial',
56+
getParentRoute: () => rootRouteImport,
57+
} as any)
58+
const DeferredRoute = DeferredRouteImport.update({
59+
id: '/deferred',
60+
path: '/deferred',
61+
getParentRoute: () => rootRouteImport,
62+
} as any)
63+
const ConcurrentRoute = ConcurrentRouteImport.update({
64+
id: '/concurrent',
65+
path: '/concurrent',
66+
getParentRoute: () => rootRouteImport,
67+
} as any)
68+
const IndexRoute = IndexRouteImport.update({
69+
id: '/',
70+
path: '/',
71+
getParentRoute: () => rootRouteImport,
72+
} as any)
73+
74+
export interface FileRoutesByFullPath {
75+
'/': typeof IndexRoute
76+
'/concurrent': typeof ConcurrentRoute
77+
'/deferred': typeof DeferredRoute
78+
'/fast-serial': typeof FastSerialRoute
79+
'/many-promises': typeof ManyPromisesRoute
80+
'/nested-deferred': typeof NestedDeferredRoute
81+
'/query-heavy': typeof QueryHeavyRoute
82+
'/slow-render': typeof SlowRenderRoute
83+
'/stream': typeof StreamRoute
84+
'/sync-only': typeof SyncOnlyRoute
85+
}
86+
export interface FileRoutesByTo {
87+
'/': typeof IndexRoute
88+
'/concurrent': typeof ConcurrentRoute
89+
'/deferred': typeof DeferredRoute
90+
'/fast-serial': typeof FastSerialRoute
91+
'/many-promises': typeof ManyPromisesRoute
92+
'/nested-deferred': typeof NestedDeferredRoute
93+
'/query-heavy': typeof QueryHeavyRoute
94+
'/slow-render': typeof SlowRenderRoute
95+
'/stream': typeof StreamRoute
96+
'/sync-only': typeof SyncOnlyRoute
97+
}
98+
export interface FileRoutesById {
99+
__root__: typeof rootRouteImport
100+
'/': typeof IndexRoute
101+
'/concurrent': typeof ConcurrentRoute
102+
'/deferred': typeof DeferredRoute
103+
'/fast-serial': typeof FastSerialRoute
104+
'/many-promises': typeof ManyPromisesRoute
105+
'/nested-deferred': typeof NestedDeferredRoute
106+
'/query-heavy': typeof QueryHeavyRoute
107+
'/slow-render': typeof SlowRenderRoute
108+
'/stream': typeof StreamRoute
109+
'/sync-only': typeof SyncOnlyRoute
110+
}
111+
export interface FileRouteTypes {
112+
fileRoutesByFullPath: FileRoutesByFullPath
113+
fullPaths:
114+
| '/'
115+
| '/concurrent'
116+
| '/deferred'
117+
| '/fast-serial'
118+
| '/many-promises'
119+
| '/nested-deferred'
120+
| '/query-heavy'
121+
| '/slow-render'
122+
| '/stream'
123+
| '/sync-only'
124+
fileRoutesByTo: FileRoutesByTo
125+
to:
126+
| '/'
127+
| '/concurrent'
128+
| '/deferred'
129+
| '/fast-serial'
130+
| '/many-promises'
131+
| '/nested-deferred'
132+
| '/query-heavy'
133+
| '/slow-render'
134+
| '/stream'
135+
| '/sync-only'
136+
id:
137+
| '__root__'
138+
| '/'
139+
| '/concurrent'
140+
| '/deferred'
141+
| '/fast-serial'
142+
| '/many-promises'
143+
| '/nested-deferred'
144+
| '/query-heavy'
145+
| '/slow-render'
146+
| '/stream'
147+
| '/sync-only'
148+
fileRoutesById: FileRoutesById
149+
}
150+
export interface RootRouteChildren {
151+
IndexRoute: typeof IndexRoute
152+
ConcurrentRoute: typeof ConcurrentRoute
153+
DeferredRoute: typeof DeferredRoute
154+
FastSerialRoute: typeof FastSerialRoute
155+
ManyPromisesRoute: typeof ManyPromisesRoute
156+
NestedDeferredRoute: typeof NestedDeferredRoute
157+
QueryHeavyRoute: typeof QueryHeavyRoute
158+
SlowRenderRoute: typeof SlowRenderRoute
159+
StreamRoute: typeof StreamRoute
160+
SyncOnlyRoute: typeof SyncOnlyRoute
161+
}
162+
163+
declare module '@tanstack/react-router' {
164+
interface FileRoutesByPath {
165+
'/sync-only': {
166+
id: '/sync-only'
167+
path: '/sync-only'
168+
fullPath: '/sync-only'
169+
preLoaderRoute: typeof SyncOnlyRouteImport
170+
parentRoute: typeof rootRouteImport
171+
}
172+
'/stream': {
173+
id: '/stream'
174+
path: '/stream'
175+
fullPath: '/stream'
176+
preLoaderRoute: typeof StreamRouteImport
177+
parentRoute: typeof rootRouteImport
178+
}
179+
'/slow-render': {
180+
id: '/slow-render'
181+
path: '/slow-render'
182+
fullPath: '/slow-render'
183+
preLoaderRoute: typeof SlowRenderRouteImport
184+
parentRoute: typeof rootRouteImport
185+
}
186+
'/query-heavy': {
187+
id: '/query-heavy'
188+
path: '/query-heavy'
189+
fullPath: '/query-heavy'
190+
preLoaderRoute: typeof QueryHeavyRouteImport
191+
parentRoute: typeof rootRouteImport
192+
}
193+
'/nested-deferred': {
194+
id: '/nested-deferred'
195+
path: '/nested-deferred'
196+
fullPath: '/nested-deferred'
197+
preLoaderRoute: typeof NestedDeferredRouteImport
198+
parentRoute: typeof rootRouteImport
199+
}
200+
'/many-promises': {
201+
id: '/many-promises'
202+
path: '/many-promises'
203+
fullPath: '/many-promises'
204+
preLoaderRoute: typeof ManyPromisesRouteImport
205+
parentRoute: typeof rootRouteImport
206+
}
207+
'/fast-serial': {
208+
id: '/fast-serial'
209+
path: '/fast-serial'
210+
fullPath: '/fast-serial'
211+
preLoaderRoute: typeof FastSerialRouteImport
212+
parentRoute: typeof rootRouteImport
213+
}
214+
'/deferred': {
215+
id: '/deferred'
216+
path: '/deferred'
217+
fullPath: '/deferred'
218+
preLoaderRoute: typeof DeferredRouteImport
219+
parentRoute: typeof rootRouteImport
220+
}
221+
'/concurrent': {
222+
id: '/concurrent'
223+
path: '/concurrent'
224+
fullPath: '/concurrent'
225+
preLoaderRoute: typeof ConcurrentRouteImport
226+
parentRoute: typeof rootRouteImport
227+
}
228+
'/': {
229+
id: '/'
230+
path: '/'
231+
fullPath: '/'
232+
preLoaderRoute: typeof IndexRouteImport
233+
parentRoute: typeof rootRouteImport
234+
}
235+
}
236+
}
237+
238+
const rootRouteChildren: RootRouteChildren = {
239+
IndexRoute: IndexRoute,
240+
ConcurrentRoute: ConcurrentRoute,
241+
DeferredRoute: DeferredRoute,
242+
FastSerialRoute: FastSerialRoute,
243+
ManyPromisesRoute: ManyPromisesRoute,
244+
NestedDeferredRoute: NestedDeferredRoute,
245+
QueryHeavyRoute: QueryHeavyRoute,
246+
SlowRenderRoute: SlowRenderRoute,
247+
StreamRoute: StreamRoute,
248+
SyncOnlyRoute: SyncOnlyRoute,
249+
}
250+
export const routeTree = rootRouteImport
251+
._addFileChildren(rootRouteChildren)
252+
._addFileTypes<FileRouteTypes>()
253+
254+
import type { getRouter } from './router.tsx'
255+
import type { createStart } from '@tanstack/react-start'
256+
declare module '@tanstack/react-start' {
257+
interface Register {
258+
ssr: true
259+
router: Awaited<ReturnType<typeof getRouter>>
260+
}
261+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { QueryClient } from '@tanstack/react-query'
2+
import { createRouter } from '@tanstack/react-router'
3+
import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query'
4+
import { routeTree } from './routeTree.gen'
5+
6+
export function getRouter() {
7+
const queryClient = new QueryClient()
8+
const router = createRouter({
9+
routeTree,
10+
context: { queryClient },
11+
scrollRestoration: true,
12+
})
13+
setupRouterSsrQueryIntegration({
14+
router,
15+
queryClient,
16+
})
17+
return router
18+
}

0 commit comments

Comments
 (0)