Skip to content

Commit 9da5517

Browse files
authored
feat: prerender with vite preview server (#5921)
1 parent 5e7ad48 commit 9da5517

38 files changed

+12356
-422
lines changed

e2e/react-start/basic-cloudflare/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"react-dom": "^19.0.0"
2121
},
2222
"devDependencies": {
23-
"@cloudflare/vite-plugin": "^1.13.7",
23+
"@cloudflare/vite-plugin": "^1.15.1",
2424
"@playwright/test": "^1.50.1",
2525
"@tailwindcss/postcss": "^4.1.15",
2626
"@tanstack/router-e2e-utils": "workspace:^",
@@ -33,6 +33,6 @@
3333
"typescript": "^5.7.2",
3434
"vite": "^7.1.7",
3535
"vite-tsconfig-paths": "^5.1.4",
36-
"wrangler": "^4.40.2"
36+
"wrangler": "^4.49.1"
3737
}
3838
}

e2e/react-start/basic-cloudflare/src/routeTree.gen.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@
99
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
1010

1111
import { Route as rootRouteImport } from './routes/__root'
12+
import { Route as StaticRouteImport } from './routes/static'
1213
import { Route as IndexRouteImport } from './routes/index'
1314

15+
const StaticRoute = StaticRouteImport.update({
16+
id: '/static',
17+
path: '/static',
18+
getParentRoute: () => rootRouteImport,
19+
} as any)
1420
const IndexRoute = IndexRouteImport.update({
1521
id: '/',
1622
path: '/',
@@ -19,28 +25,39 @@ const IndexRoute = IndexRouteImport.update({
1925

2026
export interface FileRoutesByFullPath {
2127
'/': typeof IndexRoute
28+
'/static': typeof StaticRoute
2229
}
2330
export interface FileRoutesByTo {
2431
'/': typeof IndexRoute
32+
'/static': typeof StaticRoute
2533
}
2634
export interface FileRoutesById {
2735
__root__: typeof rootRouteImport
2836
'/': typeof IndexRoute
37+
'/static': typeof StaticRoute
2938
}
3039
export interface FileRouteTypes {
3140
fileRoutesByFullPath: FileRoutesByFullPath
32-
fullPaths: '/'
41+
fullPaths: '/' | '/static'
3342
fileRoutesByTo: FileRoutesByTo
34-
to: '/'
35-
id: '__root__' | '/'
43+
to: '/' | '/static'
44+
id: '__root__' | '/' | '/static'
3645
fileRoutesById: FileRoutesById
3746
}
3847
export interface RootRouteChildren {
3948
IndexRoute: typeof IndexRoute
49+
StaticRoute: typeof StaticRoute
4050
}
4151

4252
declare module '@tanstack/react-router' {
4353
interface FileRoutesByPath {
54+
'/static': {
55+
id: '/static'
56+
path: '/static'
57+
fullPath: '/static'
58+
preLoaderRoute: typeof StaticRouteImport
59+
parentRoute: typeof rootRouteImport
60+
}
4461
'/': {
4562
id: '/'
4663
path: '/'
@@ -53,6 +70,7 @@ declare module '@tanstack/react-router' {
5370

5471
const rootRouteChildren: RootRouteChildren = {
5572
IndexRoute: IndexRoute,
73+
StaticRoute: StaticRoute,
5674
}
5775
export const routeTree = rootRouteImport
5876
._addFileChildren(rootRouteChildren)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { createFileRoute } from '@tanstack/react-router'
2+
import { createServerFn } from '@tanstack/react-start'
3+
import { env } from 'cloudflare:workers'
4+
5+
export const Route = createFileRoute('/static')({
6+
loader: () => getData(),
7+
component: StaticPage,
8+
})
9+
10+
const getData = createServerFn().handler(() => {
11+
return {
12+
myVar: env.MY_VAR,
13+
}
14+
})
15+
16+
function StaticPage() {
17+
const data = Route.useLoaderData()
18+
19+
return (
20+
<div>
21+
<h1 data-testid="static-heading">Static Page</h1>
22+
<p data-testid="static-content">The value is {data.myVar}</p>
23+
</div>
24+
)
25+
}

e2e/react-start/basic-cloudflare/tests/app.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { existsSync } from 'node:fs'
2+
import { join } from 'node:path'
13
import { expect } from '@playwright/test'
24
import { test } from '@tanstack/router-e2e-utils'
35

@@ -14,3 +16,16 @@ test('returns the correct value from a Cloudflare binding', async ({
1416
await page.goto('/')
1517
await expect(page.getByTestId('myVar')).toHaveText('Hello from Cloudflare')
1618
})
19+
20+
test('prerender with Cloudflare Workers runtime', async ({ page }) => {
21+
// Verify the static page was prerendered during build
22+
const distDir = join(process.cwd(), 'dist', 'client')
23+
expect(existsSync(join(distDir, 'static', 'index.html'))).toBe(true)
24+
25+
// Verify the page loads correctly
26+
await page.goto('/static')
27+
await expect(page.getByTestId('static-heading')).toHaveText('Static Page')
28+
await expect(page.getByTestId('static-content')).toHaveText(
29+
'The value is Hello from Cloudflare',
30+
)
31+
})

e2e/react-start/basic-cloudflare/vite.config.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ export default defineConfig({
1010
projects: ['./tsconfig.json'],
1111
}),
1212
cloudflare({ viteEnvironment: { name: 'ssr' }, inspectorPort: false }),
13-
tanstackStart(),
13+
tanstackStart({
14+
prerender: {
15+
enabled: true,
16+
filter: (page) => page.path === '/static',
17+
},
18+
}),
1419
viteReact(),
1520
],
1621
})

0 commit comments

Comments
 (0)