Skip to content

Commit f2fa845

Browse files
authored
Merge branch 'main' into task-16961
2 parents 17b126b + b7625fd commit f2fa845

File tree

166 files changed

+2643
-1173
lines changed

Some content is hidden

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

166 files changed

+2643
-1173
lines changed

.changeset/dirty-planes-tell.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/legal-mangos-peel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: change title only after any pending work has completed

.changeset/sixty-comics-bow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: preserve symbols when creating derived rest properties

documentation/docs/03-template-syntax/19-await-expressions.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,54 @@ If a `<svelte:boundary>` with a `pending` snippet is encountered during SSR, tha
135135

136136
> [!NOTE] In the future, we plan to add a streaming implementation that renders the content in the background.
137137
138+
## Forking
139+
140+
The [`fork(...)`](svelte#fork) API, added in 5.42, makes it possible to run `await` expressions that you _expect_ to happen in the near future. This is mainly intended for frameworks like SvelteKit to implement preloading when (for example) users signal an intent to navigate.
141+
142+
```svelte
143+
<script>
144+
import { fork } from 'svelte';
145+
import Menu from './Menu.svelte';
146+
147+
let open = $state(false);
148+
149+
/** @type {import('svelte').Fork | null} */
150+
let pending = null;
151+
152+
function preload() {
153+
pending ??= fork(() => {
154+
open = true;
155+
});
156+
}
157+
158+
function discard() {
159+
pending?.discard();
160+
pending = null;
161+
}
162+
</script>
163+
164+
<button
165+
onfocusin={preload}
166+
onfocusout={discard}
167+
onpointerenter={preload}
168+
onpointerleave={discard}
169+
onclick={() => {
170+
pending?.commit();
171+
pending = null;
172+
173+
// in case `pending` didn't exist
174+
// (if it did, this is a no-op)
175+
open = true;
176+
}}
177+
>open menu</button>
178+
179+
{#if open}
180+
<!-- any async work inside this component will start
181+
as soon as the fork is created -->
182+
<Menu onclose={() => open = false} />
183+
{/if}
184+
```
185+
138186
## Caveats
139187

140188
As an experimental feature, the details of how `await` is handled (and related APIs like `$effect.pending()`) are subject to breaking changes outside of a semver major release, though we intend to keep such changes to a bare minimum.

documentation/docs/98-reference/.generated/client-errors.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,12 @@ $effect(() => {
130130

131131
Often when encountering this issue, the value in question shouldn't be state (for example, if you are pushing to a `logs` array in an effect, make `logs` a normal array rather than `$state([])`). In the rare cases where you really _do_ need to write to state in an effect — [which you should avoid]($effect#When-not-to-use-$effect) — you can read the state with [untrack](svelte#untrack) to avoid adding it as a dependency.
132132

133+
### experimental_async_fork
134+
135+
```
136+
Cannot use `fork(...)` unless the `experimental.async` compiler option is `true`
137+
```
138+
133139
### flush_sync_in_effect
134140

135141
```
@@ -140,6 +146,18 @@ The `flushSync()` function can be used to flush any pending effects synchronousl
140146

141147
This restriction only applies when using the `experimental.async` option, which will be active by default in Svelte 6.
142148

149+
### fork_discarded
150+
151+
```
152+
Cannot commit a fork that was already discarded
153+
```
154+
155+
### fork_timing
156+
157+
```
158+
Cannot create a fork inside an effect or when state changes are pending
159+
```
160+
143161
### get_abort_signal_outside_reaction
144162

145163
```

packages/svelte/CHANGELOG.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,81 @@
11
# svelte
22

3+
## 5.43.2
4+
5+
### Patch Changes
6+
7+
- fix: treat each blocks with async dependencies as uncontrolled ([#17077](https://github.com/sveltejs/svelte/pull/17077))
8+
9+
## 5.43.1
10+
11+
### Patch Changes
12+
13+
- fix: transform `$bindable` after `await` expressions ([#17066](https://github.com/sveltejs/svelte/pull/17066))
14+
15+
## 5.43.0
16+
17+
### Minor Changes
18+
19+
- feat: out-of-order rendering ([#17038](https://github.com/sveltejs/svelte/pull/17038))
20+
21+
### Patch Changes
22+
23+
- fix: settle batch after DOM updates ([#17054](https://github.com/sveltejs/svelte/pull/17054))
24+
25+
## 5.42.3
26+
27+
### Patch Changes
28+
29+
- fix: handle `<svelte:head>` rendered asynchronously ([#17052](https://github.com/sveltejs/svelte/pull/17052))
30+
31+
- fix: don't restore batch in `#await` ([#17051](https://github.com/sveltejs/svelte/pull/17051))
32+
33+
## 5.42.2
34+
35+
### Patch Changes
36+
37+
- fix: better error message for global variable assignments ([#17036](https://github.com/sveltejs/svelte/pull/17036))
38+
39+
- chore: tweak memoizer logic ([#17042](https://github.com/sveltejs/svelte/pull/17042))
40+
41+
## 5.42.1
42+
43+
### Patch Changes
44+
45+
- fix: ignore fork `discard()` after `commit()` ([#17034](https://github.com/sveltejs/svelte/pull/17034))
46+
47+
## 5.42.0
48+
49+
### Minor Changes
50+
51+
- feat: experimental `fork` API ([#17004](https://github.com/sveltejs/svelte/pull/17004))
52+
53+
### Patch Changes
54+
55+
- fix: always allow `setContext` before first await in component ([#17031](https://github.com/sveltejs/svelte/pull/17031))
56+
57+
- fix: less confusing names for inspect errors ([#17026](https://github.com/sveltejs/svelte/pull/17026))
58+
59+
## 5.41.4
60+
61+
### Patch Changes
62+
63+
- fix: take into account static blocks when determining transition locality ([#17018](https://github.com/sveltejs/svelte/pull/17018))
64+
65+
- fix: coordinate mount of snippets with await expressions ([#17021](https://github.com/sveltejs/svelte/pull/17021))
66+
67+
- fix: better optimization of await expressions ([#17025](https://github.com/sveltejs/svelte/pull/17025))
68+
69+
- fix: flush pending changes after rendering `failed` snippet ([#16995](https://github.com/sveltejs/svelte/pull/16995))
70+
71+
## 5.41.3
72+
73+
### Patch Changes
74+
75+
- chore: exclude vite optimized deps from stack traces ([#17008](https://github.com/sveltejs/svelte/pull/17008))
76+
77+
- perf: skip repeatedly traversing the same derived ([#17016](https://github.com/sveltejs/svelte/pull/17016))
78+
379
## 5.41.2
480

581
### Patch Changes

packages/svelte/messages/client-errors/errors.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ $effect(() => {
100100

101101
Often when encountering this issue, the value in question shouldn't be state (for example, if you are pushing to a `logs` array in an effect, make `logs` a normal array rather than `$state([])`). In the rare cases where you really _do_ need to write to state in an effect — [which you should avoid]($effect#When-not-to-use-$effect) — you can read the state with [untrack](svelte#untrack) to avoid adding it as a dependency.
102102

103+
## experimental_async_fork
104+
105+
> Cannot use `fork(...)` unless the `experimental.async` compiler option is `true`
106+
103107
## flush_sync_in_effect
104108

105109
> Cannot use `flushSync` inside an effect
@@ -108,6 +112,14 @@ The `flushSync()` function can be used to flush any pending effects synchronousl
108112

109113
This restriction only applies when using the `experimental.async` option, which will be active by default in Svelte 6.
110114

115+
## fork_discarded
116+
117+
> Cannot commit a fork that was already discarded
118+
119+
## fork_timing
120+
121+
> Cannot create a fork inside an effect or when state changes are pending
122+
111123
## get_abort_signal_outside_reaction
112124

113125
> `getAbortSignal()` can only be called inside an effect or derived

packages/svelte/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "svelte",
33
"description": "Cybernetically enhanced web apps",
44
"license": "MIT",
5-
"version": "5.41.2",
5+
"version": "5.43.2",
66
"type": "module",
77
"types": "./types/index.d.ts",
88
"engines": {

packages/svelte/src/compiler/phases/1-parse/state/element.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ import { decode_character_references } from '../utils/html.js';
99
import * as e from '../../../errors.js';
1010
import * as w from '../../../warnings.js';
1111
import { create_fragment } from '../utils/create.js';
12-
import { create_attribute, create_expression_metadata, is_element_node } from '../../nodes.js';
12+
import { create_attribute, ExpressionMetadata, is_element_node } from '../../nodes.js';
1313
import { get_attribute_expression, is_expression_attribute } from '../../../utils/ast.js';
1414
import { closing_tag_omitted } from '../../../../html-tree-validation.js';
1515
import { list } from '../../../utils/string.js';
16-
import { regex_whitespace } from '../../patterns.js';
1716

1817
const regex_invalid_unquoted_attribute_value = /^(\/>|[\s"'=<>`])/;
1918
const regex_closing_textarea_tag = /^<\/textarea(\s[^>]*)?>/i;
@@ -297,7 +296,7 @@ export default function element(parser) {
297296
element.tag = get_attribute_expression(definition);
298297
}
299298

300-
element.metadata.expression = create_expression_metadata();
299+
element.metadata.expression = new ExpressionMetadata();
301300
}
302301

303302
if (is_top_level_script_or_style) {
@@ -508,7 +507,7 @@ function read_attribute(parser) {
508507
end: parser.index,
509508
expression,
510509
metadata: {
511-
expression: create_expression_metadata()
510+
expression: new ExpressionMetadata()
512511
}
513512
};
514513

@@ -528,7 +527,7 @@ function read_attribute(parser) {
528527
end: parser.index,
529528
expression,
530529
metadata: {
531-
expression: create_expression_metadata()
530+
expression: new ExpressionMetadata()
532531
}
533532
};
534533

@@ -568,7 +567,7 @@ function read_attribute(parser) {
568567
name
569568
},
570569
metadata: {
571-
expression: create_expression_metadata()
570+
expression: new ExpressionMetadata()
572571
}
573572
};
574573

@@ -628,7 +627,7 @@ function read_attribute(parser) {
628627
modifiers: /** @type {Array<'important'>} */ (modifiers),
629628
value,
630629
metadata: {
631-
expression: create_expression_metadata()
630+
expression: new ExpressionMetadata()
632631
}
633632
};
634633
}
@@ -658,7 +657,7 @@ function read_attribute(parser) {
658657
name: directive_name,
659658
expression,
660659
metadata: {
661-
expression: create_expression_metadata()
660+
expression: new ExpressionMetadata()
662661
}
663662
};
664663

@@ -824,7 +823,7 @@ function read_sequence(parser, done, location) {
824823
end: parser.index,
825824
expression,
826825
metadata: {
827-
expression: create_expression_metadata()
826+
expression: new ExpressionMetadata()
828827
}
829828
};
830829

packages/svelte/src/compiler/phases/1-parse/state/tag.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/** @import { Parser } from '../index.js' */
44
import { walk } from 'zimmerframe';
55
import * as e from '../../../errors.js';
6-
import { create_expression_metadata } from '../../nodes.js';
6+
import { ExpressionMetadata } from '../../nodes.js';
77
import { parse_expression_at } from '../acorn.js';
88
import read_pattern from '../read/context.js';
99
import read_expression, { get_loose_identifier } from '../read/expression.js';
@@ -42,7 +42,7 @@ export default function tag(parser) {
4242
end: parser.index,
4343
expression,
4444
metadata: {
45-
expression: create_expression_metadata()
45+
expression: new ExpressionMetadata()
4646
}
4747
});
4848
}
@@ -65,7 +65,7 @@ function open(parser) {
6565
consequent: create_fragment(),
6666
alternate: null,
6767
metadata: {
68-
expression: create_expression_metadata()
68+
expression: new ExpressionMetadata()
6969
}
7070
});
7171

@@ -249,7 +249,7 @@ function open(parser) {
249249
then: null,
250250
catch: null,
251251
metadata: {
252-
expression: create_expression_metadata()
252+
expression: new ExpressionMetadata()
253253
}
254254
});
255255

@@ -334,7 +334,7 @@ function open(parser) {
334334
expression,
335335
fragment: create_fragment(),
336336
metadata: {
337-
expression: create_expression_metadata()
337+
expression: new ExpressionMetadata()
338338
}
339339
});
340340

@@ -477,7 +477,7 @@ function next(parser) {
477477
consequent: create_fragment(),
478478
alternate: null,
479479
metadata: {
480-
expression: create_expression_metadata()
480+
expression: new ExpressionMetadata()
481481
}
482482
});
483483

@@ -643,7 +643,7 @@ function special(parser) {
643643
end: parser.index,
644644
expression,
645645
metadata: {
646-
expression: create_expression_metadata()
646+
expression: new ExpressionMetadata()
647647
}
648648
});
649649

@@ -721,7 +721,7 @@ function special(parser) {
721721
end: parser.index - 1
722722
},
723723
metadata: {
724-
expression: create_expression_metadata()
724+
expression: new ExpressionMetadata()
725725
}
726726
});
727727
}
@@ -748,7 +748,7 @@ function special(parser) {
748748
end: parser.index,
749749
expression: /** @type {AST.RenderTag['expression']} */ (expression),
750750
metadata: {
751-
expression: create_expression_metadata(),
751+
expression: new ExpressionMetadata(),
752752
dynamic: false,
753753
arguments: [],
754754
path: [],

0 commit comments

Comments
 (0)