From b8c6b6c553f9a505f924cc4cac7f10d643a14790 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 10 Sep 2025 19:24:06 -0400 Subject: [PATCH 1/2] fix: issue `state_proxy_unmount` warning when unmounting a state proxy --- .changeset/fuzzy-pillows-tell.md | 5 +++++ .../.generated/client-warnings.md | 21 +++++++++++++++++++ .../messages/client-warnings/warnings.md | 19 +++++++++++++++++ packages/svelte/src/internal/client/render.js | 8 +++++-- .../svelte/src/internal/client/warnings.js | 11 ++++++++++ 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 .changeset/fuzzy-pillows-tell.md diff --git a/.changeset/fuzzy-pillows-tell.md b/.changeset/fuzzy-pillows-tell.md new file mode 100644 index 000000000000..9d2e54ac64a4 --- /dev/null +++ b/.changeset/fuzzy-pillows-tell.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: issue `state_proxy_unmount` warning when unmounting a state proxy diff --git a/documentation/docs/98-reference/.generated/client-warnings.md b/documentation/docs/98-reference/.generated/client-warnings.md index 6f1d677fe951..c95ace22293d 100644 --- a/documentation/docs/98-reference/.generated/client-warnings.md +++ b/documentation/docs/98-reference/.generated/client-warnings.md @@ -312,6 +312,27 @@ Reactive `$state(...)` proxies and the values they proxy have different identiti To resolve this, ensure you're comparing values where both values were created with `$state(...)`, or neither were. Note that `$state.raw(...)` will _not_ create a state proxy. +### state_proxy_unmount + +``` +Tried to unmount a state proxy, rather than a component +``` + +`unmount` was called with a state proxy: + +```js +import { mount, unmount } from 'svelte'; +import Component from './Component.svelte'; +let target = document.body; +// ---cut--- +let component = $state(mount(Component, { target })); + +// later... +unmount(component); +``` + +Avoid using `$state` here. If `component` _does_ need to be reactive for some reason, use `$state.raw` instead. + ### svelte_boundary_reset_noop ``` diff --git a/packages/svelte/messages/client-warnings/warnings.md b/packages/svelte/messages/client-warnings/warnings.md index 123c6833e688..9763c8df1ab8 100644 --- a/packages/svelte/messages/client-warnings/warnings.md +++ b/packages/svelte/messages/client-warnings/warnings.md @@ -272,6 +272,25 @@ To silence the warning, ensure that `value`: To resolve this, ensure you're comparing values where both values were created with `$state(...)`, or neither were. Note that `$state.raw(...)` will _not_ create a state proxy. +## state_proxy_unmount + +> Tried to unmount a state proxy, rather than a component + +`unmount` was called with a state proxy: + +```js +import { mount, unmount } from 'svelte'; +import Component from './Component.svelte'; +let target = document.body; +// ---cut--- +let component = $state(mount(Component, { target })); + +// later... +unmount(component); +``` + +Avoid using `$state` here. If `component` _does_ need to be reactive for some reason, use `$state.raw` instead. + ## svelte_boundary_reset_noop > A `` `reset` function only resets the boundary the first time it is called diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index c5015875a8a3..6f9254ae64cf 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -30,7 +30,7 @@ import * as w from './warnings.js'; import * as e from './errors.js'; import { assign_nodes } from './dom/template.js'; import { is_passive_event } from '../../utils.js'; -import { COMMENT_NODE } from './constants.js'; +import { COMMENT_NODE, STATE_SYMBOL } from './constants.js'; /** * This is normally true — block effects should run their intro transitions — @@ -309,7 +309,11 @@ export function unmount(component, options) { } if (DEV) { - w.lifecycle_double_unmount(); + if (STATE_SYMBOL in component) { + w.state_proxy_unmount(); + } else { + w.lifecycle_double_unmount(); + } } return Promise.resolve(); diff --git a/packages/svelte/src/internal/client/warnings.js b/packages/svelte/src/internal/client/warnings.js index dfa2a3752e52..1d0c224d7c1f 100644 --- a/packages/svelte/src/internal/client/warnings.js +++ b/packages/svelte/src/internal/client/warnings.js @@ -171,6 +171,17 @@ export function lifecycle_double_unmount() { } } +/** + * Tried to unmount a state proxy, rather than a component + */ +export function state_proxy_unmount() { + if (DEV) { + console.warn(`%c[svelte] state_proxy_unmount\n%cTried to unmount a state proxy, rather than a component\nhttps://svelte.dev/e/state_proxy_unmount`, bold, normal); + } else { + console.warn(`https://svelte.dev/e/state_proxy_unmount`); + } +} + /** * %parent% passed property `%prop%` to %child% with `bind:`, but its parent component %owner% did not declare `%prop%` as a binding. Consider creating a binding between %owner% and %parent% (e.g. `bind:%prop%={...}` instead of `%prop%={...}`) * @param {string} parent From d2f723a7dac20c358ebf2490e2b49a6d8e1dc1e1 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 10 Sep 2025 19:30:00 -0400 Subject: [PATCH 2/2] regenerate --- .../svelte/src/internal/client/warnings.js | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/svelte/src/internal/client/warnings.js b/packages/svelte/src/internal/client/warnings.js index 1d0c224d7c1f..1081ef58618e 100644 --- a/packages/svelte/src/internal/client/warnings.js +++ b/packages/svelte/src/internal/client/warnings.js @@ -171,17 +171,6 @@ export function lifecycle_double_unmount() { } } -/** - * Tried to unmount a state proxy, rather than a component - */ -export function state_proxy_unmount() { - if (DEV) { - console.warn(`%c[svelte] state_proxy_unmount\n%cTried to unmount a state proxy, rather than a component\nhttps://svelte.dev/e/state_proxy_unmount`, bold, normal); - } else { - console.warn(`https://svelte.dev/e/state_proxy_unmount`); - } -} - /** * %parent% passed property `%prop%` to %child% with `bind:`, but its parent component %owner% did not declare `%prop%` as a binding. Consider creating a binding between %owner% and %parent% (e.g. `bind:%prop%={...}` instead of `%prop%={...}`) * @param {string} parent @@ -235,6 +224,17 @@ export function state_proxy_equality_mismatch(operator) { } } +/** + * Tried to unmount a state proxy, rather than a component + */ +export function state_proxy_unmount() { + if (DEV) { + console.warn(`%c[svelte] state_proxy_unmount\n%cTried to unmount a state proxy, rather than a component\nhttps://svelte.dev/e/state_proxy_unmount`, bold, normal); + } else { + console.warn(`https://svelte.dev/e/state_proxy_unmount`); + } +} + /** * A `` `reset` function only resets the boundary the first time it is called */