Skip to content

Commit e87340c

Browse files
committed
prerendering - sync #5476 to solid-start
1 parent a2aaf1f commit e87340c

File tree

6 files changed

+94
-9
lines changed

6 files changed

+94
-9
lines changed

e2e/solid-start/basic/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@
88
"dev:e2e": "vite dev",
99
"build": "vite build && tsc --noEmit",
1010
"build:spa": "MODE=spa vite build && tsc --noEmit",
11+
"build:prerender": "MODE=prerender vite build && tsc --noEmit",
1112
"start": "pnpx srvx --prod -s ../client dist/server/server.js",
1213
"start:spa": "node server.js",
14+
"test:e2e:startDummyServer": "node -e 'import(\"./tests/setup/global.setup.ts\").then(m => m.default())' &",
15+
"test:e2e:stopDummyServer": "node -e 'import(\"./tests/setup/global.teardown.ts\").then(m => m.default())'",
1316
"test:e2e:spaMode": "rm -rf port*.txt; MODE=spa playwright test --project=chromium",
1417
"test:e2e:ssrMode": "rm -rf port*.txt; playwright test --project=chromium",
15-
"test:e2e": "pnpm run test:e2e:spaMode && pnpm run test:e2e:ssrMode"
18+
"test:e2e:prerender": "rm -rf port*.txt; MODE=prerender playwright test --project=chromium",
19+
"test:e2e": "pnpm run test:e2e:spaMode && pnpm run test:e2e:ssrMode && pnpm run test:e2e:prerender"
1620
},
1721
"dependencies": {
1822
"@tanstack/solid-router": "workspace:^",

e2e/solid-start/basic/playwright.config.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import {
33
getDummyServerPort,
44
getTestServerPort,
55
} from '@tanstack/router-e2e-utils'
6-
import packageJson from './package.json' with { type: 'json' }
76
import { isSpaMode } from './tests/utils/isSpaMode'
7+
import { isPrerender } from './tests/utils/isPrerender'
8+
import packageJson from './package.json' with { type: 'json' }
89

910
const PORT = await getTestServerPort(
1011
`${packageJson.name}${isSpaMode ? '_spa' : ''}`,
@@ -16,15 +17,21 @@ const EXTERNAL_PORT = await getDummyServerPort(packageJson.name)
1617
const baseURL = `http://localhost:${PORT}`
1718
const spaModeCommand = `pnpm build:spa && pnpm start:spa`
1819
const ssrModeCommand = `pnpm build && pnpm start`
20+
const prerenderModeCommand = `pnpm run test:e2e:startDummyServer && pnpm build:prerender && pnpm run test:e2e:stopDummyServer && pnpm start`
1921

22+
const getCommand = () => {
23+
if (isSpaMode) return spaModeCommand
24+
if (isPrerender) return prerenderModeCommand
25+
return ssrModeCommand
26+
}
2027
console.log('running in spa mode: ', isSpaMode.toString())
28+
console.log('running in prerender mode: ', isPrerender.toString())
2129
/**
2230
* See https://playwright.dev/docs/test-configuration.
2331
*/
2432
export default defineConfig({
2533
testDir: './tests',
2634
workers: 1,
27-
2835
reporter: [['line']],
2936

3037
globalSetup: './tests/setup/global.setup.ts',
@@ -36,7 +43,7 @@ export default defineConfig({
3643
},
3744

3845
webServer: {
39-
command: isSpaMode ? spaModeCommand : ssrModeCommand,
46+
command: getCommand(),
4047
url: baseURL,
4148
reuseExistingServer: !process.env.CI,
4249
stdout: 'pipe',
@@ -53,7 +60,9 @@ export default defineConfig({
5360
projects: [
5461
{
5562
name: 'chromium',
56-
use: { ...devices['Desktop Chrome'] },
63+
use: {
64+
...devices['Desktop Chrome'],
65+
},
5766
},
5867
],
5968
})
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { existsSync, readFileSync } from 'node:fs'
2+
import { join } from 'node:path'
3+
import { expect } from '@playwright/test'
4+
import { test } from '@tanstack/router-e2e-utils'
5+
import { isPrerender } from './utils/isPrerender'
6+
7+
test.describe('Prerender Static Path Discovery', () => {
8+
test.skip(!isPrerender, 'Skipping since not in prerender mode')
9+
test.describe('Build Output Verification', () => {
10+
test('should automatically discover and prerender static routes', () => {
11+
// Check that static routes were automatically discovered and prerendered
12+
const distDir = join(process.cwd(), 'dist', 'client')
13+
14+
// These static routes should be automatically discovered and prerendered
15+
expect(existsSync(join(distDir, 'index.html'))).toBe(true)
16+
expect(existsSync(join(distDir, 'posts/index.html'))).toBe(true)
17+
expect(existsSync(join(distDir, 'users/index.html'))).toBe(true)
18+
expect(existsSync(join(distDir, 'deferred/index.html'))).toBe(true)
19+
expect(existsSync(join(distDir, 'scripts/index.html'))).toBe(true)
20+
expect(existsSync(join(distDir, 'inline-scripts/index.html'))).toBe(true)
21+
expect(existsSync(join(distDir, '대한민국/index.html'))).toBe(true)
22+
23+
// Pathless layouts should NOT be prerendered (they start with _)
24+
expect(existsSync(join(distDir, '_layout', 'index.html'))).toBe(false) // /_layout
25+
26+
// API routes should NOT be prerendered
27+
28+
expect(existsSync(join(distDir, 'api', 'users', 'index.html'))).toBe(
29+
false,
30+
) // /api/users
31+
})
32+
})
33+
34+
test.describe('Static Files Verification', () => {
35+
test('should contain prerendered content in posts.html', () => {
36+
const distDir = join(process.cwd(), 'dist', 'client')
37+
expect(existsSync(join(distDir, 'posts/index.html'))).toBe(true)
38+
39+
// "Select a post." should be in the prerendered HTML
40+
const html = readFileSync(join(distDir, 'posts/index.html'), 'utf-8')
41+
expect(html).toContain('Select a post.')
42+
})
43+
44+
test('should contain prerendered content in users.html', () => {
45+
const distDir = join(process.cwd(), 'dist', 'client')
46+
expect(existsSync(join(distDir, 'users/index.html'))).toBe(true)
47+
48+
// "Select a user." should be in the prerendered HTML
49+
const html = readFileSync(join(distDir, 'users/index.html'), 'utf-8')
50+
expect(html).toContain('Select a user.')
51+
})
52+
})
53+
})

e2e/solid-start/basic/tests/search-params.spec.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { expect } from '@playwright/test'
22
import { test } from '@tanstack/router-e2e-utils'
3-
import { isSpaMode } from '../tests/utils/isSpaMode'
3+
import { isSpaMode } from 'tests/utils/isSpaMode'
4+
import { isPrerender } from './utils/isPrerender'
45
import type { Response } from '@playwright/test'
56

67
function expectRedirect(response: Response | null, endsWith: string) {
@@ -26,9 +27,11 @@ test.describe('/search-params/loader-throws-redirect', () => {
2627
page,
2728
}) => {
2829
const response = await page.goto('/search-params/loader-throws-redirect')
29-
if (!isSpaMode) {
30+
31+
if (!isSpaMode && !isPrerender) {
3032
expectRedirect(response, '/search-params/loader-throws-redirect?step=a')
3133
}
34+
3235
await expect(page.getByTestId('search-param')).toContainText('a')
3336
expect(page.url().endsWith('/search-params/loader-throws-redirect?step=a'))
3437
})
@@ -50,7 +53,7 @@ test.describe('/search-params/default', () => {
5053
page,
5154
}) => {
5255
const response = await page.goto('/search-params/default')
53-
if (!isSpaMode) {
56+
if (!isSpaMode && !isPrerender) {
5457
expectRedirect(response, '/search-params/default?default=d1')
5558
}
5659
await expect(page.getByTestId('search-default')).toContainText('d1')
@@ -63,7 +66,7 @@ test.describe('/search-params/default', () => {
6366
test('Directly visiting the route with search param set', async ({
6467
page,
6568
}) => {
66-
const response = await page.goto('/search-params/default/?default=d2')
69+
const response = await page.goto('/search-params/default?default=d2')
6770
expectNoRedirect(response)
6871

6972
await expect(page.getByTestId('search-default')).toContainText('d2')
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const isPrerender: boolean = process.env.MODE === 'prerender'

e2e/solid-start/basic/vite.config.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import tsConfigPaths from 'vite-tsconfig-paths'
33
import { tanstackStart } from '@tanstack/solid-start/plugin/vite'
44
import viteSolid from 'vite-plugin-solid'
55
import { isSpaMode } from './tests/utils/isSpaMode'
6+
import { isPrerender } from './tests/utils/isPrerender'
67

78
const spaModeConfiguration = {
89
enabled: true,
@@ -11,6 +12,19 @@ const spaModeConfiguration = {
1112
},
1213
}
1314

15+
const prerenderConfiguration = {
16+
enabled: true,
17+
filter: (page: { path: string }) =>
18+
![
19+
'/this-route-does-not-exist',
20+
'/redirect',
21+
'/i-do-not-exist',
22+
'/not-found/via-beforeLoad',
23+
'/not-found/via-loader',
24+
].some((p) => page.path.includes(p)),
25+
maxRedirects: 100,
26+
}
27+
1428
export default defineConfig({
1529
server: {
1630
port: 3000,
@@ -22,6 +36,7 @@ export default defineConfig({
2236
// @ts-ignore we want to keep one test with verboseFileRoutes off even though the option is hidden
2337
tanstackStart({
2438
spa: isSpaMode ? spaModeConfiguration : undefined,
39+
prerender: isPrerender ? prerenderConfiguration : undefined,
2540
}),
2641
viteSolid({ ssr: true }),
2742
],

0 commit comments

Comments
 (0)