Skip to content

Commit

Permalink
docs: more Svelte 5 conversion (#12871)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: Ben McCann <[email protected]>
Co-authored-by: Willow (GHOST) <[email protected]>
Co-authored-by: Sri Senthil Balaji J <[email protected]>
Co-authored-by: Tee Ming <[email protected]>
  • Loading branch information
5 people authored Oct 25, 2024
1 parent 4cdbf76 commit bd82819
Show file tree
Hide file tree
Showing 11 changed files with 104 additions and 77 deletions.
45 changes: 29 additions & 16 deletions documentation/docs/20-core-concepts/10-routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,22 @@ A `+page.svelte` component defines a page of your app. By default, pages are ren
<a href="/">Home</a>
```

Pages can receive data from `load` functions via the `data` prop.

```svelte
<!--- file: src/routes/blog/[slug]/+page.svelte --->
<script>
/** @type {import('./$types').PageData} */
export let data;
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
</script>
<h1>{data.title}</h1>
<div>{@html data.content}</div>
```

> [!LEGACY] In Svelte 4
> In Svelte 4, you'd use `export let data` instead
> [!NOTE] Note that SvelteKit uses `<a>` elements to navigate between routes, rather than a framework-specific `<Link>` component.
### +page.js
Expand Down Expand Up @@ -153,21 +158,29 @@ But in many apps, there are elements that should be visible on _every_ page, suc

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>
```svelte
<script>
let { children } = $props();
</script>
{@render children()}
```

...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:
...but we can add whatever markup, styles and behaviour we want. The only requirement is that the component includes a `@render` tag for the page content. For example, let's add a nav bar:

```svelte
<!---- file: src/routes/+layout.svelte --->
<script>
let { children } = $props();
</script>
```html
/// file: src/routes/+layout.svelte
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/settings">Settings</a>
</nav>
<slot></slot>
{@render children()}
```

If we create pages for `/`, `/about` and `/settings`...
Expand Down Expand Up @@ -196,8 +209,8 @@ We can create a layout that only applies to pages below `/settings` (while inher
```svelte
<!--- file: src/routes/settings/+layout.svelte --->
<script>
/** @type {import('./$types').LayoutData} */
export let data;
/** @type {{ data: import('./$types').LayoutData, children: import('svelte').Snippet }} */
let { data, children } = $props();
</script>
<h1>Settings</h1>
Expand All @@ -208,7 +221,7 @@ We can create a layout that only applies to pages below `/settings` (while inher
{/each}
</div>
<slot></slot>
{@render children()}
```

You can see how `data` is populated by looking at the `+layout.js` example in the next section just below.
Expand Down Expand Up @@ -239,8 +252,8 @@ Data returned from a layout's `load` function is also available to all its child
```svelte
<!--- file: src/routes/settings/profile/+page.svelte --->
<script>
/** @type {import('./$types').PageData} */
export let data;
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
console.log(data.sections); // [{ slug: 'profile', title: 'Profile' }, ...]
</script>
Expand Down Expand Up @@ -370,13 +383,13 @@ export async function fallback({ request }) {
Throughout the examples above, we've been importing types from a `$types.d.ts` file. This is a file SvelteKit creates for you in a hidden directory if you're using TypeScript (or JavaScript with JSDoc type annotations) to give you type safety when working with your root files.
For example, annotating `export let data` with `PageData` (or `LayoutData`, for a `+layout.svelte` file) tells TypeScript that the type of `data` is whatever was returned from `load`:
For example, annotating `let { data } = $props()` with `PageData` (or `LayoutData`, for a `+layout.svelte` file) tells TypeScript that the type of `data` is whatever was returned from `load`:
```svelte
<!--- file: src/routes/blog/[slug]/+page.svelte --->
<script>
/** @type {import('./$types').PageData} */
export let data;
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
</script>
```
Expand Down
33 changes: 18 additions & 15 deletions documentation/docs/20-core-concepts/20-load.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,17 @@ export function load({ params }) {
```svelte
<!--- file: src/routes/blog/[slug]/+page.svelte --->
<script>
/** @type {import('./$types').PageData} */
export let data;
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
```

> [!LEGACY] In Svelte 4
> In Svelte 4, you'd use `export let data` instead
Thanks to the generated `$types` module, we get full type safety.

A `load` function in a `+page.js` file runs both on the server and in the browser (unless combined with `export const ssr = false`, in which case it will [only run in the browser](page-options#ssr)). If your `load` function should _always_ run on the server (because it uses private environment variables, for example, or accesses a database) then it would go in a `+page.server.js` instead.
Expand Down Expand Up @@ -85,13 +88,13 @@ export async function load() {
```svelte
<!--- file: src/routes/blog/[slug]/+layout.svelte --->
<script>
/** @type {import('./$types').LayoutData} */
export let data;
/** @type {{ data: import('./$types').LayoutData, children: Snippet }} */
let { data, children } = $props();
</script>
<main>
<!-- +page.svelte is rendered in this <slot> -->
<slot />
<!-- +page.svelte is `@render`ed here -->
{@render children()}
</main>
<aside>
Expand All @@ -115,13 +118,13 @@ Data returned from layout `load` functions is available to child `+layout.svelte
<script>
+++import { page } from '$app/stores';+++
/** @type {import('./$types').PageData} */
export let data;
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
+++ // we can access `data.posts` because it's returned from
// the parent layout `load` function
let index = $derived(data.posts.findIndex(post => post.slug === $page.params.slug));
let next = $derived(data.posts[index - 1];)+++
let next = $derived(data.posts[index + 1]);+++
</script>
<h1>{data.post.title}</h1>
Expand Down Expand Up @@ -365,8 +368,8 @@ export async function load({ parent }) {
```svelte
<!--- file: src/routes/abc/+page.svelte --->
<script>
/** @type {import('./$types').PageData} */
export let data;
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
</script>
<!-- renders `1 + 2 = 3` -->
Expand Down Expand Up @@ -504,8 +507,8 @@ This is useful for creating skeleton loading states, for example:
```svelte
<!--- file: src/routes/blog/[slug]/+page.svelte --->
<script>
/** @type {import('./$types').PageData} */
export let data;
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
</script>
<h1>{data.post.title}</h1>
Expand Down Expand Up @@ -645,8 +648,8 @@ export async function load({ fetch, depends }) {
<script>
import { invalidate, invalidateAll } from '$app/navigation';
/** @type {import('./$types').PageData} */
export let data;
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
function rerunLoadFunction() {
// any of these will cause the `load` function to rerun
Expand Down
25 changes: 11 additions & 14 deletions documentation/docs/20-core-concepts/30-form-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,8 @@ export const actions = {
```svelte
<!--- file: src/routes/login/+page.svelte --->
<script>
/** @type {import('./$types').PageData} */
export let data;

/** @type {import('./$types').ActionData} */
export let form;
/** @type {{ data: import('./$types').PageData, form: import('./$types').ActionData }} */
let { data, form } = $props();
</script>

{#if form?.success}
Expand All @@ -154,6 +151,9 @@ export const actions = {
{/if}
```
> [!LEGACY] In Svelte 4
> In Svelte 4, you'd use `export let data` and `export let form` instead to declare properties
### Validation errors
If the request couldn't be processed because of invalid data, you can return validation errors — along with the previously submitted form values — back to the user so that they can try again. The `fail` function lets you return an HTTP status code (typically 400 or 422, in the case of validation errors) along with the data. The status code is available through `$page.status` and the data through `form`:
Expand Down Expand Up @@ -339,8 +339,8 @@ The easiest way to progressively enhance a form is to add the `use:enhance` acti
<script>
+++import { enhance } from '$app/forms';+++

/** @type {import('./$types').ActionData} */
export let form;
/** @type {{ form: import('./$types').ActionData }} */
let { form } = $props();
</script>

<form method="POST" +++use:enhance+++>
Expand Down Expand Up @@ -390,8 +390,8 @@ If you return a callback, you may need to reproduce part of the default `use:enh
<script>
import { enhance, +++applyAction+++ } from '$app/forms';

/** @type {import('./$types').ActionData} */
export let form;
/** @type {{ form: import('./$types').ActionData }} */
let { form } = $props();
</script>

<form
Expand Down Expand Up @@ -427,11 +427,8 @@ We can also implement progressive enhancement ourselves, without `use:enhance`,
import { invalidateAll, goto } from '$app/navigation';
import { applyAction, deserialize } from '$app/forms';

/** @type {import('./$types').ActionData} */
export let form;

/** @type {any} */
let error;
/** @type {{ form: import('./$types').ActionData }} */
let { form } = $props();

/** @param {{ currentTarget: EventTarget & HTMLFormElement}} event */
async function handleSubmit(event) {
Expand Down
18 changes: 10 additions & 8 deletions documentation/docs/20-core-concepts/50-state-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,14 @@ You might wonder how we're able to use `$page.data` and other [app stores]($app-
import { setContext } from 'svelte';
import { writable } from 'svelte/store';
/** @type {import('./$types').LayoutData} */
export let data;
/** @type {{ data: import('./$types').LayoutData }} */
let { data } = $props();
// Create a store and update it when necessary...
const user = writable();
$: user.set(data.user);
const user = writable(data.user);
$effect.pre(() => {
user.set(data.user);
});
// ...and add it to the context for child components to access
setContext('user', user);
Expand Down Expand Up @@ -125,8 +127,8 @@ When you navigate around your application, SvelteKit reuses existing layout and
```svelte
<!--- file: src/routes/blog/[slug]/+page.svelte --->
<script>
/** @type {import('./$types').PageData} */
export let data;
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
// THIS CODE IS BUGGY!
const wordCount = data.content.split(' ').length;
Expand All @@ -148,8 +150,8 @@ Instead, we need to make the value [_reactive_](/tutorial/svelte/state):
```svelte
/// file: src/routes/blog/[slug]/+page.svelte
<script>
/** @type {import('./$types').PageData} */
export let data;
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
+++ let wordCount = $state(data.content.split(' ').length);
let estimatedReadingTime = $derived(wordCount / 250);+++
Expand Down
4 changes: 2 additions & 2 deletions documentation/docs/25-build-and-deploy/90-adapter-vercel.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ export function load() {
```svelte
<!--- file: +layout.svelte --->
<script>
/** @type {import('./$types').LayoutServerData} */
export let data;
/** @type {{ data: import('./$types').LayoutServerData }} */
let { data } = $props();
</script>
<p>This staging environment was deployed from {data.deploymentGitBranch}.</p>
Expand Down
6 changes: 3 additions & 3 deletions documentation/docs/30-advanced/10-advanced-routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ You can also put a `+page` directly inside a `(group)`, for example if `/` shoul

### Breaking out of layouts

The root layout applies to every page of your app — if omitted, it defaults to `<slot />`. If you want some pages to have a different layout hierarchy than the rest, then you can put your entire app inside one or more groups _except_ the routes that should not inherit the common layouts.
The root layout applies to every page of your app — if omitted, it defaults to `{@render children()}`. If you want some pages to have a different layout hierarchy than the rest, then you can put your entire app inside one or more groups _except_ the routes that should not inherit the common layouts.

In the example above, the `/admin` route does not inherit either the `(app)` or `(marketing)` layouts.

Expand Down Expand Up @@ -260,11 +260,11 @@ Not all use cases are suited for layout grouping, nor should you feel compelled
<!--- file: src/routes/nested/route/[email protected] --->
<script>
import ReusableLayout from '$lib/ReusableLayout.svelte';
export let data;
let { data, children } = $props();
</script>
<ReusableLayout {data}>
<slot />
{@render children()}
</ReusableLayout>
```

Expand Down
2 changes: 1 addition & 1 deletion documentation/docs/30-advanced/65-snapshots.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ To do this, export a `snapshot` object with `capture` and `restore` methods from
```svelte
<!--- file: +page.svelte --->
<script>
let comment = '';
let comment = $state('');
/** @type {import('./$types').Snapshot<string>} */
export const snapshot = {
Expand Down
2 changes: 1 addition & 1 deletion documentation/docs/30-advanced/67-shallow-routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ For this to work, you need to load the data that the `+page.svelte` expects. A c
import Modal from './Modal.svelte';
import PhotoPage from './[id]/+page.svelte';
export let data;
let { data } = $props();
</script>
{#each data.thumbnails as thumbnail}
Expand Down
16 changes: 15 additions & 1 deletion documentation/docs/98-reference/26-$lib.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,18 @@
title: $lib
---

TODO
SvelteKit automatically makes files under `src/lib` available using the `$lib` import alias. You can change which directory this alias points to in your [config file](configuration#files).

```svelte
<!--- file: src/lib/Component.svelte --->
A reusable component
```

```svelte
<!--- file: src/routes/+page.svelte --->
<script>
import Component from '$lib/Component.svelte';
</script>
<Component />
```
Loading

0 comments on commit bd82819

Please sign in to comment.