Skip to content

Commit b2497a8

Browse files
committed
Merge branch 'main' into hover
2 parents 0b66605 + 2f8b59d commit b2497a8

File tree

109 files changed

+1751
-972
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+1751
-972
lines changed

apps/svelte.dev/content/blog/2024-12-01-advent-of-svelte.md

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -99,25 +99,48 @@ As of today, you can also return things that _aren't_ built in to the language,
9999
- [docs](/docs/kit/hooks#Universal-hooks-transport)
100100
- [demo](https://stackblitz.com/edit/sveltejs-kit-template-default-b5zbxomg?file=src%2Fhooks.js)
101101

102-
## Day 13
102+
## Day 13: rise of the robots
103103

104-
Coming soon!
104+
For those of you using LLMs to help you write code — via Cursor or Copilot or Claude or Bolt or v0 or some other interface — we now publish the documentation in a selection of robot-friendly `llms.txt` files. This is experimental and will evolve over time, but by way of example here's a [snake game](/playground/0de3c1c1a31d47bdbb7c4aa3477a6b46) built by Sonnet 3.5 with no additional prompting.
105105

106-
## Day 14
106+
Thanks to [Didier Catz](https://x.com/didiercatz) and [Stanislav Khromov](https://bsky.app/profile/khromov.se) for building this!
107107

108-
Coming soon!
108+
- [docs](/docs/llms)
109109

110-
## Day 15
110+
## Day 14: unmount with outros
111111

112-
Coming soon!
112+
Now, if you need to programmatically mount and unmount a component, you can now pass an `outro: true` option to `unmount` to play transitions before it is removed from the DOM.
113113

114-
## Day 16
114+
- [docs](/docs/svelte/imperative-component-api#unmount)
115+
- [demo](/playground/a4ca332691204ccd887ec7b1df818182?version=5.13.0)
115116

116-
Coming soon!
117+
## Day 15: debugging superpowers
117118

118-
## Day 17
119+
The new `$inspect.trace(...)` rune gives you detailed information about which state changes caused a derived or effect to re-run.
119120

120-
Coming soon!
121+
- [docs](</docs/svelte/$inspect#$inspect.trace()>)
122+
- [demo](/playground/d135c6f00beb4fa391725e59d8061604?version=5.14.0)
123+
124+
## Day 16: `$app/state`
125+
126+
SvelteKit's `$app/stores` module, which gives you a way to access information about (for example) the current page, now has a modern Svelte 5 state-based counterpart: `$app/state`. It exposes all the same information, but using fine-grained state, and without the clunky `$` prefix. `$app/stores` is now deprecated, and will be removed in SvelteKit 3 next year.
127+
128+
You can migrate automatically by running the following command in your SvelteKit app:
129+
130+
```bash
131+
npx sv migrate app-state
132+
```
133+
134+
- [docs](/docs/kit/$app-state)
135+
- [tutorial](/tutorial/kit/page-state)
136+
137+
## Day 17: better IntelliSense
138+
139+
The parser used by the language tools that power things like the [Svelte for VS Code](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) extension is the same one used by the Svelte compiler. Until today, it would fail if it encountered a syntax error, making it hard to provide things like autocomplete while you were in the middle of writing code.
140+
141+
We just fixed that. Install the latest version of Svelte in your project, make sure your extensions are up to date, and feel the wind in your hair as you write your components.
142+
143+
- [demo video](https://bsky.app/profile/svelte.dev/post/3ldjajjbkwc2n)
121144

122145
## Day 18
123146

apps/svelte.dev/content/docs/cli/20-commands/20-sv-add.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ You can select multiple space-separated add-ons from [the list below](#Official-
2929

3030
- `drizzle`
3131
- `eslint`
32+
- `sveltekit-adapter`
3233
- `lucia`
3334
- `mdsvex`
3435
- `paraglide`

apps/svelte.dev/content/docs/cli/20-commands/40-sv-migrate.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,18 @@ npx sv migrate [migration]
1515

1616
## Migrations
1717

18+
### `app-state`
19+
20+
Migrates `$app/store` usage to `$app/state` in `.svelte` files. See the [migration guide](/docs/kit/migrating-to-sveltekit-2#SvelteKit-2.12:-$app-stores-deprecated) for more details.
21+
1822
### `svelte-5`
1923

2024
Upgrades a Svelte 4 app to use Svelte 5, and updates individual components to use [runes](../svelte/what-are-runes) and other Svelte 5 syntax ([see migration guide](../svelte/v5-migration-guide)).
2125

26+
### `self-closing-tags`
27+
28+
Replaces all the self-closing non-void elements in your `.svelte` files. See the [pull request](https://github.com/sveltejs/kit/pull/12128) for more details.
29+
2230
### `svelte-4`
2331

2432
Upgrades a Svelte 3 app to use Svelte 4 ([see migration guide](../svelte/v4-migration-guide)).

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: 7 additions & 6 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
@@ -431,8 +431,9 @@ We can also implement progressive enhancement ourselves, without `use:enhance`,
431431
/** @type {{ form: import('./$types').ActionData }} */
432432
let { form } = $props();
433433

434-
/** @param {{ currentTarget: EventTarget & HTMLFormElement}} event */
434+
/** @param {SubmitEvent & { currentTarget: EventTarget & HTMLFormElement}} event */
435435
async function handleSubmit(event) {
436+
event.preventDefault();
436437
const data = new FormData(event.currentTarget);
437438

438439
const response = await fetch(event.currentTarget.action, {
@@ -452,7 +453,7 @@ We can also implement progressive enhancement ourselves, without `use:enhance`,
452453
}
453454
</script>
454455

455-
<form method="POST" onsubmit|preventDefault={handleSubmit}>
456+
<form method="POST" onsubmit={handleSubmit}>
456457
<!-- content -->
457458
</form>
458459
```

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

Lines changed: 21 additions & 18 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

@@ -154,7 +153,7 @@ Instead, we need to make the value [_reactive_](/tutorial/svelte/state):
154153
/** @type {{ data: import('./$types').PageData }} */
155154
let { data } = $props();
156155
157-
+++ let wordCount = $state(data.content.split(' ').length);
156+
+++ let wordCount = $derived(data.content.split(' ').length);
158157
let estimatedReadingTime = $derived(wordCount / 250);+++
159158
</script>
160159
```
@@ -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

0 commit comments

Comments
 (0)