Skip to content

fix(framework): align template cursor in SSR hydration resolvers for nested blocks#196

Merged
toddreifsteck merged 1 commit intomainfrom
fix/commerce
Apr 8, 2026
Merged

fix(framework): align template cursor in SSR hydration resolvers for nested blocks#196
toddreifsteck merged 1 commit intomainfrom
fix/commerce

Conversation

@mohamedmansour
Copy link
Copy Markdown
Contributor

When pathStart > 0 (used during in-place hydration of repeat and conditional block items), $resolveSSR and $resolve skipped the leading path segments but never advanced the template DOM cursor through them. This left the template cursor pointing at the wrapper div from getTemplateDom() while the SSR cursor had already descended to the block root element.

The misalignment caused path resolution to fail for any binding nested deeper than one level inside a block:

  • Issue commerce example bug: refreshing product page, variant selectors don't work #175 (variant selector): The inner for-loop over group.values inside the outer for-loop over optionGroups could not resolve its parent dd element. The inner repeat was never hydrated, event handlers were never wired on the pill buttons, and clicking a variant after a direct page load (SSR) did nothing.

  • Issue commerce example bug: add to card is adding duplicates with <for> #176 (cart duplicates): The for-loop over cartItems inside the if-condition block could not resolve its parent ul element. An empty repeat was created with a new anchor in the wrong container. When updateInstance ran syncRepeat, it created new DOM items alongside the SSR-rendered originals, doubling every cart line.

The fix adds a pre-advance loop in both resolveSSR (template-only) and resolve (template path resolution) to walk the cursor through path[0..pathStart-1] before the main resolution loop. This is a no-op for the common pathStart=0 case and adds exactly one extra childNodes lookup for the pathStart=1 case used by block hydration. Zero new allocations.

Regression tests added at two levels:

Closes #175, closes #176

…nested blocks

When pathStart > 0 (used during in-place hydration of repeat and
conditional block items), $resolveSSR and $resolve skipped the
leading path segments but never advanced the template DOM cursor
through them.  This left the template cursor pointing at the wrapper
div from getTemplateDom() while the SSR cursor had already descended
to the block root element.

The misalignment caused path resolution to fail for any binding
nested deeper than one level inside a block:

- Issue #175 (variant selector): The inner for-loop over group.values
  inside the outer for-loop over optionGroups could not resolve its
  parent dd element.  The inner repeat was never hydrated, event
  handlers were never wired on the pill buttons, and clicking a
  variant after a direct page load (SSR) did nothing.

- Issue #176 (cart duplicates): The for-loop over cartItems inside
  the if-condition block could not resolve its parent ul element.
  An empty repeat was created with a new anchor in the wrong
  container.  When updateInstance ran syncRepeat, it created new DOM
  items alongside the SSR-rendered originals, doubling every cart
  line.

The fix adds a pre-advance loop in both resolveSSR (template-only)
and resolve (template path resolution) to walk the cursor through
path[0..pathStart-1] before the main resolution loop.  This is a
no-op for the common pathStart=0 case and adds exactly one extra
childNodes lookup for the pathStart=1 case used by block hydration.
Zero new allocations.

Regression tests added at two levels:

- Framework (webui-framework): 10 new SSR hydration tests for the
  nested-repeat fixture (light + shadow DOM), covering: no duplication
  after hydration, attribute preservation, reactive updates, list
  growth, and outer-scope text bindings.

- Commerce app (E2E): 3 new Playwright tests -- variant selector
  click activation after page refresh (#175), and cart line count
  after SSR reload (#176).

Closes #175, closes #176

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mohamedmansour mohamedmansour requested a review from a team April 8, 2026 21:52
Copy link
Copy Markdown
Contributor

@toddreifsteck toddreifsteck left a comment

Choose a reason for hiding this comment

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

LGTM

@toddreifsteck toddreifsteck merged commit 923ce1d into main Apr 8, 2026
20 checks passed
@toddreifsteck toddreifsteck deleted the fix/commerce branch April 8, 2026 22:12
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.

commerce example bug: add to card is adding duplicates with <for> commerce example bug: refreshing product page, variant selectors don't work

2 participants