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

Docs for the new API #5810

Merged
merged 9 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions documentation/docs/02-web-standards.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,27 @@ An instance of [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Requ

#### Response

An instance of [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) is returned from `await fetch(...)`. Fundamentally, a SvelteKit app is a machine for turning a `Request` into a `Response`.
An instance of [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) is returned from `await fetch(...)` and handlers in `+server.js` files. Fundamentally, a SvelteKit app is a machine for turning a `Request` into a `Response`.

#### Headers

The [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) interface allows you to read incoming `request.headers` and set outgoing `response.headers`:

```js
// @errors: 2461
/// file: src/routes/what-is-my-user-agent.js
/// file: src/routes/what-is-my-user-agent/+server.js
/** @type {import('@sveltejs/kit').RequestHandler} */
export function GET(event) {
// log all headers
console.log(...event.request.headers);

return {
body: {
return new Response(
{
// retrieve a specific header
userAgent: event.request.headers.get('user-agent')
}
};
},
{ headers: { 'content-type': 'application/json; charset=utf-8' } }
);
}
```

Expand Down
360 changes: 196 additions & 164 deletions documentation/docs/03-routing.md

Large diffs are not rendered by default.

142 changes: 65 additions & 77 deletions documentation/docs/04-layouts.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ So far, we've treated pages as entirely standalone components — upon navigatio

But in many apps, there are elements that should be visible on _every_ page, such as top-level navigation or a footer. Instead of repeating them in every page, we can use _layout_ components.

To create a layout that applies to every page, make a file called `src/routes/__layout.svelte`. The default layout (the one that SvelteKit uses if you don't bring your own) looks like this...
To create a layout that applies to every page, make a file called `src/routes/+layout.svelte`. The default layout (the one that SvelteKit uses if you don't bring your own) looks like this...

```html
<slot></slot>
Expand All @@ -15,7 +15,7 @@ To create a layout that applies to every page, make a file called `src/routes/__
...but we can add whatever markup, styles and behaviour we want. The only requirement is that the component includes a `<slot>` for the page content. For example, let's add a nav bar:

```html
/// file: src/routes/__layout.svelte
/// file: src/routes/+layout.svelte
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
Expand All @@ -28,17 +28,17 @@ To create a layout that applies to every page, make a file called `src/routes/__
If we create pages for `/`, `/about` and `/settings`...

```html
/// file: src/routes/index.svelte
/// file: src/routes/+page.svelte
<h1>Home</h1>
```

```html
/// file: src/routes/about.svelte
/// file: src/routes/about/+page.svelte
<h1>About</h1>
```

```html
/// file: src/routes/settings.svelte
/// file: src/routes/settings/+page.svelte
<h1>Settings</h1>
```

Expand All @@ -51,7 +51,7 @@ Suppose we don't just have a single `/settings` page, but instead have nested pa
We can create a layout that only applies to pages below `/settings` (while inheriting the root layout with the top-level nav):

```html
/// file: src/routes/settings/__layout.svelte
/// file: src/routes/settings/+layout.svelte
<h1>Settings</h1>

<div class="submenu">
Expand All @@ -67,7 +67,7 @@ We can create a layout that only applies to pages below `/settings` (while inher
Some parts of your app might need something other than the default layout. For these cases you can create _named layouts_...

```svelte
/// file: src/routes/__layout-foo.svelte
/// file: src/routes/+layout-foo.svelte
<div class="foo">
<slot></slot>
</div>
Expand All @@ -76,132 +76,120 @@ Some parts of your app might need something other than the default layout. For t
...and then use them by referencing the layout name (`foo`, in the example above) in the filename:

```svelte
/// file: src/routes/my-special-page@foo.svelte
<h1>I am inside __layout-foo</h1>
/// file: src/routes/my-special-page/+page@foo.svelte
<h1>I am inside +layout-foo</h1>
```

Named layouts are very powerful, but it can take a minute to get your head round them. Don't worry if this doesn't make sense all at once.

#### Scoping

Named layouts can be created at any depth, and will apply to any components in the same subtree. For example, `__layout-foo` will apply to `/x/one` and `/x/two`, but not `/x/three` or `/four`:
Named layouts can be created at any depth, and will apply to any components in the same subtree. For example, `+layout-foo` will apply to `/x/one` and `/x/two`, but not `/x/three` or `/four`:

```bash
src/routes/
├ x/
│ ├ __layout-foo.svelte
│ ├ one@foo.svelte # ✅ page has `@foo`
│ ├ two@foo.svelte # ✅ page has `@foo`
│ └ three.svelte # ❌ page does not have `@foo`
└ four@foo.svelte # ❌ page has `@foo`, but __layout-foo is not 'in scope'
│ ├ +layout-foo.svelte
│ ├ one/+page@foo.svelte # ✅ page has `@foo`
│ ├ two/+page@foo.svelte # ✅ page has `@foo`
│ └ three/+page.svelte # ❌ page does not have `@foo`
└ four/+page@foo.svelte # ❌ page has `@foo`, but +layout-foo is not 'in scope'
```

#### Inheritance chains

Layouts can themselves choose to inherit from named layouts, from the same directory or a parent directory. For example, `x/y/__layout@root.svelte` is the default layout for `/x/y` (meaning `/x/y/one`, `/x/y/two` and `/x/y/three` all inherit from it) because it has no name. Because it specifies `@root`, it will inherit directly from the nearest `__layout-root.svelte`, skipping `__layout.svelte` and `x/__layout.svelte`.
Layouts can themselves choose to inherit from named layouts, from the same directory or a parent directory. For example, `x/y/+layout@root.svelte` is the default layout for `/x/y` (meaning `/x/y/one`, `/x/y/two` and `/x/y/three` all inherit from it) because it has no name. Because it specifies `@root`, it will inherit directly from the nearest `+layout-root.svelte`, skipping `+layout.svelte` and `x/+layout.svelte`.

```
src/routes/
├ x/
│ ├ y/
│ │ ├ __layout@root.svelte
│ │ ├ one.svelte
│ │ ├ two.svelte
│ │ └ three.svelte
│ └ __layout.svelte
__layout.svelte
__layout-root.svelte
│ │ ├ +layout@root.svelte
│ │ ├ one/+page.svelte
│ │ ├ two/+page.svelte
│ │ └ three/+page.svelte
│ └ +layout.svelte
+layout.svelte
+layout-root.svelte
```

> In the case where `__layout-root.svelte` contains a lone `<slot />`, this effectively means we're able to 'reset' to a blank layout for any page or nested layout in the app by adding `@root`.
> In the case where `+layout-root.svelte` contains a lone `<slot />`, this effectively means we're able to 'reset' to a blank layout for any page or nested layout in the app by adding `@root`.

If no parent is specified, a layout will inherit from the nearest default (i.e. unnamed) layout _above_ it in the tree. In some cases, it's helpful for a named layout to inherit from a default layout _alongside_ it in the tree, such as `__layout-root.svelte` inheriting from `__layout.svelte`. We can do this by explicitly specifying `@default`, allowing `/x/y/one` and siblings to use the app's default layout without using `x/__layout.svelte`:
If no parent is specified, a layout will inherit from the nearest default (i.e. unnamed) layout _above_ it in the tree. In some cases, it's helpful for a named layout to inherit from a default layout _alongside_ it in the tree, such as `+layout-root.svelte` inheriting from `+layout.svelte`. We can do this by explicitly specifying `@default`, allowing `/x/y/one` and siblings to use the app's default layout without using `x/+layout.svelte`:

```diff
src/routes/
├ x/
│ ├ y/
│ │ ├ __layout@root.svelte
│ │ ├ one.svelte
│ │ ├ two.svelte
│ │ └ three.svelte
│ └ __layout.svelte
__layout.svelte
-└ __layout-root.svelte
+└ __layout-root@default.svelte
│ │ ├ +layout@root.svelte
│ │ ├ one/+page.svelte
│ │ ├ two/+page.svelte
│ │ └ three/+page.svelte
│ └ +layout.svelte
+layout.svelte
-└ +layout-root.svelte
Rich-Harris marked this conversation as resolved.
Show resolved Hide resolved
+└ +layout-root@default.svelte
```

> `default` is a reserved name — in other words, you can't have a `__layout-default.svelte` file.
> `default` is a reserved name — in other words, you can't have a `+layout-default.svelte` file.

### Error pages

If a page fails to load (see [Loading](/docs/loading)), SvelteKit will render an error page. You can customise this page by creating `__error.svelte` components alongside your layouts and pages.
If a page fails to load (see [Loading](/docs/loading)), SvelteKit will render an error page. You can customise this page by creating `+error.svelte` components alongside your layouts and pages.

For example, if `src/routes/settings/notifications/index.svelte` failed to load, SvelteKit would render `src/routes/settings/notifications/__error.svelte` in the same layout, if it existed. If not, it would render `src/routes/settings/__error.svelte` in the parent layout, or `src/routes/__error.svelte` in the root layout.
For example, if `src/routes/settings/notifications/+page.svelte` failed to load, SvelteKit would render `src/routes/settings/notifications/+error.svelte` in the same layout, if it existed. If not, it would render `src/routes/settings/+error.svelte` in the parent layout, or `src/routes/+error.svelte` in the root layout.

> SvelteKit provides a default error page in case you don't supply `src/routes/__error.svelte`, but it's recommended that you bring your own.
> SvelteKit provides a default error page in case you don't supply `src/routes/+error.svelte`, but it's recommended that you bring your own.

If an error component has a [`load`](/docs/loading) function, it will be called with `error` and `status` properties:
An error component has no access to data retrieval mechanisms like pages or layouts to ensure nothing further can go wrong. You can use the [page store](/docs/modules#$app-stores-page) to display the status code and error message:

```html
<script context="module">
/** @type {import('@sveltejs/kit').Load} */
export function load({ error, status }) {
return {
props: {
title: `${status}: ${error.message}`
}
};
}
</script>

<script>
export let title;
import { page } from '$app/stores';
</script>

<h1>{title}</h1>
<h1>{$page.status}</h1>
<p>{$page.error.message}</p>
```

> Layouts also have access to `error` and `status` via the [page store](/docs/modules#$app-stores)
> Layouts also have access to `error` and `status` via the same page store
>
> Server-side stack traces will be removed from `error` in production, to avoid exposing privileged information to users.

You can further handle unexpected errors on the server using the [handleError](/docs/hooks#handleerror) hook.

#### 404s

Nested error pages are only rendered when an error occurs while rendering a specific page. In the case of a request that doesn't match any existing route, SvelteKit will render a generic 404 instead. For example, given these routes...

```
src/routes/
__error.svelte
+error.svelte
├ marx-brothers/
│ ├ __error.svelte
│ ├ chico.svelte
│ ├ harpo.svelte
│ └ groucho.svelte
│ ├ +error.svelte
│ ├ chico/+page.svelte
│ ├ harpo/+page.svelte
│ └ groucho/+page.svelte
```

...the `marx-brothers/__error.svelte` file will _not_ be rendered if you visit `/marx-brothers/karl`. If you want to render the nested error page, you should create a route that matches any `/marx-brothers/*` request, and return a 404 from it:
...the `marx-brothers/+error.svelte` file will _not_ be rendered if you visit `/marx-brothers/karl`. If you want to render the nested error page, you should create a route that matches any `/marx-brothers/*` request, and throw a 404 from it:

```diff
src/routes/
__error.svelte
+error.svelte
├ marx-brothers/
│ ├ __error.svelte
+│ ├ [...path].svelte
│ ├ chico.svelte
│ ├ harpo.svelte
│ └ groucho.svelte
```

```svelte
/// file: src/routes/marx-brothers/[...path].svelte
<script context="module">
/** @type {import('./__types/[...path]').Load} */
export function load({ params }) {
return {
status: 404,
error: new Error(`Not found: /marx-brothers/${params.path}`)
};
}
</script>
│ ├ +error.svelte
+│ ├ [...path]/+page.js
│ ├ chico/+page.svelte
│ ├ harpo/+page.svelte
│ └ groucho/+page.svelte
```

```js
/// file: src/routes/marx-brothers/[...path]/+page.js
import { error } from '@sveltejs/kit';
/** @type {import('./$types').Load} */
export function load({ params }) {
throw error(404, `Not found: /marx-brothers/${params.path}`);
}
```
Loading