diff --git a/.changeset/soft-clocks-remember.md b/.changeset/soft-clocks-remember.md new file mode 100644 index 000000000000..69e8aca06e3c --- /dev/null +++ b/.changeset/soft-clocks-remember.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: improve consistency issues around binding invalidation diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index fb43ec654b11..e784d5407b51 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -245,7 +245,7 @@ function setup_select_synchronization(value_binding, context) { context.state.init.push( b.stmt( b.call( - '$.pre_effect', + '$.invalidate_effect', b.thunk( b.block([ b.stmt( diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 101a189b1082..0840bbe59283 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -1298,6 +1298,17 @@ export function pre_effect(init) { ); } +/** + * This effect is used to ensure binding are kept in sync. We use a pre effect to ensure we run before the + * 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)} init + * @returns {import('./types.js').EffectSignal} + */ +export function invalidate_effect(init) { + return internal_create_effect(PRE_EFFECT, init, true, current_block, true); +} + /** * @param {() => void | (() => void)} init * @returns {import('./types.js').EffectSignal} diff --git a/packages/svelte/src/internal/index.js b/packages/svelte/src/internal/index.js index 4d3205b8242d..a94a0de180cc 100644 --- a/packages/svelte/src/internal/index.js +++ b/packages/svelte/src/internal/index.js @@ -12,6 +12,7 @@ export { user_effect, render_effect, pre_effect, + invalidate_effect, flushSync, bubble_event, safe_equal, diff --git a/packages/svelte/tests/runtime-runes/samples/invalidate-effect/_config.js b/packages/svelte/tests/runtime-runes/samples/invalidate-effect/_config.js new file mode 100644 index 000000000000..b4ba660ad471 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/invalidate-effect/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + assert.htmlEqual(target.innerHTML, 'a\n