Skip to content

Commit 4b8b038

Browse files
committed
Merge branch 'main' into deriveds-in-constructor
2 parents 7ac1696 + 83d0c58 commit 4b8b038

File tree

20 files changed

+177
-72
lines changed

20 files changed

+177
-72
lines changed

.changeset/dirty-pianos-sparkle.md

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

.changeset/nine-laws-rush.md

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

documentation/docs/02-runes/04-$effect.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ Teardown functions also run when the effect is destroyed, which happens when its
7474

7575
`$effect` automatically picks up any reactive values (`$state`, `$derived`, `$props`) that are _synchronously_ read inside its function body (including indirectly, via function calls) and registers them as dependencies. When those dependencies change, the `$effect` schedules a re-run.
7676

77+
If `$state` and `$derived` are used directly inside the `$effect` (for example, during creation of a [reactive class](https://svelte.dev/docs/svelte/$state#Classes)), those values will _not_ be treated as dependencies.
78+
7779
Values that are read _asynchronously_ — after an `await` or inside a `setTimeout`, for example — will not be tracked. Here, the canvas will be repainted when `color` changes, but not when `size` changes ([demo](/playground/untitled#H4sIAAAAAAAAE31T246bMBD9lZF3pWSlBEirfaEQqdo_2PatVIpjBrDkGGQPJGnEv1e2IZfVal-wfHzmzJyZ4cIqqdCy9M-F0blDlnqArZjmB3f72XWRHVCRw_bc4me4aDWhJstSlllhZEfbQhekkMDKfwg5PFvihMvX5OXH_CJa1Zrb0-Kpqr5jkiwC48rieuDWQbqgZ6wqFLRcvkC-hYvnkWi1dWqa8ESQTxFRjfQWsOXiWzmr0sSLhEJu3p1YsoJkNUcdZUnN9dagrBu6FVRQHAM10sJRKgUG16bXcGxQ44AGdt7SDkTDdY02iqLHnJVU6hedlWuIp94JW6Tf8oBt_8GdTxlF0b4n0C35ZLBzXb3mmYn3ae6cOW74zj0YVzDNYXRHFt9mprNgHfZSl6mzml8CMoLvTV6wTZIUDEJv5us2iwMtiJRyAKG4tXnhl8O0yhbML0Wm-B7VNlSSSd31BG7z8oIZZ6dgIffAVY_5xdU9Qrz1Bnx8fCfwtZ7v8Qc9j3nB8PqgmMWlHIID6-bkVaPZwDySfWtKNGtquxQ23Qlsq2QJT0KIqb8dL0up6xQ2eIBkAg_c1FI_YqW0neLnFCqFpwmreedJYT7XX8FVOBfwWRhXstZrSXiwKQjUhOZeMIleb5JZfHWn2Yq5pWEpmR7Hv-N_wEqT8hEEAAA=)):
7880

7981
```ts

packages/svelte/CHANGELOG.md

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

3+
## 5.24.0
4+
5+
### Minor Changes
6+
7+
- feat: allow state created in deriveds/effects to be written/read locally without self-invalidation ([#15553](https://github.com/sveltejs/svelte/pull/15553))
8+
9+
### Patch Changes
10+
11+
- fix: check if DOM prototypes are extensible ([#15569](https://github.com/sveltejs/svelte/pull/15569))
12+
13+
- Keep inlined trailing JSDoc comments of properties when running svelte-migrate ([#15567](https://github.com/sveltejs/svelte/pull/15567))
14+
15+
- fix: simplify set calls for proxyable values ([#15548](https://github.com/sveltejs/svelte/pull/15548))
16+
17+
- fix: don't depend on deriveds created inside the current reaction ([#15564](https://github.com/sveltejs/svelte/pull/15564))
18+
319
## 5.23.2
420

521
### Patch Changes

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.23.2",
5+
"version": "5.24.0",
66
"type": "module",
77
"types": "./types/index.d.ts",
88
"engines": {

packages/svelte/src/compiler/migrate/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,7 +1592,6 @@ function extract_type_and_comment(declarator, state, path) {
15921592
const comment_start = /** @type {any} */ (comment_node)?.start;
15931593
const comment_end = /** @type {any} */ (comment_node)?.end;
15941594
let comment = comment_node && str.original.substring(comment_start, comment_end);
1595-
15961595
if (comment_node) {
15971596
str.update(comment_start, comment_end, '');
15981597
}
@@ -1673,6 +1672,11 @@ function extract_type_and_comment(declarator, state, path) {
16731672
state.has_type_or_fallback = true;
16741673
const match = /@type {(.+)}/.exec(comment_node.value);
16751674
if (match) {
1675+
// try to find JSDoc comments after a hyphen `-`
1676+
const jsdoc_comment = /@type {.+} (?:\w+|\[.*?\]) - (.+)/.exec(comment_node.value);
1677+
if (jsdoc_comment) {
1678+
cleaned_comment += jsdoc_comment[1]?.trim();
1679+
}
16761680
return {
16771681
type: match[1],
16781682
comment: cleaned_comment,
@@ -1693,7 +1697,6 @@ function extract_type_and_comment(declarator, state, path) {
16931697
};
16941698
}
16951699
}
1696-
16971700
return {
16981701
type: 'any',
16991702
comment: state.uses_ts ? comment : cleaned_comment,

packages/svelte/src/internal/client/dom/operations.js

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { hydrate_node, hydrating, set_hydrate_node } from './hydration.js';
33
import { DEV } from 'esm-env';
44
import { init_array_prototype_warnings } from '../dev/equality.js';
5-
import { get_descriptor } from '../../shared/utils.js';
5+
import { get_descriptor, is_extensible } from '../../shared/utils.js';
66

77
// export these for reference in the compiled code, making global name deduplication unnecessary
88
/** @type {Window} */
@@ -34,26 +34,31 @@ export function init_operations() {
3434

3535
var element_prototype = Element.prototype;
3636
var node_prototype = Node.prototype;
37+
var text_prototype = Text.prototype;
3738

3839
// @ts-ignore
3940
first_child_getter = get_descriptor(node_prototype, 'firstChild').get;
4041
// @ts-ignore
4142
next_sibling_getter = get_descriptor(node_prototype, 'nextSibling').get;
4243

43-
// the following assignments improve perf of lookups on DOM nodes
44-
// @ts-expect-error
45-
element_prototype.__click = undefined;
46-
// @ts-expect-error
47-
element_prototype.__className = undefined;
48-
// @ts-expect-error
49-
element_prototype.__attributes = null;
50-
// @ts-expect-error
51-
element_prototype.__style = undefined;
52-
// @ts-expect-error
53-
element_prototype.__e = undefined;
54-
55-
// @ts-expect-error
56-
Text.prototype.__t = undefined;
44+
if (is_extensible(element_prototype)) {
45+
// the following assignments improve perf of lookups on DOM nodes
46+
// @ts-expect-error
47+
element_prototype.__click = undefined;
48+
// @ts-expect-error
49+
element_prototype.__className = undefined;
50+
// @ts-expect-error
51+
element_prototype.__attributes = null;
52+
// @ts-expect-error
53+
element_prototype.__style = undefined;
54+
// @ts-expect-error
55+
element_prototype.__e = undefined;
56+
}
57+
58+
if (is_extensible(text_prototype)) {
59+
// @ts-expect-error
60+
text_prototype.__t = undefined;
61+
}
5762

5863
if (DEV) {
5964
// @ts-expect-error

packages/svelte/src/internal/client/index.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export {
101101
text,
102102
props_id
103103
} from './dom/template.js';
104-
export { derived, derived_safe_equal } from './reactivity/deriveds.js';
104+
export { user_derived as derived, derived_safe_equal } from './reactivity/deriveds.js';
105105
export {
106106
effect_tracking,
107107
effect_root,
@@ -113,14 +113,7 @@ export {
113113
user_effect,
114114
user_pre_effect
115115
} from './reactivity/effects.js';
116-
export {
117-
mutable_source,
118-
mutate,
119-
set,
120-
source as state,
121-
update,
122-
update_pre
123-
} from './reactivity/sources.js';
116+
export { mutable_source, mutate, set, state, update, update_pre } from './reactivity/sources.js';
124117
export {
125118
prop,
126119
rest_props,

packages/svelte/src/internal/client/proxy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
object_prototype
1111
} from '../shared/utils.js';
1212
import { check_ownership, widen_ownership } from './dev/ownership.js';
13-
import { source, set } from './reactivity/sources.js';
13+
import { state as source, set } from './reactivity/sources.js';
1414
import { STATE_SYMBOL, STATE_SYMBOL_METADATA } from './constants.js';
1515
import { UNINITIALIZED } from '../../constants.js';
1616
import * as e from './errors.js';

packages/svelte/src/internal/client/reactivity/deriveds.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
skip_reaction,
99
update_reaction,
1010
increment_write_version,
11-
set_active_effect
11+
set_active_effect,
12+
push_reaction_value
1213
} from '../runtime.js';
1314
import { equals, safe_equals } from './equality.js';
1415
import * as e from '../errors.js';
@@ -61,6 +62,19 @@ export function derived(fn) {
6162
return signal;
6263
}
6364

65+
/**
66+
* @template V
67+
* @param {() => V} fn
68+
* @returns {Derived<V>}
69+
*/
70+
export function user_derived(fn) {
71+
const d = derived(fn);
72+
73+
push_reaction_value(d);
74+
75+
return d;
76+
}
77+
6478
/**
6579
* @template V
6680
* @param {() => V} fn

packages/svelte/src/internal/client/reactivity/sources.js

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import {
1515
set_reaction_sources,
1616
check_dirtiness,
1717
untracking,
18-
is_destroying_effect
18+
is_destroying_effect,
19+
push_reaction_value
1920
} from '../runtime.js';
2021
import { equals, safe_equals } from './equality.js';
2122
import {
@@ -64,14 +65,6 @@ export function source(v, stack) {
6465
wv: 0
6566
};
6667

67-
if (active_reaction !== null && active_reaction.f & EFFECT_IS_UPDATING) {
68-
if (reaction_sources === null) {
69-
set_reaction_sources([signal]);
70-
} else {
71-
reaction_sources.push(signal);
72-
}
73-
}
74-
7568
if (DEV && tracing_mode_flag) {
7669
signal.created = stack ?? get_stack('CreatedAt');
7770
signal.debug = null;
@@ -80,6 +73,19 @@ export function source(v, stack) {
8073
return signal;
8174
}
8275

76+
/**
77+
* @template V
78+
* @param {V} v
79+
* @param {Error | null} [stack]
80+
*/
81+
export function state(v, stack) {
82+
const s = source(v, stack);
83+
84+
push_reaction_value(s);
85+
86+
return s;
87+
}
88+
8389
/**
8490
* @template V
8591
* @param {V} initial_value

packages/svelte/src/internal/client/runtime.js

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,17 @@ export function set_reaction_sources(sources) {
101101
reaction_sources = sources;
102102
}
103103

104+
/** @param {Value} value */
105+
export function push_reaction_value(value) {
106+
if (active_reaction !== null && active_reaction.f & EFFECT_IS_UPDATING) {
107+
if (reaction_sources === null) {
108+
set_reaction_sources([value]);
109+
} else {
110+
reaction_sources.push(value);
111+
}
112+
}
113+
}
114+
104115
/**
105116
* The dependencies of the reaction that is currently being executed. In many cases,
106117
* the dependencies are unchanged between runs, and so this will be `null` unless
@@ -875,21 +886,23 @@ export function get(signal) {
875886

876887
// Register the dependency on the current reaction signal.
877888
if (active_reaction !== null && !untracking) {
878-
var deps = active_reaction.deps;
879-
if (signal.rv < read_version) {
880-
signal.rv = read_version;
881-
// If the signal is accessing the same dependencies in the same
882-
// order as it did last time, increment `skipped_deps`
883-
// rather than updating `new_deps`, which creates GC cost
884-
if (new_deps === null && deps !== null && deps[skipped_deps] === signal) {
885-
skipped_deps++;
886-
} else if (new_deps === null) {
887-
new_deps = [signal];
888-
} else if (!skip_reaction || !new_deps.includes(signal)) {
889-
// Normally we can push duplicated dependencies to `new_deps`, but if we're inside
890-
// an unowned derived because skip_reaction is true, then we need to ensure that
891-
// we don't have duplicates
892-
new_deps.push(signal);
889+
if (!reaction_sources?.includes(signal)) {
890+
var deps = active_reaction.deps;
891+
if (signal.rv < read_version) {
892+
signal.rv = read_version;
893+
// If the signal is accessing the same dependencies in the same
894+
// order as it did last time, increment `skipped_deps`
895+
// rather than updating `new_deps`, which creates GC cost
896+
if (new_deps === null && deps !== null && deps[skipped_deps] === signal) {
897+
skipped_deps++;
898+
} else if (new_deps === null) {
899+
new_deps = [signal];
900+
} else if (!skip_reaction || !new_deps.includes(signal)) {
901+
// Normally we can push duplicated dependencies to `new_deps`, but if we're inside
902+
// an unowned derived because skip_reaction is true, then we need to ensure that
903+
// we don't have duplicates
904+
new_deps.push(signal);
905+
}
893906
}
894907
}
895908
} else if (

packages/svelte/src/internal/shared/utils.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export var get_descriptors = Object.getOwnPropertyDescriptors;
1010
export var object_prototype = Object.prototype;
1111
export var array_prototype = Array.prototype;
1212
export var get_prototype_of = Object.getPrototypeOf;
13+
export var is_extensible = Object.isExtensible;
1314

1415
/**
1516
* @param {any} thing

packages/svelte/src/version.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
* The current version, as set in package.json.
55
* @type {string}
66
*/
7-
export const VERSION = '5.23.2';
7+
export const VERSION = '5.24.0';
88
export const PUBLIC_VERSION = '5';

packages/svelte/tests/migrate/samples/jsdoc-with-comments/input.svelte

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
*/
2222
export let type_no_comment;
2323
24+
/** @type {boolean} type_with_comment - One-line declaration with comment */
25+
export let type_with_comment;
26+
2427
/**
2528
* This is optional
2629
*/
@@ -40,4 +43,10 @@
4043
export let inline_multiline_trailing_comment = 'world'; /*
4144
* this is a same-line trailing multiline comment
4245
**/
46+
47+
/** @type {number} [default_value=1] */
48+
export let default_value = 1;
49+
50+
/** @type {number} [comment_default_value=1] - This has a comment and an optional value. */
51+
export let comment_default_value = 1;
4352
</script>

packages/svelte/tests/migrate/samples/jsdoc-with-comments/output.svelte

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,33 @@
99
1010
1111
12+
13+
14+
15+
1216
1317
1418
1519
20+
1621
1722
23+
1824
/**
1925
* @typedef {Object} Props
2026
* @property {string} comment - My wonderful comment
2127
* @property {number} another_comment - My wonderful other comment
2228
* @property {any} one_line - one line comment
2329
* @property {any} no_comment
2430
* @property {boolean} type_no_comment
31+
* @property {boolean} type_with_comment - One-line declaration with comment
2532
* @property {any} [optional] - This is optional
2633
* @property {any} inline_commented - this should stay a comment
2734
* @property {any} inline_commented_merged - This comment should be merged - with this inline comment
2835
* @property {string} [inline_multiline_leading_comment] - this is a same-line leading multiline comment
2936
* @property {string} [inline_multiline_trailing_comment] - this is a same-line trailing multiline comment
37+
* @property {number} [default_value]
38+
* @property {number} [comment_default_value] - This has a comment and an optional value.
3039
*/
3140
3241
/** @type {Props} */
@@ -36,10 +45,13 @@
3645
one_line,
3746
no_comment,
3847
type_no_comment,
48+
type_with_comment,
3949
optional = {stuff: true},
4050
inline_commented,
4151
inline_commented_merged,
4252
inline_multiline_leading_comment = 'world',
43-
inline_multiline_trailing_comment = 'world'
53+
inline_multiline_trailing_comment = 'world',
54+
default_value = 1,
55+
comment_default_value = 1
4456
} = $props();
4557
</script>

packages/svelte/tests/runtime-runes/samples/effect-cleanup/_config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ export default test({
1010
flushSync(() => {
1111
b1.click();
1212
});
13-
assert.deepEqual(logs, ['init 0', 'cleanup 2', null, 'init 2', 'cleanup 4', null, 'init 4']);
13+
assert.deepEqual(logs, ['init 0']);
1414
}
1515
});

0 commit comments

Comments
 (0)