Skip to content

Commit c415524

Browse files
Sync kit docs (#1025)
sync kit docs Co-authored-by: Rich-Harris <[email protected]>
1 parent 198e9f1 commit c415524

File tree

17 files changed

+201
-55
lines changed

17 files changed

+201
-55
lines changed

apps/svelte.dev/content/docs/kit/10-getting-started/40-web-standards.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ Most of the time, your endpoints will return complete data, as in the `userAgent
7979
8080
## URL APIs
8181
82-
URLs are represented by the [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) interface, which includes useful properties like `origin` and `pathname` (and, in the browser, `hash`). This interface shows up in various places — `event.url` in [hooks](hooks) and [server routes](routing#server), [`$page.url`]($app-stores) in [pages](routing#page), `from` and `to` in [`beforeNavigate` and `afterNavigate`]($app-navigation) and so on.
82+
URLs are represented by the [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) interface, which includes useful properties like `origin` and `pathname` (and, in the browser, `hash`). This interface shows up in various places — `event.url` in [hooks](hooks) and [server routes](routing#server), [`page.url`]($app-state) in [pages](routing#page), `from` and `to` in [`beforeNavigate` and `afterNavigate`]($app-navigation) and so on.
8383
8484
### URLSearchParams
8585

apps/svelte.dev/content/docs/kit/20-core-concepts/10-routing.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,15 @@ If an error occurs during `load`, SvelteKit will render a default error page. Yo
133133
```svelte
134134
<!--- file: src/routes/blog/[slug]/+error.svelte --->
135135
<script>
136-
import { page } from '$app/stores';
136+
import { page } from '$app/state';
137137
</script>
138138
139-
<h1>{$page.status}: {$page.error.message}</h1>
139+
<h1>{page.status}: {page.error.message}</h1>
140140
```
141141

142+
> [!LEGACY]
143+
> `$app/state` was added in SvelteKit 2.12. If you're using an earlier version or are using Svelte 4, use `$app/stores` instead.
144+
142145
SvelteKit will 'walk up the tree' looking for the closest error boundary — if the file above didn't exist it would try `src/routes/blog/+error.svelte` and then `src/routes/+error.svelte` before rendering the default error page. If _that_ fails (or if the error was thrown from the `load` function of the root `+layout`, which sits 'above' the root `+error`), SvelteKit will bail out and render a static fallback error page, which you can customise by creating a `src/error.html` file.
143146

144147
If the error occurs inside a `load` function in `+layout(.server).js`, the closest error boundary in the tree is an `+error.svelte` file _above_ that layout (not next to it).

apps/svelte.dev/content/docs/kit/20-core-concepts/20-load.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,14 @@ Data returned from layout `load` functions is available to child `+layout.svelte
117117
```svelte
118118
/// file: src/routes/blog/[slug]/+page.svelte
119119
<script>
120-
+++import { page } from '$app/stores';+++
120+
+++import { page } from '$app/state';+++
121121
122122
/** @type {{ data: import('./$types').PageData }} */
123123
let { data } = $props();
124124
125125
+++ // we can access `data.posts` because it's returned from
126126
// the parent layout `load` function
127-
let index = $derived(data.posts.findIndex(post => post.slug === $page.params.slug));
127+
let index = $derived(data.posts.findIndex(post => post.slug === page.params.slug));
128128
let next = $derived(data.posts[index + 1]);+++
129129
</script>
130130
@@ -138,24 +138,28 @@ Data returned from layout `load` functions is available to child `+layout.svelte
138138

139139
> [!NOTE] If multiple `load` functions return data with the same key, the last one 'wins' — the result of a layout `load` returning `{ a: 1, b: 2 }` and a page `load` returning `{ b: 3, c: 4 }` would be `{ a: 1, b: 3, c: 4 }`.
140140
141-
## $page.data
141+
## page.data
142142

143143
The `+page.svelte` component, and each `+layout.svelte` component above it, has access to its own data plus all the data from its parents.
144144

145-
In some cases, we might need the opposite — a parent layout might need to access page data or data from a child layout. For example, the root layout might want to access a `title` property returned from a `load` function in `+page.js` or `+page.server.js`. This can be done with `$page.data`:
145+
In some cases, we might need the opposite — a parent layout might need to access page data or data from a child layout. For example, the root layout might want to access a `title` property returned from a `load` function in `+page.js` or `+page.server.js`. This can be done with `page.data`:
146146

147147
```svelte
148148
<!--- file: src/routes/+layout.svelte --->
149149
<script>
150-
import { page } from '$app/stores';
150+
import { page } from '$app/state';
151151
</script>
152152
153153
<svelte:head>
154-
<title>{$page.data.title}</title>
154+
<title>{page.data.title}</title>
155155
</svelte:head>
156156
```
157157

158-
Type information for `$page.data` is provided by `App.PageData`.
158+
Type information for `page.data` is provided by `App.PageData`.
159+
160+
> [!LEGACY]
161+
> `$app/state` was added in SvelteKit 2.12. If you're using an earlier version or are using Svelte 4, use `$app/stores` instead.
162+
> It provides a `page` store with the same interface that you can subscribe to, e.g. `$page.data.title`.
159163
160164
## Universal vs server
161165

apps/svelte.dev/content/docs/kit/20-core-concepts/30-form-actions.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ As well as the `action` attribute, we can use the `formaction` attribute on a bu
103103
104104
## Anatomy of an action
105105
106-
Each action receives a `RequestEvent` object, allowing you to read the data with `request.formData()`. After processing the request (for example, logging the user in by setting a cookie), the action can respond with data that will be available through the `form` property on the corresponding page and through `$page.form` app-wide until the next update.
106+
Each action receives a `RequestEvent` object, allowing you to read the data with `request.formData()`. After processing the request (for example, logging the user in by setting a cookie), the action can respond with data that will be available through the `form` property on the corresponding page and through `page.form` app-wide until the next update.
107107
108108
```js
109109
/// file: src/routes/login/+page.server.js
@@ -157,7 +157,7 @@ export const actions = {
157157
158158
### Validation errors
159159
160-
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`:
160+
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`:
161161
162162
```js
163163
/// file: src/routes/login/+page.server.js
@@ -353,7 +353,7 @@ The easiest way to progressively enhance a form is to add the `use:enhance` acti
353353
354354
Without an argument, `use:enhance` will emulate the browser-native behaviour, just without the full-page reloads. It will:
355355
356-
- update the `form` property, `$page.form` and `$page.status` on a successful or invalid response, but only if the action is on the same page you're submitting from. For example, if your form looks like `<form action="/somewhere/else" ..>`, `form` and `$page` will _not_ be updated. This is because in the native form submission case you would be redirected to the page the action is on. If you want to have them updated either way, use [`applyAction`](#Progressive-enhancement-Customising-use:enhance)
356+
- update the `form` property, `page.form` and `page.status` on a successful or invalid response, but only if the action is on the same page you're submitting from. For example, if your form looks like `<form action="/somewhere/else" ..>`, the `form` prop and the `page.form` state will _not_ be updated. This is because in the native form submission case you would be redirected to the page the action is on. If you want to have them updated either way, use [`applyAction`](#Progressive-enhancement-Customising-use:enhance)
357357
- reset the `<form>` element
358358
- invalidate all data using `invalidateAll` on a successful response
359359
- call `goto` on a redirect response
@@ -412,7 +412,7 @@ If you return a callback, you may need to reproduce part of the default `use:enh
412412
413413
The behaviour of `applyAction(result)` depends on `result.type`:
414414
415-
- `success`, `failure` — sets `$page.status` to `result.status` and updates `form` and `$page.form` to `result.data` (regardless of where you are submitting from, in contrast to `update` from `enhance`)
415+
- `success`, `failure` — sets `page.status` to `result.status` and updates `form` and `page.form` to `result.data` (regardless of where you are submitting from, in contrast to `update` from `enhance`)
416416
- `redirect` — calls `goto(result.location, { invalidateAll: true })`
417417
- `error` — renders the nearest `+error` boundary with `result.error`
418418

apps/svelte.dev/content/docs/kit/20-core-concepts/50-state-management.md

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Instead, you should _authenticate_ the user using [`cookies`](load#Cookies) and
4141

4242
## No side-effects in load
4343

44-
For the same reason, your `load` functions should be _pure_ — no side-effects (except maybe the occasional `console.log(...)`). For example, you might be tempted to write to a store inside a `load` function so that you can use the store value in your components:
44+
For the same reason, your `load` functions should be _pure_ — no side-effects (except maybe the occasional `console.log(...)`). For example, you might be tempted to write to a store or global state inside a `load` function so that you can use the value in your components:
4545

4646
```js
4747
/// file: +page.js
@@ -77,31 +77,25 @@ export async function load({ fetch }) {
7777
}
7878
```
7979

80-
...and pass it around to the components that need it, or use [`$page.data`](load#$page.data).
80+
...and pass it around to the components that need it, or use [`page.data`](load#page.data).
8181

8282
If you're not using SSR, then there's no risk of accidentally exposing one user's data to another. But you should still avoid side-effects in your `load` functions — your application will be much easier to reason about without them.
8383

84-
## Using stores with context
84+
## Using state and stores with context
8585

86-
You might wonder how we're able to use `$page.data` and other [app stores]($app-stores) if we can't use our own stores. The answer is that app stores on the server use Svelte's [context API](/tutorial/svelte/context-api) — the store is attached to the component tree with `setContext`, and when you subscribe you retrieve it with `getContext`. We can do the same thing with our own stores:
86+
You might wonder how we're able to use `page.data` and other [app state]($app-state) (or [app stores]($app-stores)) if we can't use global state. The answer is that app state and app stores on the server use Svelte's [context API](/tutorial/svelte/context-api) — the state (or store) is attached to the component tree with `setContext`, and when you subscribe you retrieve it with `getContext`. We can do the same thing with our own state:
8787

8888
```svelte
8989
<!--- file: src/routes/+layout.svelte --->
9090
<script>
9191
import { setContext } from 'svelte';
92-
import { writable } from 'svelte/store';
9392
9493
/** @type {{ data: import('./$types').LayoutData }} */
9594
let { data } = $props();
9695
97-
// Create a store and update it when necessary...
98-
const user = writable(data.user);
99-
$effect.pre(() => {
100-
user.set(data.user);
101-
});
102-
103-
// ...and add it to the context for child components to access
104-
setContext('user', user);
96+
// Pass a function referencing our state
97+
// to the context for child components to access
98+
setContext('user', () => data.user);
10599
</script>
106100
```
107101

@@ -114,10 +108,15 @@ You might wonder how we're able to use `$page.data` and other [app stores]($app-
114108
const user = getContext('user');
115109
</script>
116110
117-
<p>Welcome {$user.name}</p>
111+
<p>Welcome {user().name}</p>
118112
```
119113

120-
Updating the value of a context-based store in deeper-level pages or components while the page is being rendered via SSR will not affect the value in the parent component because it has already been rendered by the time the store value is updated. In contrast, on the client (when CSR is enabled, which is the default) the value will be propagated and components, pages, and layouts higher in the hierarchy will react to the new value. Therefore, to avoid values 'flashing' during state updates during hydration, it is generally recommended to pass state down into components rather than up.
114+
> [!NOTE] We're passing a function into `setContext` to keep reactivity across boundaries. Read more about it [here](https://svelte.dev/docs/svelte/$state#Passing-state-into-functions)
115+
116+
> [!LEGACY]
117+
> You also use stores from `svelte/store` for this, but when using Svelte 5 it is recommended to make use of universal reactivity instead.
118+
119+
Updating the value of context-based state in deeper-level pages or components while the page is being rendered via SSR will not affect the value in the parent component because it has already been rendered by the time the state value is updated. In contrast, on the client (when CSR is enabled, which is the default) the value will be propagated and components, pages, and layouts higher in the hierarchy will react to the new value. Therefore, to avoid values 'flashing' during state updates during hydration, it is generally recommended to pass state down into components rather than up.
121120

122121
If you're not using SSR (and can guarantee that you won't need to use SSR in future) then you can safely keep state in a shared module, without using the context API.
123122

