Skip to content

Commit e0d7ee0

Browse files
authored
Fix Edge SSR routes (#39594)
Currently Edge SSR routes are added to both `routedPages` (catch-all page render routes) and `edgeRoutesSet` (catch-all edge function routes). This causes the request to be handled by both and results in an error (the Node server can't execute the Edge SSR route as a regular page). Another fix is to make sure Edge Function routes are sorted too, so `/foo` can be caught before dynamic ones like `/[id]`. ## Bug - [ ] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm lint` - [ ] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
1 parent 6791e75 commit e0d7ee0

File tree

5 files changed

+80
-22
lines changed

5 files changed

+80
-22
lines changed

packages/next/server/dev/next-dev-server.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,12 +382,13 @@ export default class DevServer extends Server {
382382
page: pageName,
383383
pageRuntime: staticInfo.runtime,
384384
onClient: () => {},
385-
onServer: () => {},
385+
onServer: () => {
386+
routedPages.push(pageName)
387+
},
386388
onEdgeServer: () => {
387389
edgeRoutesSet.add(pageName)
388390
},
389391
})
390-
routedPages.push(pageName)
391392
}
392393

393394
if (envChange) {

packages/next/server/next-server.ts

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,10 @@ import { removeTrailingSlash } from '../shared/lib/router/utils/remove-trailing-
8484
import { getNextPathnameInfo } from '../shared/lib/router/utils/get-next-pathname-info'
8585
import { bodyStreamToNodeStream, getClonableBody } from './body-streams'
8686
import { checkIsManualRevalidate } from './api-utils'
87-
import { isDynamicRoute } from '../shared/lib/router/utils'
8887
import { shouldUseReactRoot } from './utils'
8988
import ResponseCache from './response-cache'
9089
import { IncrementalCache } from './lib/incremental-cache'
90+
import { getSortedRoutes } from '../shared/lib/router/utils/sorted-routes'
9191

9292
if (shouldUseReactRoot) {
9393
;(process.env as any).__NEXT_REACT_ROOT = 'true'
@@ -1151,10 +1151,13 @@ export default class NextNodeServer extends BaseServer {
11511151
return []
11521152
}
11531153

1154-
return Object.keys(manifest.functions).map((page) => ({
1155-
match: getMiddlewareMatcher(manifest.functions[page]),
1156-
page,
1157-
}))
1154+
// Make sure to sort function routes too.
1155+
return getSortedRoutes(Object.keys(manifest.functions)).map((page) => {
1156+
return {
1157+
match: getMiddlewareMatcher(manifest.functions[page]),
1158+
page,
1159+
}
1160+
})
11581161
}
11591162

11601163
protected getEdgeRoutes(): RoutingItem[] {
@@ -1371,22 +1374,13 @@ export default class NextNodeServer extends BaseServer {
13711374
const normalizedPathname = removeTrailingSlash(pathname || '')
13721375
let page = normalizedPathname
13731376
let params: Params | undefined = undefined
1374-
let pageFound = !isDynamicRoute(page)
1375-
1376-
if (this.dynamicRoutes) {
1377-
for (const dynamicRoute of this.dynamicRoutes) {
1378-
params = dynamicRoute.match(normalizedPathname) || undefined
1379-
if (params) {
1380-
page = dynamicRoute.page
1381-
pageFound = true
1382-
break
1383-
}
1384-
}
1385-
}
13861377

1387-
if (!pageFound) {
1388-
return {
1389-
finished: false,
1378+
for (const edgeFunction of edgeFunctions) {
1379+
const matched = edgeFunction.match(page)
1380+
if (matched) {
1381+
params = matched
1382+
page = edgeFunction.page
1383+
break
13901384
}
13911385
}
13921386

test/e2e/switchable-runtime/index.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,43 @@ describe('Switchable runtime', () => {
7070
expect(devMiddlewareManifest).toEqual({})
7171
})
7272

73+
it('should sort edge SSR routes correctly', async () => {
74+
const res = await fetchViaHTTP(next.url, `/edge/foo`)
75+
const html = await res.text()
76+
77+
// /edge/foo should be caught before /edge/[id]
78+
expect(html).toContain(`to /edge/[id]`)
79+
})
80+
81+
it('should be able to navigate between edge SSR routes without any errors', async () => {
82+
const res = await fetchViaHTTP(next.url, `/edge/foo`)
83+
const html = await res.text()
84+
85+
// /edge/foo should be caught before /edge/[id]
86+
expect(html).toContain(`to /edge/[id]`)
87+
88+
const browser = await webdriver(context.appPort, '/edge/foo')
89+
90+
await browser.waitForElementByCss('a').click()
91+
92+
// on /edge/[id]
93+
await check(
94+
() => browser.eval('document.documentElement.innerHTML'),
95+
/to \/edge\/foo/
96+
)
97+
98+
await browser.waitForElementByCss('a').click()
99+
100+
// on /edge/foo
101+
await check(
102+
() => browser.eval('document.documentElement.innerHTML'),
103+
/to \/edge\/\[id\]/
104+
)
105+
106+
expect(context.stdout).not.toContain('self is not defined')
107+
expect(context.stderr).not.toContain('self is not defined')
108+
})
109+
73110
it.skip('should support client side navigation to ssr rsc pages', async () => {
74111
let flightRequest = null
75112

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import Link from 'next/link'
2+
3+
export default function Page() {
4+
return (
5+
<div>
6+
<Link href="/edge/foo">to /edge/foo</Link>
7+
</div>
8+
)
9+
}
10+
11+
export const config = {
12+
runtime: 'experimental-edge',
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import Link from 'next/link'
2+
3+
export default function Page() {
4+
return (
5+
<div>
6+
<Link href="/edge/123">to /edge/[id]</Link>
7+
</div>
8+
)
9+
}
10+
11+
export const config = {
12+
runtime: 'experimental-edge',
13+
}

0 commit comments

Comments
 (0)