Repository navigation
Fix hydration state restoration for custom element attribute updates - #18467
Conversation
dummdidumm
left a comment
There was a problem hiding this comment.
what's the use case? please provide some rationale - if something throws we normally should switch to the error boundary etc, so restoring hydration state is irrelevant. also needs a test and changeset
f0bd6da to
c0eb1c5
Compare
|
Install the latest version of pnpm add https://pkg.svelte.dev/svelte/c/6903be843fdd6bed54a0632522db0bed5aaecb6dOpen in Note This PR is from a fork. A maintainer must approve approve each commit before it can be built and installed. |
🦋 Changeset detectedLatest commit: 6903be8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The use case is a custom element setter throwing during hydration while the error is caught by a svelte:boundary. |
|
I checked the git history and I think this came from #15217 (3b7066f). That change added set_hydrating(false) in both set_custom_element_data and set_attributes. In set_custom_element_data it gets restored in a finally, but in set_attributes it only gets restored at the end. In this case the setter throws, but svelte:boundary catches the error and keeps going. At that point hydrating is still false, so the hydration cleanup does not happen and the old custom element stays in the DOM. So I think this PR just makes set_attributes behave the same way as set_custom_element_data when something throws. |
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## svelte@5.57.2 ### Patch Changes - fix: don't create async deriveds for a component destroyed while waiting for its top-level `await` ([#18931](#18931)) - fix: prevent untracked derived reads from retaining disconnected dependencies ([#18829](#18829)) - fix: error if `{:else}` is followed by another `{:else}` or `{:else if ...}` ([#18900](#18900)) - fix: avoid tracking SvelteURLSearchParams during URL updates ([#18791](#18791)) - fix: restore hydration state when custom element attribute updates throw ([#18467](#18467)) - fix: attach event handlers that are assigned after a top-level `await` in production ([#18933](#18933)) - fix: flush anything pending before invoking flushSync callback function ([#18878](#18878)) - fix: preserve location information for `await` wrappers ([#18859](#18859)) - fix: keep a reactive assignment with no dependencies when `migrate` cannot turn it into a declaration ([#18817](#18817)) - fix: don't hang `migrate` on a declaration that shares a line with its script tag ([#18816](#18816)) - fix: prevent duplicate subscriptions when reconnecting deriveds ([#18899](#18899)) - fix: recover when an unexpected node replaces a nested boundary comment during hydration ([#18925](#18925)) - fix: print `{#await}` blocks that only have a pending branch ([#18908](#18908)) - fix: don't warn about a redundant `link` role on `<area>` elements without an `href` ([#18872](#18872)) - fix: don't throw `state_unsafe_mutation` when the focused element is removed while `bind:activeElement` is used ([#18921](#18921)) - fix: don't overwrite an unchanged spread `value`, preserving incomplete number input ([#18864](#18864)) - fix: read batch-local array on each-block commit ([#18879](#18879)) - fix: error at compile time when a declaration in a snippet redeclares one of its parameters ([#18842](#18842)) - fix: error when using `let:` directives on a component with a `children` snippet ([#18873](#18873)) - fix: ignore stale boundary reset callbacks ([#18886](#18886)) - fix: handle deferred transitions aborted before initialization ([#18776](#18776)) - fix: prevent hydration mismatch recovery from being intercepted by error boundaries ([#18841](#18841)) - fix: preserve dynamic element connections during hydration ([#18855](#18855)) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [svelte](https://svelte.dev) ([source](https://github.com/sveltejs/svelte/tree/HEAD/packages/svelte)) | [`5.57.1` → `5.57.2`](https://renovatebot.com/diffs/npm/svelte/5.57.1/5.57.2) |  |  | --- ### Release Notes <details> <summary>sveltejs/svelte (svelte)</summary> ### [`v5.57.2`](https://github.com/sveltejs/svelte/blob/HEAD/packages/svelte/CHANGELOG.md#5572) [Compare Source](https://github.com/sveltejs/svelte/compare/svelte@5.57.1...svelte@5.57.2) ##### Patch Changes - fix: don't create async deriveds for a component destroyed while waiting for its top-level `await` ([#​18931](sveltejs/svelte#18931)) - fix: prevent untracked derived reads from retaining disconnected dependencies ([#​18829](sveltejs/svelte#18829)) - fix: error if `{:else}` is followed by another `{:else}` or `{:else if ...}` ([#​18900](sveltejs/svelte#18900)) - fix: avoid tracking SvelteURLSearchParams during URL updates ([#​18791](sveltejs/svelte#18791)) - fix: restore hydration state when custom element attribute updates throw ([#​18467](sveltejs/svelte#18467)) - fix: attach event handlers that are assigned after a top-level `await` in production ([#​18933](sveltejs/svelte#18933)) - fix: flush anything pending before invoking flushSync callback function ([#​18878](sveltejs/svelte#18878)) - fix: preserve location information for `await` wrappers ([#​18859](sveltejs/svelte#18859)) - fix: keep a reactive assignment with no dependencies when `migrate` cannot turn it into a declaration ([#​18817](sveltejs/svelte#18817)) - fix: don't hang `migrate` on a declaration that shares a line with its script tag ([#​18816](sveltejs/svelte#18816)) - fix: prevent duplicate subscriptions when reconnecting deriveds ([#​18899](sveltejs/svelte#18899)) - fix: recover when an unexpected node replaces a nested boundary comment during hydration ([#​18925](sveltejs/svelte#18925)) - fix: print `{#await}` blocks that only have a pending branch ([#​18908](sveltejs/svelte#18908)) - fix: don't warn about a redundant `link` role on `<area>` elements without an `href` ([#​18872](sveltejs/svelte#18872)) - fix: don't throw `state_unsafe_mutation` when the focused element is removed while `bind:activeElement` is used ([#​18921](sveltejs/svelte#18921)) - fix: don't overwrite an unchanged spread `value`, preserving incomplete number input ([#​18864](sveltejs/svelte#18864)) - fix: read batch-local array on each-block commit ([#​18879](sveltejs/svelte#18879)) - fix: error at compile time when a declaration in a snippet redeclares one of its parameters ([#​18842](sveltejs/svelte#18842)) - fix: error when using `let:` directives on a component with a `children` snippet ([#​18873](sveltejs/svelte#18873)) - fix: ignore stale boundary reset callbacks ([#​18886](sveltejs/svelte#18886)) - fix: handle deferred transitions aborted before initialization ([#​18776](sveltejs/svelte#18776)) - fix: prevent hydration mismatch recovery from being intercepted by error boundaries ([#​18841](sveltejs/svelte#18841)) - fix: preserve dynamic element connections during hydration ([#​18855](sveltejs/svelte#18855)) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xNDguNCIsInVwZGF0ZWRJblZlciI6IjQ0LjE0OC40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
Problem
While hydrating custom elements, set_attributes temporarily disables global hydration state via set_hydrating(false) and restores it only at the end. If a prop setter or attribute operation throws partway through, hydration mode can remain disabled globally.
Fix
Wrap the temporary hydration-state override in a try/finally block in set_attributes so set_hydrating(true) always runs when is_hydrating_custom_element is true.
Validation
No runtime tests were run in this PR workflow. This is a control-flow safety fix to ensure state restoration under error conditions.