@@ -164,14 +163,18 @@ Instead, we need to make the value [_reactive_](/tutorial/svelte/state):
164163
Reusing components like this means that things like sidebar scroll state are preserved, and you can easily animate between changing values. In the case that you do need to completely destroy and remount a component on navigation, you can use this pattern:
165164

166165
```svelte
167-
{#key $page.url.pathname}
166+
<script>
167+
import { page } from '$app/state';
168+
</script>
169+
170+
{#key page.url.pathname}
168171
<BlogPost title={data.title} content={data.title} />
169172
{/key}
170173
```
171174

172175
## Storing state in the URL
173176

174-
If you have state that should survive a reload and/or affect SSR, such as filters or sorting rules on a table, URL search parameters (like `?sort=price&order=ascending`) are a good place to put them. You can put them in `<a href="...">` or `<form action="...">` attributes, or set them programmatically via `goto('?key=value')`. They can be accessed inside `load` functions via the `url` parameter, and inside components via `$page.url.searchParams`.
177+
If you have state that should survive a reload and/or affect SSR, such as filters or sorting rules on a table, URL search parameters (like `?sort=price&order=ascending`) are a good place to put them. You can put them in `<a href="...">` or `<form action="...">` attributes, or set them programmatically via `goto('?key=value')`. They can be accessed inside `load` functions via the `url` parameter, and inside components via `page.url.searchParams`.
175178

