From 26c9068eab8dd4d4e5f0e3fdbedd8a58409947b7 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Tue, 5 Mar 2024 16:16:52 +0000 Subject: [PATCH 1/3] fix: untrack console.log calls on REPL (#10706) --- sites/svelte-5-preview/src/lib/Output/Viewer.svelte | 8 +++++++- sites/svelte-5-preview/src/lib/workers/bundler/index.js | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/sites/svelte-5-preview/src/lib/Output/Viewer.svelte b/sites/svelte-5-preview/src/lib/Output/Viewer.svelte index 1bd921a523..322c68c5f0 100644 --- a/sites/svelte-5-preview/src/lib/Output/Viewer.svelte +++ b/sites/svelte-5-preview/src/lib/Output/Viewer.svelte @@ -131,7 +131,13 @@ const __repl_exports = ${$bundle.client?.code}; { - const { mount, unmount, App } = __repl_exports; + const { mount, unmount, App, untrack } = __repl_exports; + + const console_log = console.log + + console.log = function (...v) { + return untrack(() => console_log.apply(this, v)); + } const component = mount(App, { target: document.body }); window.__unmount_previous = () => unmount(component); } diff --git a/sites/svelte-5-preview/src/lib/workers/bundler/index.js b/sites/svelte-5-preview/src/lib/workers/bundler/index.js index 920f8328eb..bd0ee9d67e 100644 --- a/sites/svelte-5-preview/src/lib/workers/bundler/index.js +++ b/sites/svelte-5-preview/src/lib/workers/bundler/index.js @@ -485,7 +485,7 @@ async function bundle({ uid, files }) { lookup.set('./__entry.js', { name: '__entry', source: ` - export { mount, unmount } from 'svelte'; + export { mount, unmount, untrack } from 'svelte'; export {default as App} from './App.svelte'; `, type: 'js', From b3d0a0695ac017297247d1625f75cf01a129400f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 20:07:11 +0000 Subject: [PATCH 2/3] Version Packages (next) (#10701) Co-authored-by: github-actions[bot] --- .changeset/pre.json | 3 +++ packages/svelte/CHANGELOG.md | 10 ++++++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index 5d4b668ce9..b7f5e30134 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -228,6 +228,7 @@ "seven-deers-jam", "seven-hornets-smile", "seven-jobs-sniff", + "seven-masks-end", "seven-ravens-check", "shaggy-cameras-live", "sharp-gorillas-impress", @@ -260,6 +261,7 @@ "sour-weeks-fix", "spicy-jeans-deliver", "spicy-plums-admire", + "spotty-houses-search", "spotty-pens-agree", "spotty-rocks-destroy", "spotty-spiders-compare", @@ -320,6 +322,7 @@ "violet-pigs-jam", "weak-terms-destroy", "wet-games-fly", + "wet-wombats-repeat", "wicked-clouds-exercise", "wicked-doors-train", "wicked-hairs-cheer", diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 0fce88cce7..46f96db13a 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,15 @@ # svelte +## 5.0.0-next.72 + +### Patch Changes + +- fix: adjust keyed each block equality handling ([#10699](https://github.com/sveltejs/svelte/pull/10699)) + +- fix: improve indexed each equality ([#10702](https://github.com/sveltejs/svelte/pull/10702)) + +- fix: prevent snippet children conflict ([#10700](https://github.com/sveltejs/svelte/pull/10700)) + ## 5.0.0-next.71 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index e8d9e43c1c..8ab2452936 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.0.0-next.71", + "version": "5.0.0-next.72", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index 86694f4697..00875a7c69 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -6,5 +6,5 @@ * https://svelte.dev/docs/svelte-compiler#svelte-version * @type {string} */ -export const VERSION = '5.0.0-next.71'; +export const VERSION = '5.0.0-next.72'; export const PUBLIC_VERSION = '5'; From a5a566dfa74f39f0c8df744f920705e2bc6e5f69 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 5 Mar 2024 18:45:27 -0700 Subject: [PATCH 3/3] chore: tidy up (#10705) * tidy up * tidy up * tidy up * tidy up * remove redundant CLEAN * lint --------- Co-authored-by: Rich Harris --- .../internal/client/reactivity/deriveds.js | 18 ++++--- .../src/internal/client/reactivity/effects.js | 51 ++++++++++--------- .../src/internal/client/reactivity/sources.js | 26 +++++----- .../src/internal/client/reactivity/store.js | 28 +++++----- .../src/internal/client/reactivity/types.d.ts | 4 +- .../svelte/src/internal/client/runtime.js | 13 +++-- .../svelte/src/internal/client/types.d.ts | 12 ++--- packages/svelte/tests/signals/test.ts | 2 +- 8 files changed, 78 insertions(+), 76 deletions(-) diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index fe29bc4059..ef59b4b940 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -11,25 +11,27 @@ import { default_equals, safe_equal } from './equality.js'; */ /*#__NO_SIDE_EFFECTS__*/ export function derived(fn) { - const is_unowned = current_effect === null; - const flags = is_unowned ? DERIVED | UNOWNED : DERIVED; - const signal = /** @type {import('../types.js').Derived} */ ({ + let flags = DERIVED | CLEAN; + if (current_effect === null) flags |= UNOWNED; + + /** @type {import('#client').Derived} */ + const signal = { b: current_block, c: null, d: null, e: default_equals, - f: flags | CLEAN, + f: flags, i: fn, r: null, + // @ts-expect-error v: UNINITIALIZED, w: 0, x: null, y: null - }); + }; if (DEV) { - // @ts-expect-error - signal.inspect = new Set(); + /** @type {import('#client').DerivedDebug} */ (signal).inspect = new Set(); } if (current_consumer !== null) { @@ -42,7 +44,7 @@ export function derived(fn) { /** * @template V * @param {() => V} fn - * @returns {import('../types.js').Derived} + * @returns {import('#client').Derived} */ /*#__NO_SIDE_EFFECTS__*/ export function derived_safe_equal(fn) { diff --git a/packages/svelte/src/internal/client/reactivity/effects.js b/packages/svelte/src/internal/client/reactivity/effects.js index 2570f60bec..8ca43f8414 100644 --- a/packages/svelte/src/internal/client/reactivity/effects.js +++ b/packages/svelte/src/internal/client/reactivity/effects.js @@ -10,8 +10,8 @@ import { import { DIRTY, MANAGED, RENDER_EFFECT, EFFECT, PRE_EFFECT } from '../constants.js'; /** - * @param {import('../types.js').Reaction} target_signal - * @param {import('../types.js').Reaction} ref_signal + * @param {import('#client').Reaction} target_signal + * @param {import('#client').Reaction} ref_signal * @returns {void} */ export function push_reference(target_signal, ref_signal) { @@ -24,14 +24,14 @@ export function push_reference(target_signal, ref_signal) { } /** - * @param {import('../types.js').EffectType} type - * @param {(() => void | (() => void)) | ((b: import('../types.js').Block) => void | (() => void))} fn + * @param {import('./types.js').EffectType} type + * @param {(() => void | (() => void)) | ((b: import('#client').Block) => void | (() => void))} fn * @param {boolean} sync - * @param {null | import('../types.js').Block} block + * @param {null | import('#client').Block} block * @param {boolean} schedule - * @returns {import('../types.js').Effect} + * @returns {import('#client').Effect} */ -function internal_create_effect(type, fn, sync, block, schedule) { +function create_effect(type, fn, sync, block, schedule) { /** @type {import('#client').Effect} */ const signal = { b: block, @@ -54,13 +54,16 @@ function internal_create_effect(type, fn, sync, block, schedule) { push_reference(current_effect, signal); } } + if (schedule) { schedule_effect(signal, sync); } + return signal; } /** + * Internal representation of `$effect.active()` * @returns {boolean} */ export function effect_active() { @@ -70,7 +73,7 @@ export function effect_active() { /** * Internal representation of `$effect(...)` * @param {() => void | (() => void)} fn - * @returns {import('../types.js').Effect} + * @returns {import('#client').Effect} */ export function user_effect(fn) { if (current_effect === null) { @@ -85,7 +88,7 @@ export function user_effect(fn) { current_component_context !== null && !current_component_context.m; - const effect = internal_create_effect( + const effect = create_effect( EFFECT, fn, false, @@ -94,9 +97,7 @@ export function user_effect(fn) { ); if (apply_component_effect_heuristics) { - const context = /** @type {import('../types.js').ComponentContext} */ ( - current_component_context - ); + const context = /** @type {import('#client').ComponentContext} */ (current_component_context); (context.e ??= []).push(effect); } @@ -117,33 +118,33 @@ export function user_root_effect(fn) { /** * @param {() => void | (() => void)} fn - * @returns {import('../types.js').Effect} + * @returns {import('#client').Effect} */ export function effect(fn) { - return internal_create_effect(EFFECT, fn, false, current_block, true); + return create_effect(EFFECT, fn, false, current_block, true); } /** * @param {() => void | (() => void)} fn - * @returns {import('../types.js').Effect} + * @returns {import('#client').Effect} */ export function managed_effect(fn) { - return internal_create_effect(EFFECT | MANAGED, fn, false, current_block, true); + return create_effect(EFFECT | MANAGED, fn, false, current_block, true); } /** * @param {() => void | (() => void)} fn * @param {boolean} sync - * @returns {import('../types.js').Effect} + * @returns {import('#client').Effect} */ export function managed_pre_effect(fn, sync) { - return internal_create_effect(PRE_EFFECT | MANAGED, fn, sync, current_block, true); + return create_effect(PRE_EFFECT | MANAGED, fn, sync, current_block, true); } /** * Internal representation of `$effect.pre(...)` * @param {() => void | (() => void)} fn - * @returns {import('../types.js').Effect} + * @returns {import('#client').Effect} */ export function pre_effect(fn) { if (current_effect === null) { @@ -155,7 +156,7 @@ export function pre_effect(fn) { ); } const sync = current_effect !== null && (current_effect.f & RENDER_EFFECT) !== 0; - return internal_create_effect( + return create_effect( PRE_EFFECT, () => { const val = fn(); @@ -173,24 +174,24 @@ export function pre_effect(fn) { * bindings which are in later effects. However, we don't use a pre_effect directly as we don't want to flush anything. * * @param {() => void | (() => void)} fn - * @returns {import('../types.js').Effect} + * @returns {import('#client').Effect} */ export function invalidate_effect(fn) { - return internal_create_effect(PRE_EFFECT, fn, true, current_block, true); + return create_effect(PRE_EFFECT, fn, true, current_block, true); } /** - * @template {import('../types.js').Block} B + * @template {import('#client').Block} B * @param {(block: B) => void | (() => void)} fn * @param {any} block * @param {any} managed * @param {any} sync - * @returns {import('../types.js').Effect} + * @returns {import('#client').Effect} */ export function render_effect(fn, block = current_block, managed = false, sync = true) { let flags = RENDER_EFFECT; if (managed) { flags |= MANAGED; } - return internal_create_effect(flags, /** @type {any} */ (fn), sync, block, true); + return create_effect(flags, /** @type {any} */ (fn), sync, block, true); } diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js index 73174f208f..60403ddc3d 100644 --- a/packages/svelte/src/internal/client/reactivity/sources.js +++ b/packages/svelte/src/internal/client/reactivity/sources.js @@ -23,31 +23,31 @@ import { CLEAN, DERIVED, DIRTY, MANAGED, SOURCE } from '../constants.js'; /** * @template V - * @param {V} initial_value - * @returns {import('../types.js').Source} + * @param {V} value + * @returns {import('#client').Source} */ /*#__NO_SIDE_EFFECTS__*/ -export function source(initial_value) { +export function source(value) { /** @type {import('#client').Source} */ - const signal = { + const source = { c: null, e: default_equals, f: SOURCE | CLEAN, - v: initial_value, + v: value, w: 0 }; if (DEV) { - /** @type {import('#client').SourceDebug} */ (signal).inspect = new Set(); + /** @type {import('#client').SourceDebug} */ (source).inspect = new Set(); } - return signal; + return source; } /** * @template V * @param {V} initial_value - * @returns {import('../types.js').Source} + * @returns {import('#client').Source} */ /*#__NO_SIDE_EFFECTS__*/ export function mutable_source(initial_value) { @@ -65,7 +65,7 @@ export function mutable_source(initial_value) { /** * @template V - * @param {import('./types.js').Source} signal + * @param {import('#client').Source} signal * @param {V} value * @returns {void} */ @@ -75,7 +75,7 @@ export function set_sync(signal, value) { /** * @template V - * @param {import('./types.js').Value} source + * @param {import('#client').Value} source * @param {V} value */ export function mutate(source, value) { @@ -88,7 +88,7 @@ export function mutate(source, value) { /** * @template V - * @param {import('./types.js').Source} signal + * @param {import('#client').Source} signal * @param {V} value * @returns {V} */ @@ -150,9 +150,9 @@ export function set(signal, value) { // @ts-expect-error if (DEV && signal.inspect) { if (is_batching_effect) { - set_last_inspected_signal(/** @type {import('./types.js').ValueDebug} */ (signal)); + set_last_inspected_signal(/** @type {import('#client').ValueDebug} */ (signal)); } else { - for (const fn of /** @type {import('./types.js').ValueDebug} */ (signal).inspect) fn(); + for (const fn of /** @type {import('#client').ValueDebug} */ (signal).inspect) fn(); } } } diff --git a/packages/svelte/src/internal/client/reactivity/store.js b/packages/svelte/src/internal/client/reactivity/store.js index 3cf2867139..fe2ef12971 100644 --- a/packages/svelte/src/internal/client/reactivity/store.js +++ b/packages/svelte/src/internal/client/reactivity/store.js @@ -10,13 +10,13 @@ import { mutable_source, set } from './sources.js'; * signal that will be updated when the store is. The store references container is needed to * track reassignments to stores and to track the correct component context. * @template V - * @param {import('../types.js').Store | null | undefined} store + * @param {import('#client').Store | null | undefined} store * @param {string} store_name - * @param {import('../types.js').StoreReferencesContainer} stores + * @param {import('#client').StoreReferencesContainer} stores * @returns {V} */ export function store_get(store, store_name, stores) { - /** @type {import('../types.js').StoreReferencesContainer[''] | undefined} */ + /** @type {import('#client').StoreReferencesContainer[''] | undefined} */ let entry = stores[store_name]; const is_new = entry === undefined; @@ -29,8 +29,8 @@ export function store_get(store, store_name, stores) { }; // TODO: can we remove this code? it was refactored out when we split up source/comptued signals // push_destroy_fn(entry.value, () => { - // /** @type {import('../types.js').StoreReferencesContainer['']} */ (entry).last_value = - // /** @type {import('../types.js').StoreReferencesContainer['']} */ (entry).value.value; + // /** @type {import('#client').StoreReferencesContainer['']} */ (entry).last_value = + // /** @type {import('#client').StoreReferencesContainer['']} */ (entry).value.value; // }); stores[store_name] = entry; } @@ -49,8 +49,8 @@ export function store_get(store, store_name, stores) { /** * @template V - * @param {import('../types.js').Store | null | undefined} store - * @param {import('../types.js').Source} source + * @param {import('#client').Store | null | undefined} store + * @param {import('#client').Source} source */ function connect_store_to_signal(store, source) { if (store == null) { @@ -70,7 +70,7 @@ function connect_store_to_signal(store, source) { /** * Sets the new value of a store and returns that value. * @template V - * @param {import('../types.js').Store} store + * @param {import('#client').Store} store * @param {V} value * @returns {V} */ @@ -81,7 +81,7 @@ export function store_set(store, value) { /** * Unsubscribes from all auto-subscribed stores on destroy - * @param {import('../types.js').StoreReferencesContainer} stores + * @param {import('#client').StoreReferencesContainer} stores */ export function unsubscribe_on_destroy(stores) { on_destroy(() => { @@ -97,7 +97,7 @@ export function unsubscribe_on_destroy(stores) { /** * Updates a store with a new value. - * @param {import('../types.js').Store} store the store to update + * @param {import('#client').Store} store the store to update * @param {any} expression the expression that mutates the store * @param {V} new_value the new store value * @template V @@ -110,18 +110,18 @@ export function mutate_store(store, expression, new_value) { /** * @template V * @param {unknown} val - * @returns {val is import('../types.js').Store} + * @returns {val is import('#client').Store} */ export function is_store(val) { return ( typeof val === 'object' && val !== null && - typeof (/** @type {import('../types.js').Store} */ (val).subscribe) === 'function' + typeof (/** @type {import('#client').Store} */ (val).subscribe) === 'function' ); } /** - * @param {import('../types.js').Store} store + * @param {import('#client').Store} store * @param {number} store_value * @param {1 | -1} [d] * @returns {number} @@ -132,7 +132,7 @@ export function update_store(store, store_value, d = 1) { } /** - * @param {import('../types.js').Store} store + * @param {import('#client').Store} store * @param {number} store_value * @param {1 | -1} [d] * @returns {number} diff --git a/packages/svelte/src/internal/client/reactivity/types.d.ts b/packages/svelte/src/internal/client/reactivity/types.d.ts index 0dc0b2d5a4..a390d83b03 100644 --- a/packages/svelte/src/internal/client/reactivity/types.d.ts +++ b/packages/svelte/src/internal/client/reactivity/types.d.ts @@ -78,8 +78,6 @@ export type Effect = { export type Reaction = Derived | Effect; -export type Signal = Source | Reaction; - export type MaybeSignal = T | Source; export type UnwrappedSignal = T extends Value ? U : T; @@ -87,3 +85,5 @@ export type UnwrappedSignal = T extends Value ? U : T; export type Value = Source | Derived; export type ValueDebug = SourceDebug | DerivedDebug; + +export type Signal = Source | Derived | Effect; diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 10cd320165..abe296907c 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -865,8 +865,7 @@ export function mark_subtree_inert(signal, inert, visited_blocks = new Set()) { } /** - * @template V - * @param {import('./types.js').Signal} signal + * @param {import('./types.js').Signal} signal * @param {number} to_status * @param {boolean} force_schedule * @returns {void} @@ -962,9 +961,9 @@ export function push_destroy_fn(signal, destroy_fn) { } const STATUS_MASK = ~(DIRTY | MAYBE_DIRTY | CLEAN); + /** - * @template V - * @param {import('./types.js').Signal} signal + * @param {import('./types.js').Signal} signal * @param {number} status * @returns {void} */ @@ -974,14 +973,14 @@ export function set_signal_status(signal, status) { /** * @template V - * @param {V | import('./types.js').Signal} val - * @returns {val is import('./types.js').Signal} + * @param {V | import('./types.js').Value} val + * @returns {val is import('./types.js').Value} */ export function is_signal(val) { return ( typeof val === 'object' && val !== null && - typeof (/** @type {import('./types.js').Signal} */ (val).f) === 'number' + typeof (/** @type {import('./types.js').Value} */ (val).f) === 'number' ); } diff --git a/packages/svelte/src/internal/client/types.d.ts b/packages/svelte/src/internal/client/types.d.ts index c1b42a7b94..563835384d 100644 --- a/packages/svelte/src/internal/client/types.d.ts +++ b/packages/svelte/src/internal/client/types.d.ts @@ -27,13 +27,13 @@ export type Store = { export type ComponentContext = { /** local signals (needed for beforeUpdate/afterUpdate) */ - d: null | Signal[]; + d: null | Source[]; /** props */ s: Record; /** exports (and props, if `accessors: true`) */ x: Record | null; /** effects */ - e: null | Array; + e: null | Effect[]; /** mounted */ m: boolean; /** parent */ @@ -223,11 +223,11 @@ export type EachItemBlock = { /** dom */ d: null | TemplateNode | Array; /** effect */ - e: null | Reaction; + e: null | Effect; /** item */ - v: any | Value; + v: any | Source; /** index */ - i: number | Value; + i: number | Source; /** key */ k: unknown; /** parent */ @@ -292,7 +292,7 @@ export type StoreReferencesContainer = Record< store: Store | null; last_value: any; unsubscribe: Function; - value: Value; + value: Source; } >; diff --git a/packages/svelte/tests/signals/test.ts b/packages/svelte/tests/signals/test.ts index 07e5716edf..8791a434d4 100644 --- a/packages/svelte/tests/signals/test.ts +++ b/packages/svelte/tests/signals/test.ts @@ -1,10 +1,10 @@ import { describe, assert, it } from 'vitest'; import * as $ from '../../src/internal/client/runtime'; -import { derived } from '../../src/internal/client/reactivity/deriveds'; import { effect, render_effect, user_effect } from '../../src/internal/client/reactivity/effects'; import { source, set } from '../../src/internal/client/reactivity/sources'; import type { Derived } from '../../src/internal/client/types'; import { proxy } from '../../src/internal/client/proxy'; +import { derived } from '../../src/internal/client/reactivity/deriveds'; /** * @param runes runes mode