Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle redirects in new router #40396

Merged
merged 36 commits into from Sep 20, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
2d8104b
Add redirect() to new router
timneutkens Sep 9, 2022
cbca8c2
Add client-side redirect
timneutkens Sep 9, 2022
42ad643
Use object instead of error class
timneutkens Sep 9, 2022
cd5ec64
Merge branch 'canary' of github.com:vercel/next.js into add/redirect-…
timneutkens Sep 14, 2022
29d8568
Add tests for redirect in next.config.js
timneutkens Sep 14, 2022
b92b6bf
Add test for redirect in middleware
timneutkens Sep 14, 2022
4f73221
Ensure prefetch error does not crash the app
timneutkens Sep 14, 2022
6d42511
Merge branch 'canary' of github.com:vercel/next.js into add/redirect-…
timneutkens Sep 15, 2022
3d54f6b
Enable test that passes already
timneutkens Sep 15, 2022
fa28b18
Enable test that passes
timneutkens Sep 15, 2022
ca1df00
Fix type err
timneutkens Sep 15, 2022
60a952c
Merge branch 'canary' of github.com:vercel/next.js into add/redirect-…
timneutkens Sep 19, 2022
f5d3d28
Add canonicalUrl to fetchServerResponse
timneutkens Sep 19, 2022
91344e7
Fix test id
timneutkens Sep 19, 2022
2087e11
Move vercel analytics test to separate file
timneutkens Sep 19, 2022
900afec
Fix experimental_use type
timneutkens Sep 19, 2022
3f4373c
Add handling for redirected server url
timneutkens Sep 19, 2022
1ffbdd8
Skip tests that are not passing yet
timneutkens Sep 19, 2022
cdf4116
Fix ts errors
timneutkens Sep 19, 2022
7b7681a
Remove console.log
timneutkens Sep 19, 2022
4fc0cd4
Finish comment
timneutkens Sep 19, 2022
6492d39
Change infinitePromise to leverage `use`
timneutkens Sep 19, 2022
99a1bbb
Leverage use to get router instance
timneutkens Sep 19, 2022
4a437ab
Update tests
timneutkens Sep 19, 2022
4a88637
Merge branch 'canary' of github.com:vercel/next.js into add/redirect-…
timneutkens Sep 19, 2022
a17f11b
Rename file
timneutkens Sep 19, 2022
ac12057
Change page to client component
timneutkens Sep 19, 2022
c4f1b18
Only skip one test
timneutkens Sep 19, 2022
5c58f42
Merge branch 'canary' of github.com:vercel/next.js into add/redirect-…
timneutkens Sep 19, 2022
232fdc1
Add source to error handler
timneutkens Sep 20, 2022
c448661
Merge branch 'canary' of github.com:vercel/next.js into add/redirect-…
timneutkens Sep 20, 2022
d18ffca
Hide all cases of DynamicServerError
timneutkens Sep 20, 2022
373b7f5
Fix errors during build
timneutkens Sep 20, 2022
1b49efa
Fix additional build errors
timneutkens Sep 20, 2022
1da73c0
Fix tests
timneutkens Sep 20, 2022
47e1d6d
Merge branch 'canary' into add/redirect-new-router
kodiakhq[bot] Sep 20, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions packages/next/client/components/redirect.ts
@@ -0,0 +1,14 @@
export const REDIRECT_ERROR_CODE = 'NEXT_REDIRECT'
timneutkens marked this conversation as resolved.
Show resolved Hide resolved

class Redirect extends Error {
timneutkens marked this conversation as resolved.
Show resolved Hide resolved
url: string
code: typeof REDIRECT_ERROR_CODE = REDIRECT_ERROR_CODE
constructor(url: string) {
// Message is not used.
super('redirect')
this.url = url
}
}
export function redirect(url: string) {
throw new Redirect(url)
}
21 changes: 20 additions & 1 deletion packages/next/server/app-render.tsx
Expand Up @@ -27,6 +27,7 @@ import {
} from '../build/webpack/plugins/flight-manifest-plugin'
import { FlushEffectsContext } from '../client/components/hooks-client'
import type { ComponentsType } from '../build/webpack/loaders/next-app-loader'
import { REDIRECT_ERROR_CODE } from '../client/components/redirect'

// this needs to be required lazily so that `next-server` can set
// the env before we require
Expand Down Expand Up @@ -1189,6 +1190,10 @@ export async function renderToHTMLOrFlight(
flushEffectsToHead: true,
})
} catch (err) {
if (err.code === REDIRECT_ERROR_CODE) {
throw err
}

// TODO-APP: show error overlay in development. `element` should probably be wrapped in AppRouter for this case.
const renderStream = await renderToInitialStream({
ReactDOMServer,
Expand Down Expand Up @@ -1221,5 +1226,19 @@ export async function renderToHTMLOrFlight(
}
}

return new RenderResult(await bodyResult())
try {
return new RenderResult(await bodyResult())
} catch (err) {
if (err.code === REDIRECT_ERROR_CODE) {
;(renderOpts as any).pageData = {
pageProps: {
__N_REDIRECT: err.url,
__N_REDIRECT_STATUS: 307,
},
}
;(renderOpts as any).isRedirect = true
return RenderResult.fromStatic('')
}
throw err
}
}
@@ -0,0 +1,6 @@
import { redirect } from 'next/dist/client/components/redirect'

export default function Page() {
redirect('/redirect/result')
return <></>
}
3 changes: 3 additions & 0 deletions test/e2e/app-dir/app/app/redirect/result/page.server.js
@@ -0,0 +1,3 @@
export default function Page() {
return <h1 id="result-page">Result Page</h1>
}
@@ -0,0 +1,6 @@
import { redirect } from 'next/dist/client/components/redirect'

export default function Page() {
redirect('/redirect/result')
return <></>
}
18 changes: 18 additions & 0 deletions test/e2e/app-dir/index.test.ts
Expand Up @@ -1417,6 +1417,24 @@ describe('app dir', () => {
expect(errors).toInclude('Error during SSR')
})
})

describe('redirect', () => {
it('should redirect in a server component', async () => {
const browser = await webdriver(next.url, '/redirect/servercomponent')
await browser.waitForElementByCss('#result-page')
expect(await browser.elementByCss('#result-page').text()).toBe(
'Result Page'
)
})

it('should redirect in a client component', async () => {
const browser = await webdriver(next.url, '/redirect/clientcomponent')
await browser.waitForElementByCss('#result-page')
expect(await browser.elementByCss('#result-page').text()).toBe(
'Result Page'
)
})
})
}

describe('without assetPrefix', () => {
Expand Down