Skip to content

Make removeChild in receivers less strict#533

Merged
igor10k merged 1 commit into
mainfrom
i10k/less_strict_remove_child
Feb 24, 2025
Merged

Make removeChild in receivers less strict#533
igor10k merged 1 commit into
mainfrom
i10k/less_strict_remove_child

Conversation

@igor10k
Copy link
Copy Markdown
Contributor

@igor10k igor10k commented Feb 21, 2025

Porting #522 since through the adapter remote-dom receivers can be used with remote-ui remote which can be using old versions of remote-ui that don't handle removeChild calls well.

@github-actions

This comment has been minimized.

@igor10k igor10k force-pushed the i10k/less_strict_remove_child branch from ae7c371 to 94ab3c1 Compare February 21, 2025 18:35
Copy link
Copy Markdown

@thomas-marcucci thomas-marcucci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me! Ideally I guess there would be tests, but at a glance I don't see any so maybe it's not an issue here.

Copy link
Copy Markdown
Member

@simontaisne simontaisne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for looking into that 💯

@igor10k igor10k merged commit a9a88ab into main Feb 24, 2025
shopify-river Bot pushed a commit that referenced this pull request Apr 30, 2026
Drop `insertChild`, `removeChild`, `updateProperty`, and `updateText`
mutations whose target node is no longer in the receiver's `attached`
map, instead of throwing a `TypeError` while dereferencing the missing
node.

This race surfaces in production as unhandled promise rejections such
as `TypeError: undefined is not an object (evaluating 'x.properties')`
(Safari) / `TypeError: Cannot read properties of undefined (reading
'properties')` (V8) when a remote sender dispatches a mutation for a
node whose host-side state has just been removed.

PR #533 previously added a similar guard to `removeChild` for the case
where the *child slot* at a given index was empty, but did not handle
the case where the *parent itself* was missing, and did not touch
`updateProperty` or `updateText`. This change applies the same
defensive pattern uniformly to every connection callback that
dereferences `attached.get(id)`.

Late mutations targeting a detached subtree are by definition no-ops:
there is nothing left to mutate.

Fixes the original report in #542 (which #533 was assumed to fix but
did not actually cover).

Requested by Eddie Chan <eddie.chan@shopify.com>
eddiechan added a commit that referenced this pull request May 8, 2026
Drop `insertChild`, `removeChild`, `updateProperty`, and `updateText`
mutations whose target node is no longer in the receiver's `attached`
map, instead of throwing a `TypeError` while dereferencing the missing
node.

This race surfaces in production as unhandled promise rejections such
as `TypeError: undefined is not an object (evaluating 'x.properties')`
(Safari) / `TypeError: Cannot read properties of undefined (reading
'properties')` (V8) when a remote sender dispatches a mutation for a
node whose host-side state has just been removed.

PR #533 previously added a similar guard to `removeChild` for the case
where the *child slot* at a given index was empty, but did not handle
the case where the *parent itself* was missing, and did not touch
`updateProperty` or `updateText`. This change applies the same
defensive pattern uniformly to every connection callback that
dereferences `attached.get(id)`.

Late mutations targeting a detached subtree are by definition no-ops:
there is nothing left to mutate.

Fixes the original report in #542 (which #533 was assumed to fix but
did not actually cover).

Requested by Eddie Chan <eddie.chan@shopify.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants