Skip to content

Commit

Permalink
docs: revamp redirect/navigate/render docs
Browse files Browse the repository at this point in the history
  • Loading branch information
brillout committed Mar 1, 2024
1 parent d547664 commit f62f7c2
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 25 deletions.
2 changes: 1 addition & 1 deletion docs/headingsDetached.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ const headingsDetached = [
{
title: 'Abort',
url: '/abort',
sectionTitles: ['`throw redirect()` VS `throw render()`']
sectionTitles: ['`throw redirect()` VS `throw render()` VS `navigate()`']
},
{
title: 'Custom Exports/Hooks',
Expand Down
43 changes: 35 additions & 8 deletions docs/pages/abort/+Page.mdx
Original file line number Diff line number Diff line change
@@ -1,24 +1,51 @@
import { Link } from '@brillout/docpress'

By using <Link href="/render" text={<code>throw render()</code>}></Link> or <Link href="/redirect" text={<code>throw redirect()</code>}></Link> you abort the rendering of the current page and render something else instead.
You can use <Link href="/render">`throw render()`</Link> or <Link href="/redirect">`throw redirect()`</Link> in order to abort rendering the current page and render something else instead.

## `throw redirect()` VS `throw render()`

While `throw redirect()` changes the URL, `throw render()` preserves it:
- If a user goes to `/admin` and `throw redirect('/login')` is called, then the user will see the new URL `/login` in the browser's address bar.
- If a user goes to `/admin` and `throw render('/login')` is called, then the user keeps seeing the same URL `/admin` in the browser's address bar.
## `throw redirect()` VS `throw render()` VS `navigate()`

**`throw redirect()` VS `throw render()`**

While <Link href="/redirect">`throw redirect()`</Link> changes the URL, <Link href="/render">`throw render()`</Link> preserves it:
- If a user goes to `/admin` and `throw redirect('/login')` is called, then the `/login` page is rendered and the user sees a new URL `/login` in the address bar of his browser.
- If a user goes to `/admin` and `throw render('/login')` is called, then the `/login` page is rendered but the user keeps seeing the same URL `/admin` in the address bar of his browser (even though the `/login` page is rendered).

> We usually recommend using `throw render()` instead of `throw redirect()` as it preserves the URL and, therefore, the user's intention. We further explain this technique at <Link href="/auth#login-flow" />.
**`throw redirect()` VS `navigate()`**

Difference between `throw redirect()` and <Link href="/navigate">`navigate()`</Link>:
- `navigate()` only works on the client-side and shouldn't be called during the rendering of a page.
- `throw redirect()` works on both client- and server-side but only works during the rendering a page.

In a nuthsell: if you want to abort the rendering of a page then use `throw redirect()`, otherwise use `navigate()`.

For example:
- For redirecting the user upon a form submit action, use `navigate()`. (Since the page is already rendered and thus `throw redirect()` doesn't make sense as there is no pending page rendering to abort.)
- For protecting a page from unprivileged access, such as a normal user trying to access an admin page, use `throw redirect()` in order to abort (on both server- and client-side) the rendering of the admin page and redirect the user to another page instead (for example the login page).

In general, we recommend using `throw render('/login')` instead of `throw redirect('/login')` as it preserves the URL and, therefore, the user's intention. We further explain this techniue at <Link href="/auth#login-flow" />.

## Debug

If `throw redirect()` or `throw render()` doesn't work:
- **Make sure `throw redirect()` / `throw render()` isn't swallowed.**
In developement, check your server logs for the following log. If this log is missing then this means that Vike didn't receive the `throw redirect()` / `throw render()` exception: some other code is catching and swallowing it.
- **Make sure `throw redirect()` / `throw render()` isn't intercepted.**
In developement, check your server logs for the following log. If the log is missing then it means that Vike didn't catch the `throw redirect()` / `throw render()` exception: some other code is intercepting it and thus prevents Vike from catching it.
```
10:00:00 AM [vike][request(42)] throw redirect('/some-url') intercepted while
rendering /some-other-url
```
> Most notably, using `throw redirect()` / `throw render()` inside a UI component usually doesn't work because most <Link href="/ui-framework">UI frameworks</Link> will intercept the execption, and thus Vike won't be able to catch it. Instead, consider using `throw redirect()` / `throw render()` in a Vike hook such as <Link href="/guard">`guard()`</Link> or <Link href="/data">`data()`</Link>, or use <Link href="/navigate">`navigate()`</Link>.
- **Make sure to use `throw redirect()` / `throw render()` within a Vike hook.**
If you use `throw redirect()` / `throw render()` outside of Vike hooks, for example in some server middleware code, then Vike won't be able to intercept it.

If `throw redirect()` doesn't work:
- **Make sure to add `pageContext.httpResponse.headers` to the HTTP response.**
If you've embedded Vike into your server using <Link text={<code>renderPage()</code>} href="/renderPage" />, then insepct whether `pageContext.httpResponse.headers` contains the `Location` header and double check that you're correctly adding all the headers defined by `pageContext.httpResponse.headers` to the HTTP response.


## See also

- <Link href="/redirect" />
- <Link href="/render" />
- <Link href="/navigate" />
6 changes: 4 additions & 2 deletions docs/pages/navigate/+Page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ async function onSubmit() {
}
```

> If you want to redirect while rendering a page (e.g. redirect non-authenticated users to a login page), then use <Link href='/redirect' noBreadcrumb /> instead.
> If you want to redirect the user while rendering a page (e.g. redirect non-authenticated users to a login page), then use <Link href='/redirect'>`throw redirect()`</Link> instead. See <Link href="/abort#throw-redirect-vs-throw-render-vs-navigate" doNotInferSectionTitle={true} />.
> If you want to navigate back, then use [`window.history.back()`](https://developer.mozilla.org/en-US/docs/Web/API/History/back) instead.
Expand Down Expand Up @@ -76,4 +76,6 @@ If you don't use a <UiFrameworkVikeExtension /> and if you use <Link text="Serve

## See also

- <Link href="/redirect" />
- <Link href="/redirect" />
- <Link href="/redirects" />
- <Link href="/abort#throw-redirect-vs-throw-render-vs-navigate" doNotInferSectionTitle={true} />
24 changes: 16 additions & 8 deletions docs/pages/redirect/+Page.mdx
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { Link } from '@brillout/docpress'

See also:
- <Link href="/redirects" noBreadcrumb={true} />
- <Link href="/render" noBreadcrumb={true} />
- <Link href="/abort#throw-redirect-vs-throw-render" doNotInferSectionTitle={true} noBreadcrumb={true} />

```ts
// Redirect the user to another URL
redirect(url: `/${string}` | `https://${string}` | `http://${string}`)
Expand All @@ -20,13 +15,26 @@ function onSomeHook() {
}
```

> `throw redirect()` makes temporary redirections (HTTP status code `302`). For permanent redirections (HTTP status code `301`), you can set <Link href="/redirects" noBreadcrumb={true} /> or pass a second argument `throw redirect('/some-url', 301)`.
> `throw redirect()` is about *aborting* a page from being rendered and redirecting to the user to another page instead. Use <Link href="/navigate">`navigate()`</Link> if you want to redirect *after* the page is already rendered. See <Link href="/abort#throw-redirect-vs-throw-render-vs-navigate" doNotInferSectionTitle={true} />.
While it's most commonly used with [`guard()`](/guard) or [`data()`](/data) you can use it with any hook.
> `throw redirect()` makes temporary redirections (HTTP status code `302`). For permanent redirections (HTTP status code `301`), use the <Link href="/redirects">`redirects` setting</Link> or pass a second argument `throw redirect('/some-url', 301)`.
Common use cases:

- Authentication and authorization, see <Link href="/auth#login-flow" />.
- Data fetching error handling, see <Link href="/data#error-handling" />.

If `throw redirect()` doesn't work, see <Link href="/abort#debug" />.
While it's most commonly used with [`guard()`](/guard) or [`data()`](/data) you can use it with any hook.

> For improved DX, consider using <Link href="/render">`throw render()`</Link> instead of `throw redirect()`. See <Link href="/abort#throw-redirect-vs-throw-render-vs-navigate" doNotInferSectionTitle={true} />.
If `throw redirect()` doesn't work, see <Link href="/abort#debug" /> and <Link href="/abort#throw-redirect-vs-throw-render-vs-navigate" />.


## See also

- <Link href="/redirects" />
- <Link href="/navigate" />
- <Link href="/render" />
- <Link href="/abort#throw-redirect-vs-throw-render-vs-navigate" doNotInferSectionTitle={true} />
- <Link href="/abort#debug" />
15 changes: 9 additions & 6 deletions docs/pages/render/+Page.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { Link } from '@brillout/docpress'

See also:
- <Link href="/redirects" noBreadcrumb={true} />
- <Link href="/redirect" noBreadcrumb={true} />
- <Link href="/abort#throw-redirect-vs-throw-render" doNotInferSectionTitle={true} noBreadcrumb={true} />
`throw render()` is like <Link href="/redirect">`throw redirect()`</Link> but preserves the URL, see <Link href="/abort#throw-redirect-vs-throw-render-vs-navigate" doNotInferSectionTitle={true} />.

```ts
// Render the error page
Expand All @@ -12,8 +9,6 @@ render(abortStatusCode: 401 | 403 | 404 | 429 | 500 | 503, abortReason?: unknown
render(url: `/${string}`, abortReason?: unknown)
```

> If you use TypeScript, you can define the `abortReason` type by using the global interface `Vike.PageContext`, see <Link href="/error-page" />.
```js
import { render } from 'vike/abort'

Expand All @@ -36,6 +31,7 @@ function onSomeHook() {
- [`500` Internal Server Error](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500) - App has a bug.
- [`503` Service Unavailable](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503) - Server is overloaded and/or a third-party API isn't responding.
- The `abortReason` and `abortStatusCode` arguments are made available at `pageContext.abortReason` and `pageContext.abortStatusCode` which is useful for enabling the error page to show a useful error message to the user, see <Link href="/error-page" />.
> If you use TypeScript, you can define the `abortReason` type by using the global interface `Vike.PageContext`, see <Link href="/error-page" />.
While it's most commonly used with [`guard()`](/guard) or [`data()`](/data) you can use it with any hook.

Expand All @@ -45,3 +41,10 @@ Common use cases:
- Data fetching error handling, see <Link href="/data#error-handling" />.

If `throw render()` doesn't work, see <Link href="/abort#debug" />.


## See also

- <Link href="/redirect" />
- <Link href="/abort#throw-redirect-vs-throw-render-vs-navigate" doNotInferSectionTitle={true} />
- <Link href="/abort#debug" />

0 comments on commit f62f7c2

Please sign in to comment.