176179
## Storing ephemeral state in snapshots
177180

apps/svelte.dev/content/docs/kit/30-advanced/25-errors.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,20 @@ export async function load({ params }) {
4141
}
4242
```
4343

44-
This throws an exception that SvelteKit catches, causing it to set the response status code to 404 and render an [`+error.svelte`](routing#error) component, where `$page.error` is the object provided as the second argument to `error(...)`.
44+
This throws an exception that SvelteKit catches, causing it to set the response status code to 404 and render an [`+error.svelte`](routing#error) component, where `page.error` is the object provided as the second argument to `error(...)`.
4545

4646
```svelte
4747
<!--- file: src/routes/+error.svelte --->
4848
<script>
49-
import { page } from '$app/stores';
49+
import { page } from '$app/state';
5050
</script>
5151
52-
<h1>{$page.error.message}</h1>
52+
<h1>{page.error.message}</h1>
5353
```
5454

55+
> [!LEGACY]
56+
> `$app/state` was added in SvelteKit 2.12. If you're using an earlier version or are using Svelte 4, use `$app/stores` instead.
57+
5558
You can add extra properties to the error object if needed...
5659

5760
```js

apps/svelte.dev/content/docs/kit/30-advanced/67-shallow-routing.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ SvelteKit makes this possible with the [`pushState`]($app-navigation#pushState)
1313
<!--- file: +page.svelte --->
1414
<script>
1515
import { pushState } from '$app/navigation';
16-
import { page } from '$app/stores';
16+
import { page } from '$app/state';
1717
import Modal from './Modal.svelte';
1818
1919
function showModal() {
@@ -23,21 +23,24 @@ SvelteKit makes this possible with the [`pushState`]($app-navigation#pushState)
2323
}
2424
</script>
2525
26-
{#if $page.state.showModal}
26+
{#if page.state.showModal}
2727
<Modal close={() => history.back()} />
2828
{/if}
2929
```
3030

31-
The modal can be dismissed by navigating back (unsetting `$page.state.showModal`) or by interacting with it in a way that causes the `close` callback to run, which will navigate back programmatically.
31+
The modal can be dismissed by navigating back (unsetting `page.state.showModal`) or by interacting with it in a way that causes the `close` callback to run, which will navigate back programmatically.
3232

3333
## API
3434

3535
The first argument to `pushState` is the URL, relative to the current URL. To stay on the current URL, use `''`.
3636

37-
The second argument is the new page state, which can be accessed via the [page store]($app-stores#page) as `$page.state`. You can make page state type-safe by declaring an [`App.PageState`](types#PageState) interface (usually in `src/app.d.ts`).
37+
The second argument is the new page state, which can be accessed via the [page object]($app-state#page) as `page.state`. You can make page state type-safe by declaring an [`App.PageState`](types#PageState) interface (usually in `src/app.d.ts`).
3838

3939
To set page state without creating a new history entry, use `replaceState` instead of `pushState`.
4040

41+
> [!LEGACY]
42+
> `page.state` from `$app/state` was added in SvelteKit 2.12. If you're using an earlier version or are using Svelte 4, use `$page.state` from `$app/stores` instead.
43+
4144
## Loading data for a route
4245

4346
When shallow routing, you may want to render another `+page.svelte` inside the current page. For example, clicking on a photo thumbnail could pop up the detail view without navigating to the photo page.
@@ -48,7 +51,7 @@ For this to work, you need to load the data that the `+page.svelte` expects. A c
4851
<!--- file: src/routes/photos/+page.svelte --->
4952
<script>
5053
import { preloadData, pushState, goto } from '$app/navigation';
51-
import { page } from '$app/stores';
54+
import { page } from '$app/state';
5255
import Modal from './Modal.svelte';
5356
import PhotoPage from './[id]/+page.svelte';
5457
@@ -86,17 +89,17 @@ For this to work, you need to load the data that the `+page.svelte` expects. A c
8689
</a>
8790
{/each}
8891
89-
{#if $page.state.selected}
92+
{#if page.state.selected}
9093
<Modal onclose={() => history.back()}>
9194
<!-- pass page data to the +page.svelte component,
9295
just like SvelteKit would on navigation -->
93-
<PhotoPage data={$page.state.selected} />
96+
<PhotoPage data={page.state.selected} />
9497
</Modal>
9598
{/if}
9699
```
97100

98101
## Caveats
99102

100-
During server-side rendering, `$page.state` is always an empty object. The same is true for the first page the user lands on — if the user reloads the page (or returns from another document), state will _not_ be applied until they navigate.
103+
During server-side rendering, `page.state` is always an empty object. The same is true for the first page the user lands on — if the user reloads the page (or returns from another document), state will _not_ be applied until they navigate.
101104

102105
Shallow routing is a feature that requires JavaScript to work. Be mindful when using it and try to think of sensible fallback behavior in case JavaScript isn't available.

0 commit comments

Comments
 (0)