From 6534aa08e32b3c2d09c2ffb06e4ae7a18fdffa30 Mon Sep 17 00:00:00 2001 From: Edoardo Cavazza Date: Mon, 25 Aug 2025 21:06:53 +0200 Subject: [PATCH 01/10] fix: Add check for builtin custom elements in `set_custom_element_data` (#16592) Fixes #16591 This PR introduces a check for builtin custom elements (is attribute) inside the set_custom_element_data helper in order to correctly set properties that have a setter. --- .changeset/fuzzy-shrimps-dream.md | 5 +++++ .../client/dom/elements/attributes.js | 9 +++++---- .../custom-element-attributes/_config.js | 3 +++ .../custom-element-attributes/main.svelte | 19 +++++++++++++++++++ 4 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 .changeset/fuzzy-shrimps-dream.md diff --git a/.changeset/fuzzy-shrimps-dream.md b/.changeset/fuzzy-shrimps-dream.md new file mode 100644 index 0000000000..0ddab531ac --- /dev/null +++ b/.changeset/fuzzy-shrimps-dream.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: Add check for builtin custom elements in `set_custom_element_data` diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index 2fa5d4541c..a5b7140f25 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -238,10 +238,10 @@ export function set_custom_element_data(node, prop, value) { // Don't compute setters for custom elements while they aren't registered yet, // because during their upgrade/instantiation they might add more setters. // Instead, fall back to a simple "an object, then set as property" heuristic. - (setters_cache.has(node.nodeName) || + (setters_cache.has(node.getAttribute('is') || node.nodeName) || // customElements may not be available in browser extension contexts !customElements || - customElements.get(node.tagName.toLowerCase()) + customElements.get(node.getAttribute('is') || node.tagName.toLowerCase()) ? get_setters(node).includes(prop) : value && typeof value === 'object') ) { @@ -546,9 +546,10 @@ var setters_cache = new Map(); /** @param {Element} element */ function get_setters(element) { - var setters = setters_cache.get(element.nodeName); + var cache_key = element.getAttribute('is') || element.nodeName; + var setters = setters_cache.get(cache_key); if (setters) return setters; - setters_cache.set(element.nodeName, (setters = [])); + setters_cache.set(cache_key, (setters = [])); var descriptors; var proto = element; // In the case of custom elements there might be setters on the instance diff --git a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/_config.js b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/_config.js index 7f406d8f0d..3d8917c147 100644 --- a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/_config.js @@ -20,5 +20,8 @@ export default test({ const [value1, value2] = target.querySelectorAll('value-element'); assert.equal(value1.shadowRoot?.innerHTML, 'test'); assert.equal(value2.shadowRoot?.innerHTML, 'test'); + + const value_builtin = target.querySelector('div'); + assert.equal(value_builtin?.shadowRoot?.innerHTML, 'test'); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte index 82774f160d..badb8f96c7 100644 --- a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte @@ -15,6 +15,24 @@ } }); } + if(!customElements.get('value-builtin')) { + customElements.define('value-builtin', class extends HTMLDivElement { + + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + } + + set value(v) { + if (this.__value !== v) { + this.__value = v; + this.shadowRoot.innerHTML = `${v}`; + } + } + }, { + extends: 'div' + }); + } @@ -22,3 +40,4 @@ +
From 0d48916e020cb99f5573925a47b4231d0fb6ac5a Mon Sep 17 00:00:00 2001 From: hariharan <36292275+fabhari@users.noreply.github.com> Date: Mon, 25 Aug 2025 22:14:17 +0100 Subject: [PATCH 02/10] fix: cursor jumps in input two way binding (#16649) * fix : remove cursor manipulation for input bindings Old Fix: Restore input binding selection position (#14649) Current Fix: Remove unnecessary cursor manipulation as the presence of runes no longer requires special handling. * fix : add change set to my previous commit * Revert "fix : add change set to my previous commit" This reverts commit 6ca8ef3f97941bb8d8e0675b36d0c14af452364d. * fix: revert previous changeset added new to fix lint errors * chore : resolve lint error to fix pipeline issue * Revert "fix: revert previous changeset added new to fix lint errors" This reverts commit 91094949a616898729b85a95b5e1a8880b450170. * fix: input binding to handle code in a synchronous manner Introduced Promise.resolve to ensure that the 'set' operation completes before the 'get' operation Minimizing update delays. * Fix: resolve cursor jumps and change sets * better fix * test * changeset * simplify * failing test * gah we can't fix the input in an effect, need to do it here, but after a tick so that changes have been flushed through each blocks * add explanatory comment * fix test * this seems to work? --------- Co-authored-by: Hariharan Srinivasan Co-authored-by: Rich Harris --- .changeset/rare-cups-fold.md | 5 ++++ .changeset/tasty-chicken-care.md | 5 ++++ .../client/dom/elements/bindings/input.js | 16 +++++----- .../samples/binding-update-in-each/_config.js | 28 +++++++++++++++++ .../binding-update-in-each/main.svelte | 8 +++++ .../binding-update-while-focused-3/_config.js | 30 +++++++++++++++++++ .../main.svelte | 6 ++++ 7 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 .changeset/rare-cups-fold.md create mode 100644 .changeset/tasty-chicken-care.md create mode 100644 packages/svelte/tests/runtime-runes/samples/binding-update-in-each/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/binding-update-in-each/main.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/main.svelte diff --git a/.changeset/rare-cups-fold.md b/.changeset/rare-cups-fold.md new file mode 100644 index 0000000000..8cd5995651 --- /dev/null +++ b/.changeset/rare-cups-fold.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: Introduced Promise.resolve to ensure that the 'set' operation completes before the 'get' operation Minimizing update delays. diff --git a/.changeset/tasty-chicken-care.md b/.changeset/tasty-chicken-care.md new file mode 100644 index 0000000000..ea579efe4c --- /dev/null +++ b/.changeset/tasty-chicken-care.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: wait until changes propagate before updating input selection state diff --git a/packages/svelte/src/internal/client/dom/elements/bindings/input.js b/packages/svelte/src/internal/client/dom/elements/bindings/input.js index 67e6ff1dd2..815acde7c5 100644 --- a/packages/svelte/src/internal/client/dom/elements/bindings/input.js +++ b/packages/svelte/src/internal/client/dom/elements/bindings/input.js @@ -6,7 +6,7 @@ import * as e from '../../../errors.js'; import { is } from '../../../proxy.js'; import { queue_micro_task } from '../../task.js'; import { hydrating } from '../../hydration.js'; -import { untrack } from '../../../runtime.js'; +import { tick, untrack } from '../../../runtime.js'; import { is_runes } from '../../../context.js'; import { current_batch, previous_batch } from '../../../reactivity/batch.js'; @@ -17,11 +17,9 @@ import { current_batch, previous_batch } from '../../../reactivity/batch.js'; * @returns {void} */ export function bind_value(input, get, set = get) { - var runes = is_runes(); - var batches = new WeakSet(); - listen_to_event_and_reset_event(input, 'input', (is_reset) => { + listen_to_event_and_reset_event(input, 'input', async (is_reset) => { if (DEV && input.type === 'checkbox') { // TODO should this happen in prod too? e.bind_invalid_checkbox_value(); @@ -36,9 +34,13 @@ export function bind_value(input, get, set = get) { batches.add(current_batch); } - // In runes mode, respect any validation in accessors (doesn't apply in legacy mode, - // because we use mutable state which ensures the render effect always runs) - if (runes && value !== (value = get())) { + // Because `{#each ...}` blocks work by updating sources inside the flush, + // we need to wait a tick before checking to see if we should forcibly + // update the input and reset the selection state + await tick(); + + // Respect any validation in accessors + if (value !== (value = get())) { var start = input.selectionStart; var end = input.selectionEnd; diff --git a/packages/svelte/tests/runtime-runes/samples/binding-update-in-each/_config.js b/packages/svelte/tests/runtime-runes/samples/binding-update-in-each/_config.js new file mode 100644 index 0000000000..b6371ce11c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/binding-update-in-each/_config.js @@ -0,0 +1,28 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], + + html: `

a`, + + async test({ assert, target }) { + const [input] = target.querySelectorAll('input'); + + input.focus(); + input.value = 'ab'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + flushSync(); + + assert.htmlEqual(target.innerHTML, `

ab`); + assert.equal(input.value, 'ab'); + + input.focus(); + input.value = 'abc'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + flushSync(); + + assert.htmlEqual(target.innerHTML, `

abc`); + assert.equal(input.value, 'abc'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/binding-update-in-each/main.svelte b/packages/svelte/tests/runtime-runes/samples/binding-update-in-each/main.svelte new file mode 100644 index 0000000000..7925195ee1 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/binding-update-in-each/main.svelte @@ -0,0 +1,8 @@ + + +{#each array as obj} + obj.value, (value) => array = [{ value }]} /> +

{obj.value}

+{/each} diff --git a/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/_config.js b/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/_config.js new file mode 100644 index 0000000000..0909dee7a8 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/_config.js @@ -0,0 +1,30 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], + + async test({ assert, target }) { + const [input] = target.querySelectorAll('input'); + + input.focus(); + input.value = 'Ab'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + + await tick(); + await tick(); + + assert.equal(input.value, 'AB'); + assert.htmlEqual(target.innerHTML, `

AB

`); + + input.focus(); + input.value = 'ABc'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + + await tick(); + await tick(); + + assert.equal(input.value, 'ABC'); + assert.htmlEqual(target.innerHTML, `

ABC

`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/main.svelte b/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/main.svelte new file mode 100644 index 0000000000..b61bfe4e67 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/main.svelte @@ -0,0 +1,6 @@ + + + text, (v) => text = v.toUpperCase()} /> +

{text}

From 0348b4a7050b360fef41a5dc93b80c906e7842bd Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 25 Aug 2025 17:50:51 -0400 Subject: [PATCH 03/10] delete unused changeset --- .changeset/rare-cups-fold.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .changeset/rare-cups-fold.md diff --git a/.changeset/rare-cups-fold.md b/.changeset/rare-cups-fold.md deleted file mode 100644 index 8cd5995651..0000000000 --- a/.changeset/rare-cups-fold.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: Introduced Promise.resolve to ensure that the 'set' operation completes before the 'get' operation Minimizing update delays. From 967431c1a708f6115e6753c8196cf01edf46a0fa Mon Sep 17 00:00:00 2001 From: Gurpreet Atwal Date: Mon, 25 Aug 2025 15:05:58 -0700 Subject: [PATCH 04/10] chore(elements.d.ts): add "Accept-CH" as valid value for `http-equiv` (#16671) * chore(elements.d.ts): add "Accept-CH" as valid value for `http-equiv` It seems like this is a valid value and it has been working for me, however I did find conflicting information on whether it is supported or not. Supporting Evidence: - https://github.com/WICG/client-hints-infrastructure?tab=readme-ov-file#opt-in-mechanism - https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Client_hints#overview - https://developer.chrome.com/docs/privacy-security/user-agent-client-hints#introducing_the_new_user-agent_client_hints - https://github.com/httpwg/http-extensions/issues/189 Conflicting Evidence: - https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-http-equiv * changeset --------- Co-authored-by: Rich Harris --- .changeset/thick-books-fail.md | 5 +++++ packages/svelte/elements.d.ts | 1 + 2 files changed, 6 insertions(+) create mode 100644 .changeset/thick-books-fail.md diff --git a/.changeset/thick-books-fail.md b/.changeset/thick-books-fail.md new file mode 100644 index 0000000000..42dba3c86e --- /dev/null +++ b/.changeset/thick-books-fail.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: add "Accept-CH" as valid value for `http-equiv` diff --git a/packages/svelte/elements.d.ts b/packages/svelte/elements.d.ts index f63a31a96b..e604505d96 100644 --- a/packages/svelte/elements.d.ts +++ b/packages/svelte/elements.d.ts @@ -1268,6 +1268,7 @@ export interface HTMLMetaAttributes extends HTMLAttributes { charset?: string | undefined | null; content?: string | undefined | null; 'http-equiv'?: + | 'accept-ch' | 'content-security-policy' | 'content-type' | 'default-style' From 677af5723c1a80ccfdbab81cb7ef57edeecf0201 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Tue, 26 Aug 2025 00:08:07 +0200 Subject: [PATCH 05/10] fix: ensure async deriveds always get dependencies from thennable (#16672) When an async derived already has a previous promise that is still pending, we were not accessing the `then` property of the new promise. If that property access causes signals to be read, that meant that those dependencies were lost and as such the derived wouldn't rerun anymore when it should. The fix is to make sure to always access the thennable. --- .changeset/orange-chefs-float.md | 5 +++ .../internal/client/reactivity/deriveds.js | 3 ++ .../async-derived-reverse-order/_config.js | 41 +++++++++++++++++++ .../async-derived-reverse-order/main.svelte | 35 ++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 .changeset/orange-chefs-float.md create mode 100644 packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/main.svelte diff --git a/.changeset/orange-chefs-float.md b/.changeset/orange-chefs-float.md new file mode 100644 index 0000000000..fc5db3c680 --- /dev/null +++ b/.changeset/orange-chefs-float.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure async deriveds always get dependencies from thennable diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index 7f730e365e..31dc267960 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -120,6 +120,9 @@ export function async_derived(fn, location) { try { var p = fn(); + // Make sure to always access the then property to read any signals + // it might access, so that we track them as dependencies. + if (prev) Promise.resolve(p).catch(() => {}); // avoid unhandled rejection } catch (error) { p = Promise.reject(error); } diff --git a/packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/_config.js b/packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/_config.js new file mode 100644 index 0000000000..bd0dd753c2 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/_config.js @@ -0,0 +1,41 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const [increment, pop] = target.querySelectorAll('button'); + + increment.click(); + await tick(); + + pop.click(); + await tick(); + + pop.click(); + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` + + +

1

+ ` + ); + + increment.click(); + await tick(); + + pop.click(); + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` + + +

2

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/main.svelte new file mode 100644 index 0000000000..b9f6c26c2a --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/main.svelte @@ -0,0 +1,35 @@ + + + + + + + +

{await push()}

+ + {#snippet pending()} +

loading...

+ {/snippet} +
From 5912754fd6ec48ec00af121c66e959a2c9210de9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 18:09:16 -0400 Subject: [PATCH 06/10] Version Packages (#16667) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/cool-garlics-fail.md | 5 ----- .changeset/fuzzy-shrimps-dream.md | 5 ----- .changeset/silent-pigs-relax.md | 5 ----- .changeset/tasty-chicken-care.md | 5 ----- .changeset/thick-books-fail.md | 5 ----- packages/svelte/CHANGELOG.md | 14 ++++++++++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 8 files changed, 16 insertions(+), 27 deletions(-) delete mode 100644 .changeset/cool-garlics-fail.md delete mode 100644 .changeset/fuzzy-shrimps-dream.md delete mode 100644 .changeset/silent-pigs-relax.md delete mode 100644 .changeset/tasty-chicken-care.md delete mode 100644 .changeset/thick-books-fail.md diff --git a/.changeset/cool-garlics-fail.md b/.changeset/cool-garlics-fail.md deleted file mode 100644 index cabff1840d..0000000000 --- a/.changeset/cool-garlics-fail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: place instance-level snippets inside async body diff --git a/.changeset/fuzzy-shrimps-dream.md b/.changeset/fuzzy-shrimps-dream.md deleted file mode 100644 index 0ddab531ac..0000000000 --- a/.changeset/fuzzy-shrimps-dream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"svelte": patch ---- - -fix: Add check for builtin custom elements in `set_custom_element_data` diff --git a/.changeset/silent-pigs-relax.md b/.changeset/silent-pigs-relax.md deleted file mode 100644 index 5acf185ffe..0000000000 --- a/.changeset/silent-pigs-relax.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: restore batch along with effect context diff --git a/.changeset/tasty-chicken-care.md b/.changeset/tasty-chicken-care.md deleted file mode 100644 index ea579efe4c..0000000000 --- a/.changeset/tasty-chicken-care.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: wait until changes propagate before updating input selection state diff --git a/.changeset/thick-books-fail.md b/.changeset/thick-books-fail.md deleted file mode 100644 index 42dba3c86e..0000000000 --- a/.changeset/thick-books-fail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"svelte": patch ---- - -fix: add "Accept-CH" as valid value for `http-equiv` diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index fb6b20c489..9b6c652333 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,19 @@ # svelte +## 5.38.4 + +### Patch Changes + +- fix: place instance-level snippets inside async body ([#16666](https://github.com/sveltejs/svelte/pull/16666)) + +- fix: Add check for builtin custom elements in `set_custom_element_data` ([#16592](https://github.com/sveltejs/svelte/pull/16592)) + +- fix: restore batch along with effect context ([#16668](https://github.com/sveltejs/svelte/pull/16668)) + +- fix: wait until changes propagate before updating input selection state ([#16649](https://github.com/sveltejs/svelte/pull/16649)) + +- fix: add "Accept-CH" as valid value for `http-equiv` ([#16671](https://github.com/sveltejs/svelte/pull/16671)) + ## 5.38.3 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index b7effe35bd..cb606a336f 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.38.3", + "version": "5.38.4", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index 815b25bf1f..1e5a968bf5 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.38.3'; +export const VERSION = '5.38.4'; export const PUBLIC_VERSION = '5'; From 5314f48d956732a573fb69f57ed42a7ca273e704 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 20:06:00 +0200 Subject: [PATCH 07/10] Version Packages (#16673) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/orange-chefs-float.md | 5 ----- packages/svelte/CHANGELOG.md | 6 ++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) delete mode 100644 .changeset/orange-chefs-float.md diff --git a/.changeset/orange-chefs-float.md b/.changeset/orange-chefs-float.md deleted file mode 100644 index fc5db3c680..0000000000 --- a/.changeset/orange-chefs-float.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: ensure async deriveds always get dependencies from thennable diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 9b6c652333..2f75c135fe 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,11 @@ # svelte +## 5.38.5 + +### Patch Changes + +- fix: ensure async deriveds always get dependencies from thennable ([#16672](https://github.com/sveltejs/svelte/pull/16672)) + ## 5.38.4 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index cb606a336f..7891d94b88 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.38.4", + "version": "5.38.5", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index 1e5a968bf5..77cd8c1bd5 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.38.4'; +export const VERSION = '5.38.5'; export const PUBLIC_VERSION = '5'; From bde51ed7dc3554eee50edc0c29e70a05e9ee842b Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Tue, 26 Aug 2025 21:59:46 +0200 Subject: [PATCH 08/10] fix: don't fail on `flushSync` while flushing effects (#16674) * fix: don't fail on `flushSync` while flushing effects WIP fixes #16640 * cleanup, unrelated lint * revert * fix --- .changeset/honest-coins-work.md | 5 +++++ packages/svelte/elements.d.ts | 2 +- .../svelte/src/internal/client/reactivity/batch.js | 7 +++++-- .../flush-sync-inside-attachment/Child.svelte | 7 +++++++ .../samples/flush-sync-inside-attachment/_config.js | 12 ++++++++++++ .../flush-sync-inside-attachment/main.svelte | 13 +++++++++++++ 6 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 .changeset/honest-coins-work.md create mode 100644 packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/Child.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/main.svelte diff --git a/.changeset/honest-coins-work.md b/.changeset/honest-coins-work.md new file mode 100644 index 0000000000..e6b68a8a67 --- /dev/null +++ b/.changeset/honest-coins-work.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: don't fail on `flushSync` while flushing effects diff --git a/packages/svelte/elements.d.ts b/packages/svelte/elements.d.ts index e604505d96..b0c2fae2de 100644 --- a/packages/svelte/elements.d.ts +++ b/packages/svelte/elements.d.ts @@ -1268,7 +1268,7 @@ export interface HTMLMetaAttributes extends HTMLAttributes { charset?: string | undefined | null; content?: string | undefined | null; 'http-equiv'?: - | 'accept-ch' + | 'accept-ch' | 'content-security-policy' | 'content-type' | 'default-style' diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index 2c60fc8313..82f1de67a9 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -187,7 +187,7 @@ export class Batch { // if there are multiple batches, we are 'time travelling' — // we need to undo the changes belonging to any batch // other than the current one - if (batches.size > 1) { + if (async_mode_flag && batches.size > 1) { current_values = new Map(); batch_deriveds = new Map(); @@ -484,6 +484,7 @@ export class Batch { */ export function flushSync(fn) { if (async_mode_flag && active_effect !== null) { + // We disallow this because it creates super-hard to reason about stack trace and because it's generally a bad idea e.flush_sync_in_effect(); } @@ -622,7 +623,9 @@ function flush_queued_effects(effects) { } } - if (eager_block_effects.length > 0) { + // If update_effect() has a flushSync() in it, we may have flushed another flush_queued_effects(), + // which already handled this logic and did set eager_block_effects to null. + if (eager_block_effects?.length > 0) { // TODO this feels incorrect! it gets the tests passing old_values.clear(); diff --git a/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/Child.svelte b/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/Child.svelte new file mode 100644 index 0000000000..44447e4f36 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/Child.svelte @@ -0,0 +1,7 @@ + + +{text} diff --git a/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/_config.js b/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/_config.js new file mode 100644 index 0000000000..ec8858b2c6 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/_config.js @@ -0,0 +1,12 @@ +import { async_mode } from '../../../helpers'; +import { test } from '../../test'; + +export default test({ + // In legacy mode this succeeds and logs 'hello' + // In async mode this throws an error because flushSync is called inside an effect + async test({ assert, target, logs }) { + assert.htmlEqual(target.innerHTML, `
hello
`); + assert.deepEqual(logs, ['hello']); + }, + runtime_error: async_mode ? 'flush_sync_in_effect' : undefined +}); diff --git a/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/main.svelte b/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/main.svelte new file mode 100644 index 0000000000..bef820376b --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/main.svelte @@ -0,0 +1,13 @@ + + + + +
{ + mount(Child, { target, props: { text: 'hello' } }); + flushSync(); +}}>
From 942eaf027bc08625ed501473861a8dc618b1929e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 Aug 2025 13:43:16 -0400 Subject: [PATCH 09/10] Version Packages (#16677) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/honest-coins-work.md | 5 ----- packages/svelte/CHANGELOG.md | 6 ++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) delete mode 100644 .changeset/honest-coins-work.md diff --git a/.changeset/honest-coins-work.md b/.changeset/honest-coins-work.md deleted file mode 100644 index e6b68a8a67..0000000000 --- a/.changeset/honest-coins-work.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: don't fail on `flushSync` while flushing effects diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 2f75c135fe..de94eb1897 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,11 @@ # svelte +## 5.38.6 + +### Patch Changes + +- fix: don't fail on `flushSync` while flushing effects ([#16674](https://github.com/sveltejs/svelte/pull/16674)) + ## 5.38.5 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 7891d94b88..fe42603184 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.38.5", + "version": "5.38.6", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index 77cd8c1bd5..67c586790f 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.38.5'; +export const VERSION = '5.38.6'; export const PUBLIC_VERSION = '5'; From 9d1aa699b6a4ea3772a1b2bc06e6dc1170575316 Mon Sep 17 00:00:00 2001 From: Jinay Patel <78944617+Github11200@users.noreply.github.com> Date: Sat, 30 Aug 2025 05:38:50 -0700 Subject: [PATCH 10/10] Docs: Updated the custom elements documentation to include $host (#16686) * Updated the custom elements documentation to include * moved the rune reference further up * Small update to the sentence * updated the formatting * Update documentation/docs/07-misc/04-custom-elements.md --------- Co-authored-by: Rich Harris --- documentation/docs/07-misc/04-custom-elements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/07-misc/04-custom-elements.md b/documentation/docs/07-misc/04-custom-elements.md index 7e6a17b947..4e5afff7d2 100644 --- a/documentation/docs/07-misc/04-custom-elements.md +++ b/documentation/docs/07-misc/04-custom-elements.md @@ -4,7 +4,7 @@ title: Custom elements -Svelte components can also be compiled to custom elements (aka web components) using the `customElement: true` compiler option. You should specify a tag name for the component using the `` [element](svelte-options). +Svelte components can also be compiled to custom elements (aka web components) using the `customElement: true` compiler option. You should specify a tag name for the component using the `` [element](svelte-options). Within the custom element you can access the host element via the [`$host`](https://svelte.dev/docs/svelte/$host) rune. ```svelte